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 inDEFAULT_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.
When the Guard API cannot answer
If the Guard API cannot answer (a network error, a timeout, a5xx 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.