> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stigg.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Cloudflare

> Wrap a client for Cloudflare AI Gateway or Workers AI to meter and gate calls, with gateway cache hits left unbilled.

Cloudflare serves models in two ways, and the SDK meters both with one recipe:

* **AI Gateway** sits in front of other providers, such as OpenAI or Anthropic, at `gateway.ai.cloudflare.com`, with caching, fallbacks and routing.
* **Workers AI** runs open-weight models, such as Llama, on Cloudflare's own GPUs, at `api.cloudflare.com`.

Both report under the `cloudflare` vendor name, because Cloudflare is who charges you either way.

## Set up

The SDK recognizes both Cloudflare addresses automatically, so you wrap the client as usual.

```typescript AI Gateway, OpenAI client theme={null}
import OpenAI from 'openai';

const gateway = stigg.wrap(
  new OpenAI({
    baseURL: `https://gateway.ai.cloudflare.com/v1/${ACCOUNT_ID}/${GATEWAY_ID}/openai`,
    apiKey: process.env.OPENAI_API_KEY,
  }),
);

await gateway.chat.completions.create({
  model,
  messages,
  stiggContext: { customerId: 'customer-acme', entitlement: { currencyId: 'credits' } },
});
```

```typescript AI Gateway, Anthropic client theme={null}
import Anthropic from '@anthropic-ai/sdk';

const gateway = stigg.wrap(
  new Anthropic({
    baseURL: `https://gateway.ai.cloudflare.com/v1/${ACCOUNT_ID}/${GATEWAY_ID}/anthropic`,
    apiKey: process.env.ANTHROPIC_API_KEY,
  }),
);

await gateway.messages.create({
  model,
  max_tokens: 1024,
  messages,
  stiggContext: { customerId: 'customer-acme', entitlement: { currencyId: 'credits' } },
});
```

```typescript Workers AI, OpenAI client theme={null}
import OpenAI from 'openai';

const workersAi = stigg.wrap(
  new OpenAI({
    baseURL: `https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/ai/v1`,
    apiKey: process.env.CLOUDFLARE_API_TOKEN,
  }),
);

await workersAi.chat.completions.create({
  model: '@cf/meta/llama-3.1-8b-instruct',
  messages,
  stiggContext: { customerId: 'customer-acme', entitlement: { currencyId: 'credits' } },
});
```

```typescript Workers AI, Cloudflare client theme={null}
import Cloudflare from 'cloudflare';

const cloudflare = stigg.wrap(new Cloudflare({ apiToken: process.env.CLOUDFLARE_API_TOKEN }));

await cloudflare.ai.run('@cf/meta/llama-3.1-8b-instruct', {
  account_id: ACCOUNT_ID,
  messages,
  stiggContext: { customerId: 'customer-acme', entitlement: { currencyId: 'credits' } },
});
```

* **A gateway on a custom domain** has no Cloudflare address for the SDK to recognize. Pass the recipe with its base URL: `stigg.wrap(client, { recipe: cloudflareRecipe({ baseUrl }) })`.
* **Ask for usage on streamed calls.** Through the `OpenAI` client, usage is included in a stream only when the request sets `stream_options: { include_usage: true }`.
* **Do not stream `ai.run`.** A streamed `ai.run` call returns raw bytes with no usage in them, so it is checked before it is sent but not metered. Call `ai.run` without streaming, or stream through the `OpenAI` client instead.

## What is reported

Cloudflare forwards each upstream provider's response as it is, so every call reports the token counts in that provider's own format: OpenAI's field names through the OpenAI routes, and Anthropic's through the Anthropic route. For details, see Cloudflare's [AI Gateway](https://developers.cloudflare.com/ai-gateway/) and [Workers AI](https://developers.cloudflare.com/workers-ai/) docs.

| Client | Method | Event name |
| - | - | - |
| `OpenAI` | `chat.completions.create` | `cloudflare.chat.completions.create` |
| `OpenAI` | `responses.create` | `cloudflare.responses.create` |
| `Anthropic` | `messages.create` | `cloudflare.messages.create` |
| `Cloudflare` | `ai.run` | `cloudflare.ai.run` |

| Route | Metrics |
| - | - |
| Chat Completions | `prompt_tokens`, `completion_tokens`, `cached_tokens`, `total_tokens`, the same as [OpenAI](/documentation/ai-agents/providers/openai#what-is-reported) |
| Responses | `input_tokens`, `output_tokens`, `cached_tokens`, `total_tokens`, the same as [OpenAI](/documentation/ai-agents/providers/openai#what-is-reported) |
| Messages | `input_tokens`, `output_tokens`, `cache_read_input_tokens`, `cache_creation_input_tokens`, `total_tokens`, the same as [Anthropic](/documentation/ai-agents/providers/anthropic#what-is-reported) |
| `ai.run` | `prompt_tokens`, `completion_tokens`, `total_tokens` |

A meter that filters on one provider's field names misses calls in the other's format. If you use both the OpenAI and Anthropic routes, price both sets of metrics, or use [normalized metrics](/documentation/ai-agents/usage-metering#normalized-metrics-across-vendors).

Each event also carries:

| Reported | What it is |
| - | - |
| `model` dimension | The model that actually served the call. Through AI Gateway, this can differ from the one you asked for when the gateway routes or falls back. `ai.run` does not return the model, so add it yourself if you need it, for example `stiggContext: { dimensions: { model: '@cf/meta/llama-3.1-8b-instruct' } }`. |
| `cf_aig_log_id` dimension | The AI Gateway log ID for the call, so you can match it with the call's entry in your AI Gateway logs. |
| `cf_aig_step` dimension | Present only when AI Gateway fell back to another provider, with the step of the fallback chain that served the call. |
| Idempotency key | The AI Gateway request ID, when there is one, so a retried report is never counted twice. |

* **Cache hits are free.** When AI Gateway answers from its cache, no provider was paid for the call, so nothing is reported. The call is still checked before it is sent, since whether it will hit the cache is not known in advance. A call through `ai.run` cannot see the gateway's cache status, so it is always metered.
* **No `cost`.** Neither AI Gateway nor Workers AI returns a price, so you can meter tokens but not what the call cost. Workers AI charges in Neurons, and no response reports a Neuron count.

Every usage field the vendor returns is also included, with a `raw.` prefix. See [How usage is reported](/documentation/ai-agents/usage-metering#how-usage-is-reported).


## Related topics

- [JavaScript](/api-and-sdks/changelog/agent-sdk/javascript.md)
- [Apache Iceberg](/documentation/importing-and-exporting-data/export/iceberg.md)
- [Usage metering](/documentation/ai-agents/usage-metering.md)
- [S3-compatible storage](/documentation/importing-and-exporting-data/export/s3-compatible.md)
- [Bring your own vendor](/documentation/ai-agents/providers/custom.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.