Skip to main content
PromptGuardMiddleware from promptguard.integrations.fastapi scans prompts as requests reach your app, before your route runs. Use it when your app accepts prompts but calls the LLM somewhere auto-instrumentation does not patch. With promptguard.init() also on, the same text is scanned twice. It works with any ASGI app and needs no extra install:

Add the middleware

What it scans

It reads the fields named in DEFAULT_PROMPT_FIELDS (messages, prompt, system and the like) from any request body on the selected paths: JSON, text/plain and form bodies, in their declared charset, and gzip or deflate bodies once decompressed. Content blocks and tool calls go to the Guard API as they are. It scans them with the async Guard client and answers a block with 403 and the error envelope before your route runs; otherwise your route receives the body unchanged. paths and exclude_paths match whole segments of the path your routes see, with any root_path removed, so they work in a mounted app: /v1/chat covers /v1/chat/completions but not /v1/chatter. A body larger than DEFAULT_MAX_BODY_BYTES, before or after decompression, is refused with 413. So is a request the Guard API rejects as too large, in every mode, so padding a prompt cannot get it through.
multipart/form-data bodies are not scanned. A prompt sent as a multipart form field reaches your route unscanned, so scan it in the route with the Guard client if your app accepts prompts that way.

When the Guard API cannot answer

If the Guard API cannot answer (a network error, a timeout, a 5xx or a 429), the request goes through unscanned and a WARNING is logged with promptguard_event="guard_unavailable_fail_open"; pass fail_open=False to answer 503 instead. The SDK README lists every field, body type and outcome.