
Statsig offers a set of integrations that make usage with Cloudflare easy:

* Automatically pushing changes to Cloudflare's KV store, for low-latency SDK startup
* A helper pattern that handles Statsig SDK overhead, so you can focus on worker logic

{% steps %}
{% step title="Configure Integration" %}
Navigate to *Project Settings > Integrations* in the Statsig Console, then select **Cloudflare** and enter:

* **Cloudflare Account ID**: Can be found in Cloudflare portal on the Compute (Workers) page, under Account Details
* **KV Namespace ID**: Create a new namespace, then go to Account Home -> Storage and Databases -> Workers KV, and copy the ID from the table view.
* **Cloudflare API Key**: In Cloudflare portal under Account Home -> Profile -> API Tokens. Use a token with Account.Workers KV Storage Edit Permissions.

{% accordion title="Advanced: Filtering by Target App" %}
You can also filter the configs that are synced to your KV namespace by Target App. This becomes important as you add more configs to your project, but for now, you can leave this unchecked.
{% /accordion %}
{% /step %}

{% step title="Enable Integration" %}
Click **Enable**. The Statsig backend pushes a config to your KV namespace in under 60 seconds. In your KV namespace, navigate to **KV Pairs**. You'll see an entry starting with `statsig-`. This is the `key` associated with your KV storage. Copy or record this key for later.
{% /step %}

{% step title="Add the Statsig SDK to your Worker" %}
Set up a worker to read experiments and gates from your KV namespace. If you haven't created a worker before, follow the instructions [here](https://developers.cloudflare.com/workers/).

