Skip to main content
Cloudflare provides DNS, CDN caching, DDoS protection, and WAF services in front of websites and APIs. Cloudflare Workers let you run JavaScript at the edge for matching requests before Cloudflare forwards them to the origin. This integration evaluates requests to AI routes that you operate without changing application code. It does not cover direct calls that bypass the Cloudflare zone, model responses, or employee access to third-party AI services.

Integration capabilities

Before you start

Start with the policy in Observe mode. Findings appear in Activity without affecting traffic. Switch to Enforce after reviewing the results. See Policies.
The Worker does not read the response, so configure rules for this collector in the Input phase.

1. Create a collector API key

On the Cloudflare collector, open Auth and create a key. It is shown once. The key identifies the collector and its assigned policy; the request body does not need a collector ID.

2. Scaffold the Worker

Put the handler in src/index.js. The remaining configuration goes in wrangler.toml.

3. Store the key as a secret

A secret reaches the handler as env.TRUSTGUARD_API_KEY and never appears in wrangler.toml, so the config file stays committable. Do not use a plain vars entry for it.

4. Evaluate the request body

The handler clones the request, sends the body to POST /v1/evaluate with the collector key as a bearer token, and forwards to the origin only if the verdict is not block:
The following details determine what the handler evaluates:
  • request.clone(): read the clone, not the request. Consuming the original body stream leaves nothing to forward to the origin.
  • request.method === "POST": other methods pass through without evaluation. Update the condition if an endpoint accepts prompts through another method.
  • payload.input is the complete body: the raw POST body as a string, JSON scaffolding, model name and message roles included. Detectors see one blob with no role boundaries: retrieved text, your system prompt and the user’s turn are indistinct. Parse the body and send the user turn if you need that distinction.
This sample does not implement redaction. A transform verdict contains TrustGuard’s { "input": … } payload rather than your origin’s request schema. Applying it requires custom, schema-aware code that inserts the rewritten text into the original body. Use Block rules unless you have implemented and tested that conversion.
There is no try/catch around the request to TrustGuard. Catch failures and choose explicitly whether to return fetch(request) (fail open) or a 403 (fail closed). Without a catch, Cloudflare returns its own error page.

5. Route the Worker at your AI paths

Bind the Worker to the specific paths that carry prompts, not to the whole zone:
The routes list defines coverage. A narrow pattern can omit an AI path; a broad pattern adds an evaluation round trip to unrelated requests. Zone-level WAF rules run before the Worker. You can add repeat offenders to a Cloudflare IP List and block them in WAF before they reach the Worker.

6. Verify

  1. Put the policy in Enforce and POST a prompt to a guarded path that trips a rule.
  2. Confirm that the caller receives 403 with the body Blocked by TrustGuard.
  3. Confirm the event in TrustGuard Activity, under the consumer_id you sent as x-user-id.
  4. Send the same prompt to a path not listed in routes and confirm that no event is recorded.

Reference

Coverage

The Worker evaluates POST bodies on matched routes. It does not inspect model responses or support redaction. Each evaluated request adds one round trip from the edge to {TRUSTGUARD_URL}.

What is evaluated

Every call is POST /v1/evaluate with the collector key as a bearer token, and the policy’s detectors decide the verdict. /v1/evaluate answers 200 for every verdict including block, so the handler must read result.status. A successful HTTP response does not imply an allow verdict.

Configuration

Attributes

  • consumer_id: read from the x-user-id request header, "" when absent. It is what per-consumer policy routing keys on, so without it every caller shares the collector’s default policy, and gates matching consumer.id never fire.
  • session_id: read from x-session-id. The sample sends "" when the header is absent. Send a stable, verified conversation ID if you need reliable grouping in Activity.
  • Both values are caller-controlled headers. If policy decisions depend on them, replace them in the Worker with values derived from an authenticated identity.

Troubleshooting