Skip to content
Blog

Safety Settings in the Gemini API: Blocking Harmful Content Before It Ships

Configure Gemini API safety settings to block harmful content at the API level. Set category thresholds, handle safety ratings, and build production-ready content filtering.

Published on September 10, 2026

AI Assistant

The Gemini API includes built-in safety filtering that can block harmful content before it ever reaches your application. Understanding and properly configuring these settings is essential for building safe AI applications. This guide covers practical configuration of Gemini’s safety systems for production use.

Gemini Safety Categories

The Gemini API classifies content across four harm categories:

CategoryDescriptionThreshold Levels
HARM_CATEGORY_HARASSMENTContent targeting individuals with intent to harmBLOCK_NONE, BLOCK_ONLY_HIGH, BLOCK_MEDIUM_AND_ABOVE, BLOCK_LOW_AND_ABOVE
HARM_CATEGORY_HATE_SPEECHContent promoting hatred against groupsSame levels
HARM_CATEGORY_SEXUALLY_EXPLICITSexual content and nuditySame levels
HARM_CATEGORY_DANGEROUS_CONTENTDangerous activities, self-harmSame levels

Configuring Safety Settings

Basic Setup

from google import genai
from google.genai import types

client = genai.Client()

# Configure safety settings
safety_settings = {
    "HARM_CATEGORY_HARASSMENT": "BLOCK_MEDIUM_AND_ABOVE",
    "HARM_CATEGORY_HATE_SPEECH": "BLOCK_MEDIUM_AND_ABOVE",
    "HARM_CATEGORY_SEXUALLY_EXPLICIT": "BLOCK_MEDIUM_AND_ABOVE",
    "HARM_CATEGORY_DANGEROUS_CONTENT": "BLOCK_MEDIUM_AND_ABOVE",
}

response = client.models.generate_content(
    model="gemini-2.0-flash",
    contents="Tell me about...",
    config=types.GenerateContentConfig(
        safety_settings=safety_settings,
    ),
)

# Check safety ratings
for rating in response.candidates[0].safety_ratings:
    print(f"Category: {rating.category}")
    print(f"Probability: {rating.probability}")
    print(f"Blocked: {rating.blocked}")

Granular Control

Set different thresholds for different categories:

safety_config = types.GenerateContentConfig(
    safety_settings={
        # Be strict on harassment
        "HARM_CATEGORY_HARASSMENT": "BLOCK_LOW_AND_ABOVE",

        # Moderate on hate speech
        "HARM_CATEGORY_HATE_SPEECH": "BLOCK_MEDIUM_AND_ABOVE",

        # Lenient on dangerous content (for educational content)
        "HARM_CATEGORY_DANGEROUS_CONTENT": "BLOCK_ONLY_HIGH",

        # Strict on explicit content
        "HARM_CATEGORY_SEXUALLY_EXPLICIT": "BLOCK_LOW_AND_ABOVE",
    }
)

Handling Safety Blocks

Detecting Blocked Responses

async def safe_generate(prompt: str, safety_config: dict = None) -> dict:
    """Generate content with safety handling."""
    try:
        response = client.models.generate_content(
            model="gemini-2.0-flash",
            contents=prompt,
            config=types.GenerateContentConfig(
                safety_settings=safety_config or DEFAULT_SAFETY,
            ),
        )

        # Check if response was blocked
        if not response.candidates:
            return {
                "success": False,
                "error": "Content blocked by safety filters",
                "blocked_categories": [
                    rating.category
                    for candidate in response.candidates
                    for rating in candidate.safety_ratings
                    if rating.blocked
                ],
            }

        return {
            "success": True,
            "text": response.text,
            "safety_ratings": [
                {
                    "category": r.category,
                    "probability": r.probability,
                }
                for r in response.candidates[0].safety_ratings
            ],
        }

    except Exception as e:
        return {
            "success": False,
            "error": str(e),
        }

Graceful Degradation

When content is blocked, provide helpful alternatives:

class SafeContentGenerator:
    def __init__(self):
        self.safety_configs = {
            "strict": {
                "HARM_CATEGORY_HARASSMENT": "BLOCK_LOW_AND_ABOVE",
                "HARM_CATEGORY_HATE_SPEECH": "BLOCK_LOW_AND_ABOVE",
                "HARM_CATEGORY_SEXUALLY_EXPLICIT": "BLOCK_LOW_AND_ABOVE",
                "HARM_CATEGORY_DANGEROUS_CONTENT": "BLOCK_LOW_AND_ABOVE",
            },
            "moderate": {
                "HARM_CATEGORY_HARASSMENT": "BLOCK_MEDIUM_AND_ABOVE",
                "HARM_CATEGORY_HATE_SPEECH": "BLOCK_MEDIUM_AND_ABOVE",
                "HARM_CATEGORY_SEXUALLY_EXPLICIT": "BLOCK_MEDIUM_AND_ABOVE",
                "HARM_CATEGORY_DANGEROUS_CONTENT": "BLOCK_MEDIUM_AND_ABOVE",
            },
            "permissive": {
                "HARM_CATEGORY_HARASSMENT": "BLOCK_ONLY_HIGH",
                "HARM_CATEGORY_HATE_SPEECH": "BLOCK_ONLY_HIGH",
                "HARM_CATEGORY_SEXUALLY_EXPLICIT": "BLOCK_ONLY_HIGH",
                "HARM_CATEGORY_DANGEROUS_CONTENT": "BLOCK_ONLY_HIGH",
            },
        }

    async def generate(self, prompt: str, policy: str = "moderate") -> dict:
        config = self.safety_configs[policy]
        result = await safe_generate(prompt, config)

        if not result["success"]:
            # Try with less strict settings
            for fallback_policy in ["permissive", "moderate", "strict"]:
                if fallback_policy != policy:
                    result = await safe_generate(
                        prompt,
                        self.safety_configs[fallback_policy]
                    )
                    if result["success"]:
                        result["used_fallback"] = fallback_policy
                        break

        return result

