Setting Up Cloudflare AI Gateway in Front of a Model Provider
9 min read · updated August 11, 2026
AI Gateway is a URL you put in front of a provider call. There is no SDK to adopt and nothing in your request body changes, which makes the integration genuinely one line — and makes the two ways it fails worth knowing in advance.
The URL is the integration
Cloudflare documents the provider-native endpoint format as https://gateway.ai.cloudflare.com/v1/{account_id}/{gateway_id}/{provider}, where the provider segment names the upstream — OpenAI, Anthropic, Google AI Studio, Workers AI, AWS Bedrock, Azure OpenAI and others. Everything after that base is the provider’s own path, unchanged.
So a call that went to the provider’s chat completions path goes to the same path under the gateway base. Your request body, your model name, your streaming behaviour and your response parsing are all untouched. That is the property that makes this cheap to try and cheap to back out of.
You need two identifiers: your Cloudflare account id, and a gateway id. Cloudflare documents creating gateways from the AI Gateway section of the dashboard, or over the REST API with a token holding the AI Gateway - Read and AI Gateway - Edit permissions. The documentation for that POST does not publish its body fields, so create the first one from the dashboard pane and note the id you chose; that pane is the volatile part of this page and the URL format is not.
Changing one line in an SDK
Most provider SDKs expose a base URL override, which is the whole change:
import OpenAI from "openai";
const client = new OpenAI({
apiKey: env.OPENAI_API_KEY,
baseURL:
"https://gateway.ai.cloudflare.com/v1/" +
env.CF_ACCOUNT_ID +
"/" +
env.CF_GATEWAY_ID +
"/openai",
});
const completion = await client.chat.completions.create({
model: "gpt-4o-mini",
messages: [{ role: "user", content: "summarise this ticket" }],
});- Create a gateway and note its id. Cloudflare documents log collection as being on by default for the auto-created default gateway.
- Store the account id and gateway id as Worker variables, and the provider key as a secret with
npx wrangler secret put OPENAI_API_KEY. The gateway does not hold your provider credential in this mode; it is still yours to pass. - Set
baseURLas above and deploy. - Make one request and confirm it appears in the gateway’s logs before changing anything else.
Do not change the base URL and the model in the same deploy. If something breaks you want one candidate cause, and a gateway failure and a model failure look similar from the outside.
Two authorization headers, two jobs
This is the cause of most first-attempt 401s on this product, and it is entirely mechanical once stated. On the provider-native endpoints at gateway.ai.cloudflare.com there are two credentials in flight and they need separate headers:
Authorizationcarries the provider’s key. The gateway passes it upstream untouched.cf-aig-authorizationcarries the Cloudflare token, and is what the Authenticated Gateway feature checks. Cloudflare describes that feature as ensuring your gateway can only be called with a token supplied in this header.
Put the Cloudflare token in Authorization and you get a 401 — the gateway forwards your Cloudflare token to the provider as if it were a provider key, and the provider rejects it. Cloudflare’s troubleshooting guidance says exactly this: make sure the Cloudflare token is in cf-aig-authorization, not Authorization.
Cloudflare also documents a newer REST API at api.cloudflare.com which uses the standard Authorization header instead, and recommends it for new integrations. The two surfaces have opposite header conventions, so copying a snippet from one into the other reproduces the failure. Establish which surface you are on before debugging a 401.
Workers AI through the same gateway
Calls made through the Workers AI binding can be routed through a gateway without touching a URL, by passing a third argument to run():
const response = await env.AI.run(
"@cf/meta/llama-3.1-8b-instruct-fast",
{ prompt: "What is the origin of the phrase Hello, World" },
{
gateway: {
id: "default",
skipCache: true,
},
},
);Cloudflare documents id and skipCache on that options object. Reaching Workers AI over HTTP rather than through the binding has an extra requirement: Cloudflare documents that Workers AI requests always require the cf-aig-gateway-id header, which no other provider needs. A request that works against OpenAI through the gateway and fails against Workers AI is usually missing exactly that header.
Confirming logs picked it up
The verification step is not optional, because a misconfigured base URL fails in the least helpful way possible: the request succeeds, the model answers, and nothing is logged, because you were talking to the provider directly the whole time.
- Send one request with a distinctive prompt — a UUID in the user message works well, because you can search for it.
- Open the gateway’s logs pane and confirm a row appears for it. One row, with a token count and a latency, is the proof.
- Deliberately break it: change one character in the gateway id and send again. You should get a failure, not a silent success. If you get a successful completion, the base URL is not being applied and your SDK is falling back to its default.
- Restore the id, and only then enable caching, rate limiting or fallbacks on top.
The third step is the one people skip and the only one that actually proves the routing. A green log row can be produced by a prior successful request; a deliberate break cannot.
Once it is verified, be clear with yourself about what has changed operationally. The gateway is now in the request path, which is the point — it is what lets it log, cache and rate limit — but it also means a component you do not control sits between your code and a provider you already did not control. That is usually a good trade, because the observability is worth more than the added hop, and it is only a good trade if you know it happened. A provider outage and a gateway outage look the same from your Worker.
Note too what the gateway does not take off your hands in this configuration. On the provider-native endpoints you are still holding the provider’s key and still passing it on every request, so key rotation, per-environment separation and the blast radius of a leaked credential are all exactly as they were. The gateway sees your traffic; it has not become the party that authenticates to the provider.