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:
| Category | Description | Threshold Levels |
|---|---|---|
HARM_CATEGORY_HARASSMENT | Content targeting individuals with intent to harm | BLOCK_NONE, BLOCK_ONLY_HIGH, BLOCK_MEDIUM_AND_ABOVE, BLOCK_LOW_AND_ABOVE |
HARM_CATEGORY_HATE_SPEECH | Content promoting hatred against groups | Same levels |
HARM_CATEGORY_SEXUALLY_EXPLICIT | Sexual content and nudity | Same levels |
HARM_CATEGORY_DANGEROUS_CONTENT | Dangerous activities, self-harm | Same 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
-
Start with moderate settings — Begin with
BLOCK_MEDIUM_AND_ABOVEfor all categories and adjust based on your specific needs. -
Test with adversarial inputs — Deliberately try to generate blocked content to verify your safety settings work as expected.
-
Monitor false positives — Track legitimate content that gets blocked. Too many false positives indicate overly strict settings.
-
Implement fallback strategies — When content is blocked, don’t just fail. Provide helpful alternatives or retry with adjusted settings.
-
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: