Integration capabilities
Before you start
Create the policy in Observe mode. Observe records decisions in Activity without enforcing
them. Review the results, then switch the policy to Enforce. See
Policies.
1. Install
2. Guard the request path
Build the client once at module scope and reuse it. The middleware reads the body, requests a verdict, and handles it before calling the route handler:if response.is_blocked: return beforecall_next. Without it, the finding is recorded and the request reaches your handler anyway.request._body = …: a DLP rule masks by rewriting the payload, andrequest._bodyis where Starlette caches the body it will hand the handler. Assign the transformed body so the route receives the masked version.AsyncTrustGuard, notTrustGuard: in an async framework, the synchronous client blocks the event loop for the length of every evaluation, on every request.
consumer_id and session_id usually come from an identity
header and session cookie. consumer_id routes the request to a per-consumer
policy and attributes the finding in Activity. session_id groups turns in a
conversation.
Where the middleware attaches differs by framework; the guard() call does not:
Django and Flask serve synchronously in the common deployment, so the
synchronous
TrustGuard client is the right one there.
3. Scope it to the AI routes
Middleware runs on every request by default, including static assets and health checks. Filter by path or mount it only on the router that contains AI routes. Therequest.method == "POST" condition in the example is a starting point; add
the path filters required by your application.
4. Evaluate the response too
The middleware above covers input. The completion your handler produces is a second, separate evaluation withdirection="output", and the natural place for it
is the route itself, using the Python SDK client you
already built:
direction on every call. It selects the
detector phase: input before the model and
output after it. The field defaults to input, so omitting it from the second
call prevents Output-phase rules from running. The response body field remains
input on an output call; direction identifies the phase.
5. Verify
- Send a POST to a wrapped route with a jailbreak string in the body.
- Confirm the event in TrustGuard Activity, under the
consumer_idthe middleware sent. - Reconcile the run with the console using
trace_idfrom the response. It is the same identifier the finding carries in Activity.
403 with
{"detail": "Blocked by TrustGuard"}.
Reference
Coverage
Use middleware to apply the same check to selected HTTP routes. Background jobs,
queue consumers, and internal calls bypass it; instrument those call sites with
the SDK.
⚠️ Your middleware enforces the verdict. The
403 branch and
the request._body assignment turn a verdict into a block or redaction. LLM
output requires the second evaluation in
step 4.
➖ Tool calls are outside the middleware scope. The middleware has no hook
that fires when an agent chooses a tool or reads a result. Guard the tool
dispatch with the SDK using protocol="mcp", or route
MCP through TrustGate.
Limits. Use the async client in async frameworks, or every evaluation blocks
the event loop. Scope the middleware to the AI routes so unrelated endpoints do
not pay the latency. Output coverage needs a second evaluation on the response.
What is evaluated
The middleware sends the raw body as
{"input": body.decode()}, so what is
evaluated is the whole request payload, not a prompt field you selected out of it.
payload also accepts a full OpenAI, Anthropic, or Gemini provider body if the
handler receives one.
Configuration
A
block verdict still returns HTTP 200 from TrustGuard. The 403 in the
example is returned by your service. The full response carries status, findings,
transformed_payload, trace_id and request_id; see
Evaluate API for the contract behind the client.
Decide what an unreachable TrustGuard does. Wrap the call and handle timeouts
and connection errors explicitly. See
the SDK’s fail-open/fail-closed guidance
and set a timeout that does not hold requests open indefinitely.
The five reduced statuses (block, ask, transform, report, allow) behave
here as they do for any application collector; ask is advisory, because
middleware has no one to prompt. See
the SDK’s status table.
Other languages and runtimes: Node.js middleware
for Express and Next.js, or REST from any framework without
an SDK.
Attributes
Middleware can send context available at the request layer:
Both defaults in the snippet fall back to
"". An empty consumer_id means no
per-consumer policy routing and no attribution in Activity, so resolve the
authenticated user before the middleware runs, or read the verified identity
exposed by your authentication layer. Context produced by the handler, such as retrieved-document
provenance, is not available to middleware that runs before the handler.
Troubleshooting
Related
- Python SDK: evaluate the model call with application context
- Evaluate API: request and response reference
- Policies: Observe and Enforce modes, gates, and policy phases
- Collectors: keys, policy routing, and per-consumer overrides
- Node.js middleware · REST: use the same pattern in other runtimes
- Coverage: compare available collectors