Production Patterns

Pattern 1: User-Facing Safety Messages

Translate technical safety blocks into user-friendly messages:

SAFETY_MESSAGES = {
    "HARM_CATEGORY_HARASSMENT": (
        "I can't generate content that targets individuals with harm. "
        "Let me help you with something else."
    ),
    "HARM_CATEGORY_HATE_SPEECH": (
        "I can't create content that promotes hatred against any group. "
        "Here are some alternative approaches..."
    ),
    "HARM_CATEGORY_SEXUALLY_EXPLICIT": (
        "I'm not able to generate explicit content. "
        "I can help you with appropriate alternatives."
    ),
    "HARM_CATEGORY_DANGEROUS_CONTENT": (
        "I can't provide information that could enable dangerous activities. "
        "Let me help you find safe alternatives."
    ),
}

def get_user_message(blocked_categories: list) -> str:
    for category in blocked_categories:
        if category in SAFETY_MESSAGES:
            return SAFETY_MESSAGES[category]
    return "I couldn't generate that content. Please try a different approach."

Pattern 2: Logging and Monitoring

Track safety events for analysis:

import logging
from datetime import datetime

class SafetyLogger:
    def __init__(self):
        self.logger = logging.getLogger("safety")

    def log_safety_event(
        self,
        prompt_hash: str,
        blocked: bool,
        categories: list,
        policy_used: str
    ):
        self.logger.info(json.dumps({
            "timestamp": datetime.now().isoformat(),
            "prompt_hash": prompt_hash,
            "blocked": blocked,
            "categories": categories,
            "policy": policy_used,
        }))

    def log_false_positive(self, prompt: str, category: str):
        self.logger.warning(json.dumps({
            "timestamp": datetime.now().isoformat(),
            "event": "false_positive",
            "prompt": prompt[:200],
            "category": category,
        }))

Pattern 3: Content Policy Engine

Build dynamic policies based on context:

class ContentPolicyEngine:
    def __init__(self):
        self.policies = {
            "default": "moderate",
            "child_safe": "strict",
            "educational": "permissive",
            "medical": "permissive",
            "creative_writing": "moderate",
        }

    def get_policy(self, context: dict) -> str:
        """Determine safety policy based on context."""
        user_type = context.get("user_type", "default")
        content_type = context.get("content_type", "default")

        # Check user type first
        if user_type in self.policies:
            return self.policies[user_type]

        # Then content type
        if content_type in self.policies:
            return self.policies[content_type]

        return self.policies["default"]

Advanced: Custom Safety Models

For specific use cases, build custom safety classifiers on top of Gemini’s base:

class CustomSafetyClassifier:
    def __init__(self):
        self.base_safety = GeminiSafetyFilter()
        self.custom_rules = []

    def add_rule(self, rule_name: str, pattern: str, action: str):
        self.custom_rules.append({
            "name": rule_name,
            "pattern": pattern,
            "action": action,
        })

    async def check(self, text: str) -> dict:
        # First, check with Gemini's built-in safety
        gemini_result = await self.base_safety.check(text)

        # Then apply custom rules
        custom_violations = []
        for rule in self.custom_rules:
            if re.search(rule["pattern"], text):
                custom_violations.append(rule["name"])

        return {
            "safe": gemini_result["safe"] and len(custom_violations) == 0,
            "gemini_result": gemini_result,
            "custom_violations": custom_violations,
        }

Best Practices

  1. Start with moderate settings — Begin with BLOCK_MEDIUM_AND_ABOVE for all categories and adjust based on your specific needs.

  2. Test with adversarial inputs — Deliberately try to generate blocked content to verify your safety settings work as expected.

  3. Monitor false positives — Track legitimate content that gets blocked. Too many false positives indicate overly strict settings.

  4. Implement fallback strategies — When content is blocked, don’t just fail. Provide helpful alternatives or retry with adjusted settings.

  5. Document your policies — Clearly communicate your content policies to users. Transparency reduces frustration with safety blocks.

Conclusion

Gemini’s built-in safety settings provide a powerful first line of defense against harmful content. By properly configuring category thresholds, implementing graceful degradation, and monitoring safety events, you can build applications that are both safe and user-friendly. The key is balancing safety with usability — strict enough to prevent harm, flexible enough to serve legitimate use cases.

References: