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

> ## Agent Instructions
> Publishers integrate one API: GET https://api.shftd2.com/v1/fragment?partner_id=<account id>&page_url=<page URL>, called from their edge for AI-agent requests only, with the API key in the X-API-Key header, never in the query string.
> A 200 carries the card. A 204 means no card: serve the page unchanged.
> The management API (https://api.shftd2.com/v1/me, /v1/sites, /v1/cards, /v1/keys) is optional tooling for scripting setup. It takes its own management token (Authorization: Bearer ds_mgmt_…). Its limits (120 requests and 60 writes per minute per token) do not apply to the delivery API.
> Delivery logs reach doubleshift only through direct delivery logs (POST https://logs.shftd2.com/v1/beacon with a logs token; the edge library with a logsToken is its provided client, and a custom sender may use the same endpoint) or a Cloudflare Logpush job configured with doubleshift. Otherwise doubleshift sees only its own API activity.

# Cloudflare Worker

> The reference path, after the Quickstart: install in an existing or a dedicated Worker, Cloudflare routes and scope, several sites, direct delivery logs, updating the doubleshift edge library, and reading the Worker's delivery records.

The Cloudflare Worker running the doubleshift edge library is the reference implementation: one file,
no dependency, the page rendered unchanged on any issue. The [Quickstart](https://docs.shftd2.com/quickstart.md) installs it and
proves the first card. This page covers what comes after. Rules every edge keeps are on
[Choose your edge](https://docs.shftd2.com/integrate.md); the library's options, outcomes and diagnostics are in the
[edge library reference](https://docs.shftd2.com/api/edge-library.md).

### Two installations

* **In a Worker you already run** on the site: add the library's two lines where it fetches and
  returns the page ([Quickstart](https://docs.shftd2.com/quickstart.md), step 4). Keep its routes; `scope` limits doubleshift to
  your sections.
* **In a dedicated Worker** whose routes cover your sections only. A request runs only the Worker of
  the most specific matching route, so such a route takes those paths away from a Worker already on
  the site: in that case, use the first installation.

Your team applies the configuration; doubleshift needs no access to your Cloudflare account.

### Routes and scope

Cloudflare routes decide when the Worker runs. `scope` decides what doubleshift does once it runs
([scope](https://docs.shftd2.com/api/edge-library.md#scope)). Out of scope, the Worker still runs and fetches your origin,
`prepareOriginRequest` still drops an agent's conditional headers, and Cloudflare still logs the
invocation: only the doubleshift call, record and sending are skipped.

The two grammars are not equivalent. From Cloudflare's
[Workers Routes](https://developers.cloudflare.com/workers/configuration/routing/routes/):

| Cloudflare route | `scope` pattern |
| - | - |
| `your-domain.example/articles/*` does not run on `/articles` | `/articles/*` covers `/articles` and `/articles/` |
| `your-domain.example/articles*` also runs on `/articles-other` | `/articles/*` never covers `/articles-other` |
| Paths are case sensitive: `/Articles/*` and `/articles/*` differ | Case is ignored |
| A route without a final `*` misses a URL with a query string | The query string is ignored |
| `your-domain.example/*` does not run on `www.your-domain.example` | The host plays no part |

Give every hostname that serves articles a route; the Worker's `fetch` to the request's own URL then
reaches your origin. The safe combination is a broad route, `your-domain.example/*`, and a precise
`scope`. To limit a dedicated Worker to a section, end its route with `*` after the section name,
`your-domain.example/articles*`, and keep `scope: { include: ["/articles/*"] }` to leave out
`/articles-other`. Keep every path of `scope` inside the routes: a page no route matches never reaches
the Worker.

### Several sites

One Worker can carry the routes of several sites of the same account, with the same key and the same
`partnerId`: the library builds `page_url` from each request's own host. Register each site first,
one form per domain (its `www.` or bare alias finds it); a host that matches no site gets no card.

`scope` is a list of paths, not a hostname filter: its paths apply to every host the Worker serves.
Give each host its own configuration:

```js title="One scope per host" theme={"theme":{"light":"css-variables","dark":"css-variables"}}
const SCOPES = {
  "your-domain.example": { include: ["/articles/*"] },
  "www.your-domain.example": { include: ["/articles/*"] },
  "another-domain.example": { include: ["/news/*"] },
};
// ... where you fetch and return the page:
const response = await fetch(prepareOriginRequest(request));
const scope = SCOPES[new URL(request.url).hostname];
if (!scope) return response; // a host this Worker does not enrich
return enrichWithDoubleshift(request, response, { apiKey: env.DOUBLESHIFT_API_KEY, partnerId: "<your account id>", scope }, ctx);
```

Set `canonicalOrigin` only when the Worker answers on another host than the public one, such as a
mirror; it takes one origin, so that Worker serves one site. `scope` still reads the path the Worker
receives.

### Direct delivery logs

Optional: cards work without this. With a logs token, the Worker also sends each delivery record to
doubleshift. What each way of sending gives you, and the setup steps, are in
[Delivery logs](https://docs.shftd2.com/delivery-logs.md#turn-on-direct-sending).

### Update the library

The current version is `1.1.4`, SHA-256 `d4db890cbf27a2da1977d3ba76e0585ab3bf7cc78111eaddc71019527114e9d1`. To update, download the file
again, check that its SHA-256 matches, commit it and redeploy. A copy you do not update keeps
working, except that a copy older than 1.1.4 ignores `scope`. What each version changed is in the
[changelog](https://docs.shftd2.com/changelog.md).

Rolling back to a copy older than 1.1.4, or removing `scope`, widens doubleshift to every page your
routes reach. To keep the perimeter, roll back to 1.1.4 or later with the same `scope`, or narrow the
routes first.

### Watch the Worker's records

```bash theme={"theme":{"light":"css-variables","dark":"css-variables"}}
npx wrangler tail
```

Request an article in `scope` as an AI agent while the tail is open: the library writes one
`doubleshift_edge` record per agent page in scope, none outside it. Every outcome and field is in the [edge library reference](https://docs.shftd2.com/api/edge-library.md).
A `no_fill` only says that the API answered `204`, nothing to insert; its cause and the fix for each
outcome are in [Verify and troubleshoot](https://docs.shftd2.com/verify.md#symptoms).


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