After creating your worker, you need to connect your KV store to your worker through a binding. Navigate to **Compute (Workers)** -> **Select Your Worker** -> **Bindings** -> **Add binding** -> **KV namespace**. Name your binding under **Variable name**. Under **KV namespace**, select your KV store name. For more information on connecting your worker to your KV store, you can follow the instructions [here](https://developers.cloudflare.com/pages/functions/bindings/).
{% /step %}

{% step title="Install the Statsig SDK" %}
Install the Statsig serverless SDK:

```bash
npm install @statsig/serverless-client
```
{% /step %}

{% step title="Use the SDK" %}
The helper method takes two arguments, a handler function, and a ParamsObject. **Put *all* of your worker logic in the handler function**, along with your Statsig usage.

```javascript highlight={5}
import { handleWithStatsig } from '@statsig/serverless-client/cloudflare';

export default handleWithStatsig(
  async (request, env, ctx, client) => {
    // Your business, and Statsig logic here 
  },
  {
   kvKey: 'kv_key',
   envStatsigKey: 'statsig_key',
   envKvBindingName: 'STATSIG_KV'
  }
);
```

{% callout type="note" %}
Store the required ParamsObject params (kvKey, envStatsigKey, envKvBindingName) as env variables, either in your wrangler.toml or as Cloudflare secrets.
{% /callout %}

{% accordion title="ParamsObject Definition" %}
{% parameter name="kvKey" type="string" %}
Environment variable name containing your KV pair key
{% /parameter %}

{% parameter name="envStatsigKey" type="string" %}
Environment variable name containing your Statsig client key
{% /parameter %}

{% parameter name="envKvBindingName" type="string" %}
Your KV binding name
{% /parameter %}

{% parameter name="statsigOptions" type="StatsigOptions" %}
See StatsigOptions [here](/client/javascript-sdk#statsig-options)
{% /parameter %}

**Best practice:**

* store `envStatsigKey` as a Cloudflare secret. You can set this in the Cloudflare dashboard under, **Worker → Settings → Variables and Secrets**
* store `kvKey` and `envKvBindingName` in your wrangler.toml
{% /accordion %}

### Example usage

This is an example of an end-to-end worker function that uses the Statsig SDK and returns a flag value. This is all you need: it compiles as the index.js file in your worker.

{% codetabs %}
```javascript index.js expandable
import { handleWithStatsig } from '@statsig/serverless-client/cloudflare';

export default handleWithStatsig(
  async (request, env, ctx, client) => {
    const randomUserId = Math.floor(Math.random() * 100).toString();
    const gate = client.getFeatureGate("test_cloudflare_sync", { userID: randomUserId });
	const value = gate.value;
    client.logEvent('new_event', { userID: randomUserId });
    return new Response(`Gate check result: ${value}`);
  },
  {
   kvKey: 'kv_key',
   envStatsigKey: 'statsig_key',
   envKvBindingName: 'STATSIG_KV'
  }
);

```

```wrangler wrangler.toml
name = "test"
main = "src/index.js"
compatibility_date = "2025-09-10"

[vars]
kv_key = "statsig-1gh32fg61hds9876"

[[kv_namespaces]]
binding = "STATSIG_KV"
id = "b76664aa8259481e834e7c549443c6541"

[observability]
enabled = true
```
{% /codetabs %}
{% /step %}
{% /steps %}

The helper automatically:

* Initializes the Statsig Client with config specs from your KV store
* Executes your handler code (Your business logic + Statsig usage)
* Flushes all events after your handler completes execution
* Cleans up resources

{% accordion title="Advanced/manual usage" %}
**Use the advanced/manual setup if:**

* You need fine-grained control over initialization timing
* You need fine-grained control over event flushing timing
* You need to customize error handling behavior

## Prerequisites

1. Completed the [Statsig Cloudflare KV integration setup](#configure-integration)
2. [Created and bound a KV namespace to your worker](#add-the-statsig-sdk-to-your-worker)

## Installation

Install the Statsig serverless SDK.

```bash
npm install @statsig/serverless-client
```

## Import

Import the Cloudflare client.

```bash
import { StatsigCloudflareClient } from '@statsig/serverless-client/cloudflare';
```

Connect the components. This involves:

1. Creating a `StatsigCloudflareClient` instance.
2. Initializing the Statsig client
3. Checking a Gate
4. Logging an event
5. Flushing events to Statsig

These steps follow the same pattern as other Statsig SDKs. The only difference is that this SDK initializes from the KV store instead of the Statsig backend.

The example checks a gate called "test\_cloudflare\_sync" set to a 50% pass rate. A random userID is generated on every request, so the gate evaluates to true approximately 50% of the time.

### 1. Creating a `StatsigCloudflareClient` instance

```bash
const client = new StatsigCloudflareClient("<Your Statsig client key>");
```

The client instantiation takes two arguments:

* `sdkKey : string`  This is your Statsig client API key. You can find it on the [Project Settings](https://console.statsig.com/api_keys) page in the Statsig Console. Statsig uses this to authenticate your requests.
* `options : StatsigOptions` Refer to [StatsigOptions](/client/javascript-sdk#statsig-options) for available options.

For best practice:

* store `sdkKey` as a Cloudflare secret. You can set this in the Cloudflare dashboard under, **Worker → Settings → Variables and Secrets**

### 2. Client initialization

The following line initializes the client by loading feature gate and experiment configurations directly from your Cloudflare KV store.

```bash
const initResult = await client.initializeFromKV(env.<YOUR_KV_NAMESPACE_BINDING>, <YOUR_KV_KEY>);
```

The client initialization takes two arguments:

* `KvBinding` This is the binding you named earlier. Remember to provide this argument as `env.YOUR_KV_NAMESPACE_BINDING`
* `KvKey : string` This is the KV pair key that the Statsig integration generated. You can find it under **Workers KV** -> **Your KV namespace** -> **KV Pairs**

For best practice:

* store `kvBinding` and `kvKey` in your wrangler.toml

### 3. Checking a gate

```bash
const value = client.checkGate("test_cloudflare_sync", { userID: randomUserId });
```

This line checks the gate in code.

The `checkGate` method takes two arguments:

* `name : string` The name of the Statsig gate that you are checking.
* `user : StatsigUser` The Statsig user object to check the gate against. For more information on the user object, refer to the [StatsigUser object documentation](/sdks/user#introduction-to-the-statsiguser-object).

Refer to the [JavaScript on-device evaluation SDK documentation](/client/jsOnDeviceEvaluationSDK) for how to check other entities such as experiments and dynamic configs.

### 4. Logging an event

```bash
client.logEvent('gate_check', { userID: randomUserId });
```

This line logs an event in code.

The `logEvent` method takes two parameters:

* `eventOrName : string | StatsigEvent` This is the name and details of the event you are logging.
* `user : StatsigUser` The Statsig user object to log the event for.

For more information on event logging, refer to the [JavaScript on-device evaluation SDK documentation](/client/jsOnDeviceEvaluationSDK#logging-an-event).

### 5. Flushing events

```bash
ctx.waitUntil(statsig.flush());
```

This flushes all events from the SDK to Statsig. Without this step, diagnostic information and logged event data won't appear in the Statsig Console.

### Putting it all together

{% tabs %}
{% tab title="index.js" %}
```Javascript
import { StatsigCloudflareClient } from '@statsig/serverless-client/cloudflare';

export default {
  async fetch(request, env, ctx) {
    try {
      const client = new StatsigCloudflareClient(env.statsig_key);
      
      const initResult = await client.initializeFromKV(env.STATSIG_KV, env.kv_key);
      
      const randomUserId = Math.floor(Math.random() * 100).toString(); //generates a random user id

      const value = client.checkGate("test_cloudflare_sync", { userID: randomUserId });

      client.logEvent('gate_check', { userID: randomUserId });

      ctx.waitUntil(client.flush());
      
      return new Response(`Value: $\{value\}, userID: ${randomUserId});
    } catch (error) {
      return new Response(`Error: ${error.message}`, { status: 500 });
    }
  }
};
```
{% /tab %}

{% tab title="wrangler.toml" %}
```wrangler
name = "test"
main = "src/index.js"
compatibility_date = "2025-09-10"

[vars]
kv_key = "statsig-1gh32fg61hds9876"

[[kv_namespaces]]
binding = "STATSIG_KV"
id = "b76664aa8259481e834e7c549443c6541"

[observability]
enabled = true
```
{% /tab %}
{% /tabs %}

If you want to check on the evaluations you are getting, you can go to the gate you created for this example and look at the evaluations in the Diagnostics tab.

{% figure %}
![Diagnostics Stream](/images/integrations/cloudflare/1cc865ed-e15c-41a4-8979-24e1d457a7b1.png)
{% /figure %}

If you want to check the events you logged, in the **Statsig Console**, go to **Data** -> **Events**

{% figure %}
![Statsig Events log stream showing gate_check events with timestamps and user IDs](../images/client/Events.png)
{% /figure %}

The Cloudflare KV integration for Statsig is now working.

## Other considerations

### Polling for updates

The SDK can't poll for updates across requests since [**Cloudflare doesn't allow for timers**](https://developers.cloudflare.com/workers/reference/security-model/#step-1-disallow-timers-and-multi-threading).
To optimize for edge use cases, Statsig doesn't provide an API to recognize updates to your config specs. When you change your project definition in the Statsig console, Statsig propagates the changes to the KV store, and they take effect the next time you initialize the Cloudflare client.

### Flushing events

The SDK enqueues logged events and flushes them in batches. To ensure events are properly flushed, call flush using `context.waitUntil`. This keeps the request handler alive until events are flushed without blocking the response.

```bash
context.waitUntil(client.flush());
```

### Size limits

Cloudflare KV has maximum size limits that may prevent Statsig from pushing configs into your KV. Refer to the [Cloudflare KV limits documentation](https://developers.cloudflare.com/workers/platform/limits/#kv-limits) for current limits. If your payload continues to grow, filter the payload by a Target App in the integration settings.

### Unsupported features

Statsig doesn't sync ID Lists into Cloudflare KVs. If you rely on large (>1000) ID lists, you can't check them in your Cloudflare Worker.
{% /accordion %}
