Skip to content

Gemini's Safety Settings: The Harm Categories and Threshold Levels

9 min read · updated August 11, 2026

Gemini’s safety filters are configurable per request, per category, on a scale of four block levels plus off. Getting them wrong produces a response with no text in it and no error, so the response fields matter as much as the request ones.

The categories you can adjust

Google’s safety settings reference documents four adjustable harm categories for the Gemini API:

  • HARM_CATEGORY_HARASSMENT — negative or harmful comments targeting identity or protected attributes.
  • HARM_CATEGORY_HATE_SPEECH — content that is rude, disrespectful or profane.
  • HARM_CATEGORY_SEXUALLY_EXPLICIT — references to sexual acts or other lewd content.
  • HARM_CATEGORY_DANGEROUS_CONTENT — promotion of or assistance with harmful acts.

A fifth, HARM_CATEGORY_CIVIC_INTEGRITY, was added later for election-related queries and is documented separately from the four above. Treat it as a category you may see named in responses and in client enums; whether it is adjustable, and what its default is, differs from the original four and has changed since it was introduced. If your handling code switches exhaustively over categories, it needs a default branch.

Category lists grow. The four above have been stable since the Gemini API launched; civic integrity was added afterwards. Read Google’s reference rather than a hard-coded enum in a client library that may lag the API.

Separately from these, Gemini applies non-configurable filters— child safety chief among them—which no setting disables. There is no combination of safetySettings that turns off all filtering.

The threshold values

Each category takes a threshold, expressed as the probability level at which content is blocked. The documented values, from least to most permissive:

  • BLOCK_LOW_AND_ABOVE — block when the probability of harm is low, medium or high. The strictest setting.
  • BLOCK_MEDIUM_AND_ABOVE — block at medium or high.
  • BLOCK_ONLY_HIGH — block only at high probability.
  • BLOCK_NONE — do not block on this category. Safety ratings are still returned; only the block action is suppressed.
  • OFF — turn the filter off for the category entirely.
  • HARM_BLOCK_THRESHOLD_UNSPECIFIED — the proto default; the model’s own default applies.

The distinction people miss is between BLOCK_NONE and OFF. BLOCK_NONE keeps the classifier running and still reports a rating on every response; OFF disables the filter for that category. If you want ratings for logging or your own thresholding while never blocking, BLOCK_NONE is the one that gives you the numbers.

The word “probability” here is doing precise work. Gemini’s safety ratings report the probability that content is of a given harm type, not the severity of the harm if it is. A mildly rude sentence can carry a high harassment probability; a clinical medical passage can carry a low dangerous-content probability despite discussing serious matters. Thresholding on probability is therefore not the same as thresholding on how bad the content is, and calibrating your settings on a corpus of your own real traffic beats reasoning about the labels.

Setting them in a request

safetySettings is a top-level array on the request, beside contents and generationConfig. Categories you do not mention keep their defaults.

{
  "contents": [
    { "role": "user", "parts": [{ "text": "Summarise this incident report." }] }
  ],
  "safetySettings": [
    { "category": "HARM_CATEGORY_HARASSMENT",        "threshold": "BLOCK_ONLY_HIGH" },
    { "category": "HARM_CATEGORY_HATE_SPEECH",       "threshold": "BLOCK_ONLY_HIGH" },
    { "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "threshold": "BLOCK_MEDIUM_AND_ABOVE" },
    { "category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "BLOCK_ONLY_HIGH" }
  ]
}

The settings above are a realistic shape for a workplace incident-report tool: the text will legitimately quote abusive language and describe dangerous events, so the two categories that fire on quoted material are relaxed while the unrelated one is left strict. That is the right way to think about tuning—relax the categories your domain collides with, not all of them.

Two places a block appears in the response

A safety decision can be made about the prompt or about the response, and they surface in different fields. Confusing them is the most common debugging dead end here.

Prompt blocked

There is no candidates array at all. Instead the response carries promptFeedback with a blockReason:

{
  "promptFeedback": {
    "blockReason": "SAFETY",
    "safetyRatings": [
      { "category": "HARM_CATEGORY_HARASSMENT", "probability": "HIGH", "blocked": true }
    ]
  }
}

Client code that does response.candidates[0] throws here rather than reporting the block, which is why the symptom is so often an index error in a stack trace rather than a message about safety.

Response blocked

The prompt was fine and the generation was stopped. There is a candidate, it has no usable content, and its finishReason is SAFETY:

{
  "candidates": [
    {
      "finishReason": "SAFETY",
      "safetyRatings": [
        { "category": "HARM_CATEGORY_DANGEROUS_CONTENT", "probability": "MEDIUM", "blocked": true }
      ]
    }
  ],
  "usageMetadata": { "promptTokenCount": 412, "totalTokenCount": 412 }
}

Both cases return HTTP 200. Neither is an error in the transport sense, and any retry logic keyed on status codes will not notice. The empty-response-with-no-error case is worth reading in full if that is what brought you here.

Reading safetyRatings on an ordinary response

Ratings are not only present on blocks. A perfectly ordinary response carries them too, and they are the most under-used diagnostic in the API because they let you see how close a request came to a block that did not happen.

"safetyRatings": [
  { "category": "HARM_CATEGORY_HARASSMENT",        "probability": "NEGLIGIBLE" },
  { "category": "HARM_CATEGORY_HATE_SPEECH",       "probability": "NEGLIGIBLE" },
  { "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "probability": "NEGLIGIBLE" },
  { "category": "HARM_CATEGORY_DANGEROUS_CONTENT", "probability": "MEDIUM" }
]

probability takes four values — NEGLIGIBLE, LOW, MEDIUM, HIGH — and lines up exactly with the thresholds, which is why the threshold names read as they do. A rating of MEDIUM passes under BLOCK_ONLY_HIGH and is blocked under BLOCK_MEDIUM_AND_ABOVE. The response above is a request that would have been blocked by the default posture on one category and was allowed through by a relaxed one.

Two uses follow, and both are better than tuning thresholds by guesswork.

  • Calibrate on your own traffic. Set every category to BLOCK_NONE in a staging environment, run a representative sample of real prompts through it, and record the distribution of probabilities per category. You will usually find one category producing almost all the MEDIUM and HIGH ratings, and that is the only one worth adjusting. Relaxing all four because one was noisy is the common overcorrection.
  • Apply your own policy on top. With BLOCK_NONE you get the classifier’s opinion and keep the decision. That is the right arrangement when your product has an editorial policy that is not the same shape as four harm categories — you can route a HIGH harassment rating to human review rather than to a refusal message, which is not something a threshold can express.

One caution on interpreting the values: the Gemini API reports probability, while Vertex AI additionally reports a severity dimension for the same categories. If you are reading an example or a dashboard built on Vertex, the extra field is not something missing from your response — it is a different surface.

What the settings do not control

Safety settings decide whether the platform blocks a completion. They do not decide whether the model declines. A model that answers “I can’t help with that” in ordinary prose, with finishReason: STOP and every safety rating at NEGLIGIBLE, has not been blocked—it has been trained to refuse, and no threshold changes that. The two look identical to a user and completely different in the response body, so distinguish them by field rather than by reading the text.

Two further boundaries are worth knowing. Category settings do not apply to RECITATION, which is a separate finish reason for output that reproduced training data too closely. And they do not govern what your account is permitted to do: usage policies apply above the API, so a permissive threshold is not permission.