Skip to main content
The OpenAI Moderation policy sends text to OpenAI’s Moderations API and records a score for every category the model returns. It either blocks the call or lets it through: the Moderations API returns scores, not rewritten text, so there is nothing for this policy to put back. Applies to LLM traffic only. Text only.
This policy puts a synchronous call to OpenAI in front of every inspected leg. What that costs depends on your region and the size of the conversation, so measure it in your own environment rather than assuming.

Before you configure: the OpenAI key

This policy calls OpenAI with a credential of your own, so you need a key before it can do anything. That is the whole prerequisite — there is no resource to create, no template to build and no permission to grant, which is what makes this the quickest of the guardrails to stand up. Two things worth knowing before you pick a key. The Moderations API is billed separately from your model usage, and this policy calls it on every inspected leg in its scope. And a key you save here never comes back to your browser, so you cannot read it off the policy afterwards — give it a key scoped to moderation rather than one that can also spend on completions, and keep your own copy wherever you keep your other credentials.

Configure the policy

Open Policies → Library → OpenAI Moderation. Three fields, and only API Key is required. See Making it block for what this policy does with nothing else touched.
Saving validates more than “is it filled in.” The gateway rejects the write with 422 validation_failed for an unknown Model — unless it is exactly the model already stored on this policy. A model already stored under older rules stays editable; only a newly introduced bad value is refused.

The key, once saved

A key you save is never sent back to the browser. Reopen the policy and the field tells you only that a key is set; it does not show you the key. You can replace it, and you cannot read it. Rotating means pasting the new key over that marker, which is also the only way to correct a key you typed wrongly.

Inspecting the response too

The request is always inspected — that is not a setting, and it is one call to OpenAI on every turn. Inspect model responses, the toggle directly below API Key, is off by default. Turn it on and the model’s answer is sent to the Moderations API too, checked exactly like the request: a second call to OpenAI on every turn. There is no way to inspect the response only — the request is always inspected first. Measure what the request alone costs you before you turn this on; it is the call that can stop something before it reaches the model, and it is the one this policy always makes.
With Inspect model responses on, a streamed response is inspected as it is generated, and a failure of that check lets the stream continue.

Mode and scope

Start in Observe and read the recorded per-category scores before you switch to Enforce — this policy already blocks anything OpenAI flags by default, so Observe is where you see what that would catch before it starts refusing calls.

Making it block

In Enforce, this policy refuses any text OpenAI itself flags. That is true the moment you save it, with nothing else to touch: every category OpenAI scores for the chosen model, with no number of yours involved and no extra step to take. Observe records the same verdict without refusing anything, which is why it is worth switching to first — see Mode and scope.

How the decision is made

1

The text is flattened and sent in one call

On the request leg, the system prompt and the content of every message are joined with newlines into a single string. On the response leg, the assistant’s content alone. One call, one string.
2

Scores are aggregated across the returned results

The highest score per category wins, and a category flagged in any result counts as flagged.
3

A flagged category is a violation

Out of the box, any category OpenAI itself marks as flagged is a violation — every category it returns for the chosen model.
4

A violation in Enforce refuses the call

The caller gets 403, and the response lists every category that was flagged, with the score OpenAI returned for it. The wording is This content violates our usage policy.

Modes and failures

Those decision names are what you read on the request’s Policies tab in Activity: allowed, reported, block, and — when the call to OpenAI itself failed — failed_open, in Enforce and Observe alike, and failed_closed when the content caused the failure and Enforce refused it. Expect failed_open on a first run: a key that is wrong, revoked or out of quota looks from here exactly like an outage at OpenAI. The event’s failure_reason field says which: transport (the call failed or timed out), verdict_incomplete (OpenAI answered without a usable result), config_invalid (the stored settings could not be used), or decode_failed (the gateway’s own request or response body could not be decoded before OpenAI was ever called).
What happens when OpenAI cannot evaluate depends on the cause.
  • OpenAI is unavailable, or the policy is misconfigured: fail open. A revoked key, an OpenAI rate limit, a malformed response, a timeout or an outage lets the request through uninspected, and the caller sees nothing different. The only trace is failed_open on the event and the trace, so check the event’s failure_reason field before OpenAI’s status page, and treat a run of failed_open as the policy not guarding anything.
  • The content caused it: blocked in Enforce. Content larger than OpenAI accepts, or a body the gateway cannot decode, is refused with 403 and recorded as failed_closed.
  • Observe only records either case and never blocks.

Limits

  • It cannot mask. There is no anonymise action; the call is blocked or it is not. For redaction use TrustGuard or Regex Replace.
  • Inspect model responses is off by default. The model’s answer is not scored until you turn it on.
  • A streamed response is inspected as it is generated, with Inspect model responses on. If the check itself fails, the stream is not cut.
  • Text only, and structure is lost. Roles, tool calls, tool definitions and attachments are not sent — the request leg becomes one newline-joined blob. A detector that would care which participant said something cannot.
  • Your own system prompt is scored. It is the first thing in that blob, and a security-related system prompt can score high enough to matter. Check it in Observe before enforcing.
  • LLM traffic only. The policy does not apply to MCP (Model Context Protocol) tool calls.

Verify the policy

Open the Playground, pick an application the policy applies to, and work through these in order. Steps 2 and 3 are one loop: observe, then enforce.
1

Control — the path works at all

Expect a normal reply and the decision allowed. If this fails, the problem is the application, the model or the key. Fix it before going on.
2

Observe — learn what your traffic scores

Leave the policy in Observe and send real prompts, including ones you expect to be borderline. Then open Activity, open each request, and read the per-category scores and the flagged verdict on its Policies tab — this is what decides whether Enforce would have refused it.
3

Enforce — confirm a violation is refused

Switch the policy to Enforce and resend a prompt from step 2 that OpenAI flagged.Expect the decision block and a 403 naming the category and the score. Then confirm the model was never called: open the request in Activity, go to its Policies tab, and read Aggregated Latency. The Provider row should show no time at all. That the provider leg is empty is the evidence that matters.
Every decision is recorded on the request in Activity, in Observe mode too: open the request and read its Policies tab, where each policy in the chain shows its decision and what it found. The event schema documents the underlying fields if you need to match on them from an alert.

Troubleshooting