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

# Cloudflare Worker integration

> Proxy the Dáva browser listener through your own Cloudflare Worker and relay server-confirmed events from your backend.

This guide covers the customer-operated Cloudflare Worker pattern: a Worker you deploy in your own Cloudflare account that serves as a first-party proxy for both browser events and server-confirmed events.

There are two independent capabilities:

1. **Browser proxy** — the Worker serves the Dáva snippet and forwards browser events through your own subdomain (e.g. `collect.yourdomain.com`), so no third-party CDN URLs appear in your page source.
2. **Server relay** — a dedicated route on the same Worker that your backend calls explicitly to forward server-side events to Dáva. The Worker adds your API key and forwards the payload; your backend supplies the event.

<Note>
  This is **your own Worker** deployed in your own Cloudflare account. Dáva does not operate this Worker — you are responsible for deploying it, maintaining it, and paying for Cloudflare Workers capacity.
</Note>

## Quickstart

The steps below are the fast path through the browser proxy setup. Each step links to the full detail further down this page and in [Install the tracking snippet](/tracking/install-snippet#install-method-2-customer-operated-cloudflare-worker-proxy).

<Steps>
  <Step title="Dashboard — get your Worker endpoint">
    Log in to your Dáva workspace → **Settings → Workspace → Settings & Integrations**. Copy the **Worker endpoint URL** shown there — this is the value you'll paste into `DAVA_WORKER_URL` below.
  </Step>

  <Step title="Terminal — check the Wrangler CLI">
    ```bash theme={null}
    wrangler --version
    wrangler -h
    ```

    Confirms `wrangler` is installed and lets you browse all available commands. If it's missing, install it first: `npm install -g wrangler` or `pnpm add -g wrangler`.
  </Step>

  <Step title="Log in to Cloudflare">
    ```bash theme={null}
    wrangler login
    wrangler whoami
    ```

    `login` opens a browser to authorize the CLI against your Cloudflare account; `whoami` confirms which account/email you're now authenticated as — check this matches the account you'll deploy the Worker into.
  </Step>

  <Step title="Terminal — scaffold the Worker">
    ```bash theme={null}
    wrangler init dava-proxy && cd dava-proxy
    ```

    This creates a default `wrangler.jsonc` and `src/index.ts` — you'll replace both in the next step.
  </Step>

  <Step title="Paste the template">
    * In `wrangler.jsonc`: set `DAVA_WORKER_URL` to the value from step 1, keep `DAVA_SNIPPET_URL` as-is.
    * In `src/index.ts`: set `ALLOWED_ORIGINS` to your real domains (bare domain + `www`).
    * Don't keep both `wrangler.toml` and `wrangler.jsonc` in the project — Wrangler silently prefers one over the other.
  </Step>

  <Step title="Deploy">
    ```bash theme={null}
    wrangler deploy
    ```
  </Step>

  <Step title="Bind a Custom Domain (Cloudflare dashboard)">
    **Workers & Pages → dava-proxy → Settings → Domains & Routes → Add Custom Domain**. Enter your dedicated subdomain, e.g. `collect.yourdomain.com` — Cloudflare creates the DNS record and SSL certificate automatically.

    You do **not** need to add a Workers Route on your main domain — Custom Domain replaces it and avoids the silent breakage Routes have on sites fronted by another CDN in front of Cloudflare.
  </Step>

  <Step title="Update the script tag on your site">
    ```html theme={null}
    <script
      src="https://collect.yourdomain.com/_dava/listen.js"
      data-site="acct_..."
      data-endpoint="https://collect.yourdomain.com/_dava/events"
      defer
    ></script>
    ```

    Two common mistakes that silently drop every event: leaving out `data-endpoint`, or using the wrong path (`/_dava/t/event` instead of `/_dava/events`).
  </Step>

  <Step title="Verify">
    Quick command-line check before opening the browser — replace `collect.yourdomain.com` with your dedicated subdomain:

    ```bash theme={null}
    curl -v https://collect.yourdomain.com/_dava/listen.js
    curl -i -X OPTIONS https://collect.yourdomain.com/_dava/events \
      -H "Origin: https://yourdomain.com" \
      -H "Access-Control-Request-Method: POST" \
      -H "Access-Control-Request-Headers: Content-Type"
    ```

    * `listen.js` should return `200` with `content-type: application/javascript`. A TLS error here (`unrecognized name` / handshake failure) means the Custom Domain isn't bound yet or DNS hasn't propagated — recheck step 6.
    * `OPTIONS` should return `204` with `access-control-allow-origin` echoing your `Origin`. If it's missing, check `ALLOWED_ORIGINS` in `src/index.ts`.

    Then in DevTools Network on your actual site: the preflight `OPTIONS` request should return `204`, and `POST /_dava/events` should return `200`. Finally, check your Dáva workspace — new events/sessions should appear in near real time.
  </Step>
</Steps>

## Browser proxy

Follow the **Install method 2** steps in [Install the tracking snippet](/tracking/install-snippet#install-method-2-customer-operated-cloudflare-worker-proxy). That guide covers:

* Scaffolding a Worker project with `wrangler init`
* The full `wrangler.jsonc` and `src/index.ts` template (with CORS, `User-Agent` and `CF-Connecting-IP` header forwarding, and the dedicated-subdomain approach)
* Binding a Cloudflare Custom Domain to the Worker
* Updating your script tag to load the snippet through the proxy

Return to this page once your proxy subdomain is live and browser events are flowing.

## Server relay

The server relay is an **explicit, named route** you add to your Worker. Your backend calls this route when it has a server-confirmed event to record — for example, after a payment gateway confirms a purchase. The Worker receives the payload, adds your Dáva API key, and forwards the request to `POST https://api-v2.davazmysel.com/v1/events`.

<Note>
  The relay is not automatic. The Worker does not intercept or auto-detect backend traffic on your subdomain. Your own backend code must call the relay route with the event payload at the appropriate time.
</Note>

### Add the relay route to your Worker

Extend `src/index.ts` from the Install method 2 template with a dedicated relay route. The additions below fit inside your existing `fetch` handler — add `RELAY_PATH` to the path constants at the top, add `DAVA_API_KEY` to the `Env` interface, add the route check inside `fetch`, and add the `relayServerEvent` function at the bottom.

**Path constant** (add alongside `LISTEN_PATH` and `EVENTS_PATH`):

```ts theme={null}
const RELAY_PATH = "/_dava/relay-event";
```

**Updated `Env` interface** (add `DAVA_API_KEY`):

```ts theme={null}
export interface Env {
  DAVA_WORKER_URL: string;
  DAVA_SNIPPET_URL: string;
  /** Your Dáva API key — store as a Worker secret, not in vars. */
  DAVA_API_KEY: string;
}
```

**Route check** (add inside the `fetch` handler, before the pass-through fallback):

```ts theme={null}
if (url.pathname === RELAY_PATH && request.method === "POST") {
  return relayServerEvent(request, env);
}
```

**Relay handler function** (add at the bottom of `src/index.ts`):

```ts theme={null}
/**
 * Forward a server-side event payload to Dáva.
 *
 * Called explicitly by your backend or webhook handler — this route is never
 * invoked by browser code. The request body is passed through unchanged;
 * the Worker adds the Dáva API key.
 */
async function relayServerEvent(
  request: Request,
  env: Env,
): Promise<Response> {
  const upstream = await fetch("https://api-v2.davazmysel.com/v1/events", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${env.DAVA_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: request.body,
  });

  return new Response(upstream.body, {
    status: upstream.status,
    headers: { "Content-Type": "application/json" },
  });
}
```

**Store your API key as a Worker secret** (not in `vars`):

```bash theme={null}
wrangler secret put DAVA_API_KEY
# Paste your key when prompted: dava_sk_live_...
```

Then redeploy:

```bash theme={null}
wrangler deploy
```

### Call the relay from your backend

Your backend POSTs the event payload to your relay route. The Worker adds the API key and forwards it to Dáva. Example:

```js theme={null}
// Node.js — called from your backend after a purchase is confirmed:
const response = await fetch("https://collect.yourdomain.com/_dava/relay-event", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    subdomain: "yourdomain.com",
    event_type: "conversion",
    event_name: "purchase",
    anonymous_id: "anon-id-from-dava-cookie",
    dava_session_id: "01941b8c-3ae4-7e2a-9b5a-4e2a88c60d10",
    event_id: "order_ORD456",
    transaction_id: "ORD456",
    value: 99.00,
    currency: "AUD",
  }),
});

const data = await response.json();
// data.session_match: "matched" or "unmatched" — confirm during integration testing
```

<Note>
  At least one of `anonymous_id`, `contact_id`, or `hashed_email` is required in the payload — the request is rejected with `400` if all three are absent. See [Identity](/tracking/server-side-events#identity) for details.
</Note>

<Note>
  `subdomain` is required because the relay calls `api-v2.davazmysel.com` directly. Dáva cannot infer the domain from the relay request's `Host` header (which is `api-v2.davazmysel.com`, not your customer domain). See [Sending a single event](/tracking/server-side-events#sending-a-single-event) for details.
</Note>

`event_id` and `transaction_id` are dedup keys — see [Deduplication](/tracking/server-side-events#deduplication) for the full priority chain. Use `properties` for any additional domain-specific facts (e.g. `properties.sku`, `properties.plan`).

The relay route does not add authentication of its own — it is a backend-to-Worker call that stays server-side and never touches a browser. If you want to restrict which callers can use the relay, add a shared-secret header check inside `relayServerEvent` before forwarding.

For the full payload field table, deduplication chain, and error codes, see [Server-Side Events](/tracking/server-side-events).

## Hybrid setup (recommended)

To link the server event to the browser journey, include `dava_session_id` in every server event payload.

**The flow:**

1. The browser snippet loads on your page and creates a session.
2. Your **frontend JavaScript** reads the session ID: `window.dava.sessionId`
3. The frontend passes that value to your backend — via a hidden form field, a cookie, or a request body.
4. Your backend includes it as `dava_session_id` in the payload it sends to the relay route.

```js theme={null}
// In the browser — runs after the Dáva snippet has loaded:
const sessionId = window.dava ? window.dava.sessionId : null;

// Pass it to your backend, e.g. via a hidden form field:
const field = document.getElementById("dava_session_id_field");
if (field && sessionId) field.value = sessionId;
```

<Warning>
  The backend cannot read `window.dava.sessionId` directly — that is a browser object. The frontend must collect it and pass it to the server explicitly.
</Warning>

See [Joining the visitor's journey](/tracking/server-side-events#joining-the-visitor-s-journey) for more on how `dava_session_id` threads the server event onto the existing browser session.

## Next steps

* [Install the tracking snippet — Install method 2 →](/tracking/install-snippet#install-method-2-customer-operated-cloudflare-worker-proxy) — browser proxy setup: full Worker template, Custom Domain binding, CORS, and header forwarding
* [Server-Side Events reference →](/tracking/server-side-events) — full field table, dedup chain, batch endpoint, and error codes
