# Cloudflare Workers

> Deploy Centinel Analytica on your website via the Cloudflare Workers dashboard.

Source: https://docs.centinelanalytica.com/platforms/cdn-edge/cloudflare-worker-standalone

## Overview

This guide covers the console workflow for installing the Centinel Worker as a standalone file.
The worker deploys globally in 2-3 minutes.

> **Have an existing worker?:** If you already have a Cloudflare Worker and want to add Centinel to it, use the [npm package](https://docs.centinelanalytica.com/platforms/cdn-edge/cloudflare-worker-npm.md) instead.

## Prerequisites

* Centinel secret key (for validator API)
* Cloudflare account with a website added
* Access to the Cloudflare dashboard

## Install

1. **Prepare the script**

   1. Download or copy [`centinel-worker.js`](https://docs.centinelanalytica.com/downloads/centinel-worker.js).
   2. Keep your **CENTINEL\_SECRET\_KEY** ready (you'll add it as an environment variable later).

2. **Create the worker**

   1. Log into your Cloudflare dashboard.
   2. Go to **Workers & Pages → Create application → Create Worker**.
   3. Name your worker (e.g. `centinel-protection`).
   4. Click **Deploy** to create the worker with default code.

3. **Upload the script**

   1. In the worker overview, click **Quick Edit** (or go to **Edit code**).
   2. Delete all the default code.
   3. Paste the entire contents of `centinel-worker.js`.
   4. Click **Save and Deploy**.

## Configure

1. **Configure environment variables**

   1. Go to **Settings → Variables and Secrets**.
   2. Click **Add variable** and enter:
      * Variable name: `CENTINEL_SECRET_KEY`
      * Value: `your-secret-key`
      * Type: **Secret**. Do not use a plaintext variable for this.
   3. Optionally add `CENTINEL_VALIDATOR_URL`, `CENTINEL_TIMEOUT`, or `CENTINEL_ENABLE_DEBUGGING`.
   4. Click **Save and Deploy**.

   | Variable                    | Type   | Default                                            | Purpose                                                           |
   | --------------------------- | ------ | -------------------------------------------------- | ----------------------------------------------------------------- |
   | `CENTINEL_SECRET_KEY`       | secret | —                                                  | Required. Without it the worker forwards all traffic unvalidated. |
   | `CENTINEL_VALIDATOR_URL`    | text   | `https://validator.centinelanalytica.com/validate` | Alternate validator endpoint.                                     |
   | `CENTINEL_TIMEOUT`          | text   | `500`                                              | Validator timeout in milliseconds.                                |
   | `CENTINEL_ENABLE_DEBUGGING` | text   | `false`                                            | Set to `true` for verbose logs.                                   |

   > **Use a Worker secret, not a Secrets Store binding:** The worker reads this value as a plain string. A Secrets Store binding arrives as an object, which fails silently and leaves traffic unvalidated.

2. **Add a route to your domain**

   1. Go to **Settings → Domains & Routes** and click **Add**.
   2. Choose **Route**, then enter your pattern (e.g. `'example.com/*'` or `'*.example.com/*'`). A **Custom Domain** works too if the worker owns the hostname.
   3. Select your zone/domain from the dropdown.
   4. Click **Add route**.

### Advanced configuration

Edit the `activateCentinel()` call at the bottom of the script. Keep it at the top level of the
module, exactly as shipped.

```javascript
export default activateCentinel(undefined, {
    // Protect only specific paths (optional; default is every path)
    protectedPathsInclusion: /\/(api|admin|checkout)\//,

    // Also protect requests whose query string matches, on any path (optional)
    protectedQueryInclusion: /[?&]cat=/,

    // Exclude static assets (a default exclusion list is already applied)
    protectedPathsExclusion: /\.(js|css|png|jpg|svg)$/,

    // Alternate validator endpoint (optional)
    validatorURL: 'https://custom-validator.example.com/validate',

    // Validator timeout in milliseconds (default: 500)
    timeout: 500,

    // Verbose logging (default: false)
    enableDebugging: false,
});
```

> **Call activateCentinel() once, at the top level:** The handler holds the failure-backoff state. Calling `activateCentinel()` inside `fetch` resets that state for each request. The worker still calls the validator, but repeated failures can cause more validator traffic.

Path matching uses `url.pathname`, not the full URL. A query string cannot bypass an exclusion. The worker tests `protectedQueryInclusion` against the query string with its leading `?`, for example `?cat=nb&sort=p`. The worker validates a request when the path pattern or the query pattern matches. A Cloudflare route cannot match a query string. Set a route that covers the path, for example `example.com/*`. Use the options above for supported configuration. Editing a bundled constant can change the worker behavior, but the change does not update the integration source or a later download.

```bash
# Install Wrangler 4 (needs Node.js 20+)
npm install -D wrangler@4

# Authenticate
npx wrangler login

# Set secret
npx wrangler secret put CENTINEL_SECRET_KEY

# Deploy
npx wrangler deploy
```

Routes are declarative in Wrangler 4. Add them to `wrangler.toml` rather than on the command line,
then deploy:

```toml
name = "centinel-protection"
main = "centinel-worker.js"
compatibility_date = "2025-03-25"

routes = [
  { pattern = "example.com/*", zone_name = "example.com" }
]
```

## Verify

* Visit your site to confirm traffic flows normally.
* Test that requests to protected paths are validated by the Centinel API.
* Confirm a protected response carries a `Server-Timing: validator;dur=...` header. That is the zero-config signal that the validator was actually called.
* For log output, set `CENTINEL_ENABLE_DEBUGGING` to `true`, then open **Logs → Begin log stream** and reload a protected path. Entries carry `"service": "CentinelAnalytics"`. Unset it when you are done.
* A healthy worker logs nothing by default, so silence in the log stream does not mean it is working. Watch instead for `CENTINEL_SECRET_KEY not set` or a 401 from the validator: either one means traffic is passing through unvalidated.

Per-worker traffic charts are under **Workers dashboard → Your worker → Analytics**.

## Changelog

* **v1.4.0** — Query string inclusion option
* **v1.3.0** — 500 ms default validator timeout
* **v1.2.1** — Edge case fixes
* **v1.2.0** — Security and edge fixes
* **v1.1.3** — Timeout handling
* **v1.1.0** — Error handling
