Gemini models are designed to prioritize safety. However, they can
still generate harmful responses, especially when they're explicitly prompted.
To further enhance safety and minimize misuse, you can configure safety filters
to block potentially harmful responses.

Two layers of safety protections are provided:

- **Built-in core protections**:

  - All Gemini models feature **built-in protections** against severe harms (such as child exploitation, cyberattacks, and dangerous weapons).
  - These protections are **always active**, applied automatically to all prompts and responses, and can't be modified or disabled.
- **Configurable safety filters**:

  - The Gemini API provides additional **configurable safety filters** which you define using **safety settings** in your app.
  - These settings let you control the *threshold* at which content is blocked across four main [*harm categories*](https://firebase.google.com/docs/ai-logic/safety-settings.md.txt#harm-categories): Harassment, Hate speech, Sexually explicit content, and Dangerous content.

> [!IMPORTANT]
> **Important:** The model's default behavior and built-in protections cover most safety use cases due to inherent safety and alignment training. Given this, you should only configure explicit safety settings (as described on this page) if your app serves sensitive audiences (such as children) or has strict compliance requirements.

[Jump to code samples](https://firebase.google.com/docs/ai-logic/safety-settings.md.txt#configure-safety-settings)

### Important safety concepts

When working with safety for Gemini models, here are some important
concepts to understand:

- **Safety settings** : The configuration you define in your app code specifying
  which [harm categories](https://firebase.google.com/docs/ai-logic/safety-settings.md.txt#harm-categories) to monitor and at what
  [threshold](https://firebase.google.com/docs/ai-logic/safety-settings.md.txt#block-thresholds) to block content.

- **Safety filters**: The server-side classifiers that evaluate prompts and
  model responses against Google's safety dimensions. The filters block content
  based on your configured safety settings.

- **Safety ratings**: The evaluation metadata returned by the model in the
  response object. The ratings indicate the probability and severity of
  potential harm detected for each harm category.

> [!NOTE]
> **Note:** By default, configurable safety filters for harm categories that aren't specified in your app are **`OFF`**. However, built-in core protections remain active (for example, protections against severe harms (such as child exploitation, cyberattacks, and dangerous weapons)).

### Supported models

- `gemini-4-carbon`
- `gemini-4-argon`
- `gemini-3.8-flash`
- `gemini-3.5-flash-lite` (and the older `gemini-3.1-flash-lite`)
- `gemini-nano-banana-2.1` (Nano Banana 2.1)
- `gemini-3.1-flash-image` (Nano Banana 2)
- `gemini-3.1-flash-lite-image` (Nano Banana 2 Lite)
- `gemini-3-pro-image` (Nano Banana Pro)

Older general-use Gemini 3.x Flash models support this capability, but
they're no longer recommended for use due to upcoming shutdown dates and/or
automatic routing to newer models.

<br />

*** ** * ** ***

## Configure safety settings in your app

|---|
| *Click your Gemini API provider to view provider-specific content and code on this page.* <button value="dev" default="">Gemini Developer API</button> <button value="vertex">Agent Platform Gemini API</button> |

You configure safety settings as part of initializing a `GenerativeModel`
instance. The configuration is maintained for the lifetime of that model
instance.

Learn about the available [harm categories](https://firebase.google.com/docs/ai-logic/safety-settings.md.txt#harm-categories) and the
[thresholds](https://firebase.google.com/docs/ai-logic/safety-settings.md.txt#block-thresholds) that you can set for each category later on this
page.

### Swift

Configure
[`SafetySetting`](https://firebase.google.com/docs/reference/swift/firebaseailogic/api/reference/Structs/SafetySetting.md.txt)
when creating a `GenerativeModel` instance:

```swift

import FirebaseAILogic

let safetySettings = [
  SafetySetting(harmCategory: .harassment, threshold: .blockOnlyHigh),
  SafetySetting(harmCategory: .hateSpeech, threshold: .blockMediumAndAbove)
]

// Specify the safety settings as part of creating the `GenerativeModel` instance.
let model = FirebaseAI.firebaseAI(backend: .googleAI()).generativeModel(
  modelName: "GEMINI_MODEL_NAME",
  safetySettings: safetySettings
)

// ...

```

### Kotlin

Configure
[`SafetySetting`](https://firebase.google.com/docs/reference/kotlin/com/google/firebase/ai/type/SafetySetting.md.txt)
when creating a `GenerativeModel` instance:

```kotlin

// ...

val safetySettings = listOf(
    SafetySetting(HarmCategory.HARASSMENT, HarmBlockThreshold.ONLY_HIGH),
    SafetySetting(HarmCategory.HATE_SPEECH, HarmBlockThreshold.MEDIUM_AND_ABOVE)
)

// Specify the safety settings as part of creating the `GenerativeModel` instance.
val model = Firebase.ai(backend = GenerativeBackend.googleAI()).generativeModel(
    modelName = "GEMINI_MODEL_NAME",
    safetySettings = safetySettings
)

// ...

```

### Java

Configure
[`SafetySetting`](https://firebase.google.com/docs/reference/android/com/google/firebase/ai/type/SafetySetting.md.txt)
when creating a `GenerativeModel` instance:

```java

// ...

List safetySettings = List.of(
    new SafetySetting(HarmCategory.HARASSMENT, HarmBlockThreshold.ONLY_HIGH),
    new SafetySetting(HarmCategory.HATE_SPEECH, HarmBlockThreshold.MEDIUM_AND_ABOVE)
);

// Specify the safety settings as part of creating the `GenerativeModel` instance.
GenerativeModelFutures model = GenerativeModelFutures.from(
    FirebaseAI.getInstance(GenerativeBackend.googleAI())
        .generativeModel(
            /* modelName */ "GEMINI_MODEL_NAME",
            /* generationConfig is optional */ null,
            safetySettings
        )
);

// ...

```

### Web

Configure
[`SafetySetting`](https://firebase.google.com/docs/reference/js/ai.safetysetting.md.txt)
when creating a `GenerativeModel` instance:

```javascript

import { HarmBlockThreshold, HarmCategory, getAI, getGenerativeModel, GoogleAIBackend } from "firebase/ai";

// ...

const ai = getAI(firebaseApp, { backend: new GoogleAIBackend() });

const safetySettings = [
  {
    category: HarmCategory.HARM_CATEGORY_HARASSMENT,
    threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH,
  },
  {
    category: HarmCategory.HARM_CATEGORY_HATE_SPEECH,
    threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE,
  },
];

// Specify the safety settings as part of creating the `GenerativeModel` instance.
const model = getGenerativeModel(ai, {
  model: "GEMINI_MODEL_NAME",
  safetySettings,
});

// ...

```

### Dart

Configure
[`SafetySetting`](https://pub.dev/documentation/firebase_ai/latest/firebase_ai/SafetySetting-class.html)
when creating a `GenerativeModel` instance:

```dart

import 'package:firebase_ai/firebase_ai.dart';

final safetySettings = [
  SafetySetting(HarmCategory.harassment, HarmBlockThreshold.high),
  SafetySetting(HarmCategory.hateSpeech, HarmBlockThreshold.medium),
];

// Specify the safety settings as part of creating the `GenerativeModel` instance.
final model = FirebaseAI.googleAI().generativeModel(
  model: 'GEMINI_MODEL_NAME',
  safetySettings: safetySettings,
);

// ...

```

### Unity

Configure
[`SafetySetting`](https://firebase.google.com/docs/reference/unity/struct/firebase/a-i/safety-setting.md.txt)
when creating a `GenerativeModel` instance:

```c#

// ...

var safetySettings = new SafetySetting[] {
  new SafetySetting(HarmCategory.Harassment, SafetySetting.HarmBlockThreshold.OnlyHigh),
  new SafetySetting(HarmCategory.HateSpeech, SafetySetting.HarmBlockThreshold.MediumAndAbove)
};

// Specify the safety settings as part of creating the `GenerativeModel` instance.
var ai = FirebaseAI.GetInstance(FirebaseAI.Backend.GoogleAI());
var model = ai.GetGenerativeModel(
  modelName: "GEMINI_MODEL_NAME",
  safetySettings: safetySettings
);

// ...

```

<br />

*** ** * ** ***

## Available harm categories

The safety filters evaluate prompts and model responses against the following
configurable *harm categories*:

| Harm category | Description |
|---|---|
| `HARM_CATEGORY_HARASSMENT` | Negative, threatening, intimidating, bullying, or abusive comments targeting an individual or identity. |
| `HARM_CATEGORY_HATE_SPEECH` | Content that attacks, demeans, promotes hatred, or incites violence against individuals or groups based on protected attributes (such as race, ethnic origin, religion, disability, age, nationality, veteran status, sexual orientation, or gender identity). |
| `HARM_CATEGORY_SEXUALLY_EXPLICIT` | Contains references to sexual acts, pornography, or other lewd and erotic content. |
| `HARM_CATEGORY_DANGEROUS_CONTENT` | Promotes, facilitates, encourages, or provides instructions for harmful acts, illegal goods and services, weapons, self-harm, or dangerous activities. |
| `HARM_CATEGORY_CIVIC_INTEGRITY` | Content that might be used to mislead voters or undermine civic and electoral processes. *(Supported in select models and regions)*. |

### Non-configurable safety filters

In addition to configurable categories, all requests pass through system-level
filters that can't be adjusted:

- **Child Sexual Abuse Material (CSAM) / Prohibited content** : Prompts or
  responses flagged for prohibited content are immediately blocked
  (`PROHIBITED_CONTENT`).

- **Sensitive Personally Identifiable Information (SPII)** : Responses that
  risk exposing sensitive personal data (such as financial account numbers
  or national IDs) are blocked (`SPII`).

<br />

*** ** * ** ***

## Set thresholds

For each harm category that you want to control for in your app, you need to set
a *threshold*. If the evaluated content meets or exceeds that threshold, the
content is blocked.

### How safety evaluation works: Probability vs. severity

Safety filters evaluate content across two distinct dimensions:

- **Probability**: The model's confidence that content falls within a given
  harm category.

- **Severity**: The magnitude or degree of potential harm should the content
  be harmful.

Each dimension is assigned one of these levels:
`NEGLIGIBLE`, `LOW`, `MEDIUM`, or `HIGH`.

Content can have a **high probability with low severity level**
(for example, mild comedic banter or friendly insults) or
**low probability with high severity level**
(for example, medical or historical discussions mentioning violence).

### Available harm block thresholds

You can set any of the following *thresholds* for the harm categories that you
want to control for in your app:

| Threshold | Description | Allowed levels |
|---|---|---|
| `BLOCK_LOW_AND_ABOVE` | Most restrictive. Blocks content when probability (or severity) is `LOW`, `MEDIUM`, or `HIGH`. | Allows only `NEGLIGIBLE` |
| `BLOCK_MEDIUM_AND_ABOVE` | Moderate restriction. Blocks content when probability (or severity) is `MEDIUM` or `HIGH`. | Allows `NEGLIGIBLE` and `LOW` |
| `BLOCK_ONLY_HIGH` | Least restrictive active filter. Blocks content only when probability (or severity) is `HIGH`. | Allows `NEGLIGIBLE`, `LOW`, and `MEDIUM` |
| `BLOCK_NONE` | Automated response blocking is disabled for this category. Safety ratings metadata is still calculated and returned with the response so your app can perform custom moderation. | All content allowed |
| `OFF` | Turns off the safety filter for this category completely. No automated blocking occurs and no safety rating metadata is returned. | All content allowed |

> [!NOTE]
> **Note:** By default, configurable safety filters for harm categories that aren't specified in your app are **`OFF`**. However, built-in core protections remain active (for example, protections against severe harms (such as child exploitation, cyberattacks, and dangerous weapons)).

<br />

*** ** * ** ***

## Inspect safety ratings and handle blocked content

Content can be blocked at two stages during a request:

1. **Prompt blocked (`PromptFeedback`)**: The input prompt violated safety
   filters before the model generated any output. No response candidates are
   returned.

2. **Response candidate blocked (`finishReason == SAFETY`)**: The model
   evaluated or generated a candidate response that exceeded your configured
   threshold. The generated candidate text is cleared or redacted.

### The `SafetyRating` object

Every evaluated prompt or response candidate contains an array of
`SafetyRating` objects. Each rating provides the following:

- Properties available with both Gemini Developer API and
  Agent Platform Gemini API (formerly Vertex AI):

  - **`category`** : The evaluated [`HarmCategory`](https://firebase.google.com/docs/ai-logic/safety-settings.md.txt#harm-categories).

  - **`probability`** : A discrete rating
    (`NEGLIGIBLE`, `LOW`, `MEDIUM`, or `HIGH`).

  - **`blocked`** : `true` if this specific rating caused the content to be
    blocked.

- Additional properties available with the Agent Platform Gemini API (formerly Vertex AI):

  - **`probabilityScore`** : A floating-point confidence score from `0.0` to
    `1.0`.

  - **`severity`** : A discrete severity level
    (`NEGLIGIBLE`, `LOW`, `MEDIUM`, or `HIGH`).

  - **`severityScore`** : A floating-point severity score from `0.0` to `1.0`.

#### Example `SafetyRating` object

The following example illustrates the raw JSON response payload when a candidate
is blocked by safety filters:

```json
{
  "candidates": [
    {
      "finishReason": "SAFETY",
      "safetyRatings": [
        {
          "category": "HARM_CATEGORY_HARASSMENT",
          "probability": "NEGLIGIBLE",
          "blocked": false
        },
        {
          "category": "HARM_CATEGORY_HATE_SPEECH",
          "probability": "NEGLIGIBLE",
          "blocked": false
        },
        {
          "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
          "probability": "NEGLIGIBLE",
          "blocked": false
        },
        {
          "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
          "probability": "HIGH",
          "blocked": true
        }
      ]
    }
  ],
  "usageMetadata": {
    "promptTokenCount": 24,
    "totalTokenCount": 24
  }
}
```

### Catch safety errors in code

When content is blocked, the client SDKs surface the block as an exception or
error code so your app can handle it gracefully.

### Swift

You can catch `GenerateContentError.promptBlocked` or
`GenerateContentError.responseStoppedEarly`:

```swift
do {
  let response = try await model.generateContent("Your prompt here")
  print(response.text ?? "No text generated.")
} catch GenerateContentError.promptBlocked(let response) {
  // The input prompt was blocked
  if let feedback = response.promptFeedback {
    let reason = feedback.blockReason?.rawValue ?? "unknown"
    print("Prompt blocked for reason: \(reason)")
    for rating in feedback.safetyRatings {
      let cat = rating.category.rawValue
      let prob = rating.probability.rawValue
      print("Category: \(cat), probability: \(prob)")
    }
  }
} catch GenerateContentError.responseStoppedEarly(let reason, let response) {
  // Candidate response was blocked or stopped early
  if reason == .safety {
    print("Response blocked due to safety.")
    if let candidate = response.candidates.first {
      for rating in candidate.safetyRatings where rating.blocked {
        print("Blocked by category: \(rating.category.rawValue)")
      }
    }
  }
} catch {
  print("Unexpected error: \(error)")
}
```

### Kotlin

You can catch `PromptBlockedException` or inspect
`candidate.finishReason`:

```kotlin
try {
  val response = model.generateContent("Your prompt here")
  val candidate = response.candidates.firstOrNull()

  if (candidate?.finishReason == FinishReason.SAFETY) {
    val blockedRating =
      candidate.safetyRatings.firstOrNull { it.blocked }
    println("Response blocked by category: ${blockedRating?.category}")
  } else {
    println(response.text)
  }
} catch (e: PromptBlockedException) {
  val reason = e.response?.promptFeedback?.blockReason
  println("Prompt was blocked: $reason")
} catch (e: Exception) {
  println("Error generating content: ${e.message}")
}
```

### Java

You can catch `PromptBlockedException` or inspect
`candidate.getFinishReason()`:

```java
try {
  GenerateContentResponse response = model.generateContent("Your prompt here").get();
  Candidate candidate = response.getCandidates().isEmpty() ? null : response.getCandidates().get(0);

  if (candidate != null && candidate.getFinishReason() == FinishReason.SAFETY) {
    SafetyRating blockedRating = null;
    for (SafetyRating rating : candidate.getSafetyRatings()) {
      if (Boolean.TRUE.equals(rating.getBlocked())) {
        blockedRating = rating;
        break;
      }
    }
    System.out.println("Response blocked by category: " +
        (blockedRating != null ? blockedRating.getCategory() : "unknown"));
  } else {
    System.out.println(response.getText());
  }
} catch (ExecutionException e) {
  if (e.getCause() instanceof PromptBlockedException) {
    PromptBlockedException pbe = (PromptBlockedException) e.getCause();
    GenerateContentResponse blockedResponse = pbe.getResponse();
    String reason = (blockedResponse != null && blockedResponse.getPromptFeedback() != null)
        ? String.valueOf(blockedResponse.getPromptFeedback().getBlockReason())
        : "unknown";
    System.out.println("Prompt was blocked: " + reason);
  } else {
    System.out.println("Error generating content: " + e.getMessage());
  }
} catch (InterruptedException e) {
  System.out.println("Generation was interrupted: " + e.getMessage());
}
```

### Web

You can inspect `promptFeedback` and `candidate.finishReason`:

```javascript
try {
  const response = await model.generateContent("Your prompt here");

  // Check if the prompt was blocked
  if (response.promptFeedback?.blockReason) {
    console.warn(`Prompt blocked: ${response.promptFeedback.blockReason}`);
    return;
  }

  const candidate = response.candidates?.[0];
  if (candidate?.finishReason === "SAFETY") {
    const blockedRating = candidate.safetyRatings?.find((r) => r.blocked);
    console.warn(`Response blocked by category: ${blockedRating?.category}`);
  } else {
    console.log(response.text);
  }
} catch (error) {
  console.error("Error generating content:", error);
}
```

### Dart

You can inspect `promptFeedback` and `candidate.finishReason`:

```dart
try {
  final response = await model.generateContent([Content.text('Your prompt here')]);

  // Check if the prompt was blocked
  if (response.promptFeedback?.blockReason != null) {
    print('Prompt blocked: ${response.promptFeedback?.blockReason}');
    return;
  }

  final candidate = response.candidates.firstOrNull;
  if (candidate?.finishReason == FinishReason.safety) {
    final blockedRating =
        candidate?.safetyRatings?.where((r) => r.isBlocked == true).firstOrNull;
    print('Response blocked by category: ${blockedRating?.category.name}');
  } else {
    print(response.text);
  }
} catch (e) {
  print('Error generating content: $e');
}
```

### Unity

You can inspect `PromptFeedback` and `candidate.FinishReason`:

```c#
try {
  var response = await model.GenerateContentAsync("Your prompt here");

  // Check if the prompt was blocked
  if (response.PromptFeedback?.BlockReason != null) {
    Debug.LogWarning($"Prompt blocked: {response.PromptFeedback.BlockReason}");
    return;
  }

  var candidate = response.Candidates.FirstOrDefault();
  if (candidate?.FinishReason == FinishReason.Safety) {
    var blockedRating = candidate.SafetyRatings?.FirstOrDefault(r => r.Blocked);
    Debug.LogWarning($"Response blocked by category: {blockedRating?.Category}");
  } else {
    Debug.Log(response.Text);
  }
} catch (Exception ex) {
  Debug.LogError($"Error generating content: {ex.Message}");
}
```

<br />

*** ** * ** ***

## Best practices for responsible app design

- **Defense in depth** : Safety filters are a guardrail, not an instruction.
  Combine safety settings with explicit
  [system instructions](https://firebase.google.com/docs/ai-logic/system-instructions.md.txt) and targeted
  [prompt design](https://firebase.google.com/docs/ai-logic/prompt-design.md.txt) to guide tone and scope.

- **Graceful user feedback** : Never crash or show a blank screen when content
  is blocked. Detect `finishReason == SAFETY` or `PromptBlockedException` and
  display a friendly message informing the user that the request couldn't be
  fulfilled under your content guidelines.

- **Use `BLOCK_NONE` for custom moderation** : If you already have your own
  client-side or server-side moderation pipeline, set thresholds to
  `BLOCK_NONE` to receive the model's `safetyRatings` without automated
  blocking, allowing your app to enforce custom moderation policies.

- **Review Terms of Service** : If you use less restrictive settings
  (`BLOCK_ONLY_HIGH` or `BLOCK_NONE`), ensure your app continues to comply
  with Google's
  [Prohibited Use Policy](https://policies.google.com/terms/generative-ai/use-policy).

## Other options to control content generation

- Learn more about [prompt design](https://firebase.google.com/docs/ai-logic/prompt-design.md.txt) so that you can influence the model to generate output specific to your needs.
- Configure [model parameters](https://firebase.google.com/docs/ai-logic/model-parameters.md.txt) to control how the model generates a response, like max output tokens, the probability of repeated output tokens, etc.
- Set [system instructions](https://firebase.google.com/docs/ai-logic/system-instructions.md.txt) to steer the behavior of the model. This feature is like a preamble that you add before the model gets exposed to any further instructions from the end user.
- Pass a [*response schema*](https://firebase.google.com/docs/ai-logic/generate-structured-output.md.txt) along with the prompt to specify a specific output schema. This feature is most commonly used when [generating JSON output](https://firebase.google.com/docs/ai-logic/generate-structured-output.md.txt#generate-json-basic), but it can also be used for [classification tasks](https://firebase.google.com/docs/ai-logic/generate-structured-output.md.txt#generate-enum-basic) (like when you want the model to use specific labels or tags).