Skip to content

Content moderation for Python + FastAPI

Arcjet content moderation detects harmful content in untrusted text before it is stored, displayed, or forwarded. It is a Guard rule – call it from guard() / Guard, not protect().

What is Arcjet? Arcjet is the runtime security platform that ships with your code. Enforce budgets, stop prompt injection, detect bots, and protect personal information with Arcjet's AI security building blocks.

This example screens inbound text with content moderation before you store or display it.

Content moderation is a Guard rule, so this example uses arcjet.guard inside your FastAPI route – not protect().

We assume you already have a FastAPI project set up. For helper options and denial behavior, see the Agent guards guide.

Install the dependencies:

Terminal window
# Export your Arcjet API key from https://console.arcjet.com
export ARCJET_KEY="ajkey_..."
export ARCJET_ENV=development
pip install arcjet fastapi

Create the example:

main.py
import os
from arcjet.guard import ModerateContent, launch_arcjet
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
app = FastAPI()
arcjet = launch_arcjet(key=os.environ["ARCJET_KEY"])
moderate = ModerateContent()
class MessageRequest(BaseModel):
message: str
@app.post("/messages")
async def create_message(body: MessageRequest):
decision = await arcjet.guard(
label="message.received",
rules=[moderate(body.message)],
)
if decision.conclusion == "DENY" and decision.reason == "MODERATE_CONTENT":
raise HTTPException(
status_code=400,
detail="Harmful content detected – rephrase your message",
)
return {"ok": True}

Then send a test POST request to /messages.

Requests appear in your Arcjet dashboard in real time.

Terminal window
npm install @arcjet/guard
import { launchArcjet, moderateContent } from "@arcjet/guard";
const arcjet = launchArcjet({ key: process.env.ARCJET_KEY! });
const moderate = moderateContent();
const decision = await arcjet.guard({
label: "tools.chat",
rules: [moderate(userMessage)],
});
if (decision.conclusion === "DENY" && decision.reason === "MODERATE_CONTENT") {
throw new Error("Harmful content detected – rephrase your message");
}
const result = moderate.result(decision);
// `detected` is true when harmful content was found. Billing is undefined
// when the service does not report usage. Content moderation uses text_units.
console.log(result?.detected, result?.billing?.unit, result?.billing?.count);

Keep the response generic. Do not leak detector details or explain exactly what was flagged.

Discussion