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

# Fastly

> Serve your RSL license and enforce CAP on Fastly — as a single Compute service, or by chaining an existing VCL service to a Compute validator.

Supertab Connect serves your RSL license at `/license.xml` and enforces the Crawler Authentication Protocol (CAP) on crawler requests. The SDK runs in a Fastly **Compute** service, so how you deploy depends on your current Fastly setup.

| Your setup                                 | Approach                                                        | What you do                                                               |
| :----------------------------------------- | :-------------------------------------------------------------- | :------------------------------------------------------------------------ |
| **Compute** (greenfield or full migration) | [Compute service](#compute-service)                             | One SDK handler serves `/license.xml` and enforces CAP.                   |
| **Existing VCL service**                   | [VCL and Compute (chaining)](#vcl-and-compute-chaining)         | Keep your VCL service and chain licensed requests to a Compute validator. |
| **VCL only, no Compute**                   | [Bot Events on Fastly VCL](/reference/fastly/bot-events-on-vcl) | Analytics only — see which crawlers hit your site. No CAP enforcement.    |

<Note>
  CAP enforcement always requires a Compute service — the SDK is Wasm and does not run in VCL. A pure-VCL service can still *serve* the RSL license via a URL rewrite (see [Serving the license on VCL](#serving-the-license-on-vcl)), but it cannot enforce CAP on its own.
</Note>

***

## Compute service

Everything runs in one Compute service: the SDK serves `/license.xml` (via `enableRSL`) and enforces CAP on all other traffic.

Install the SDK:

```bash theme={null}
npm install @getsupertab/supertab-connect-sdk
```

### Backends

The Compute service needs two backends:

* **`stc-backend`** → `api-connect.supertab.co:443` (TLS enabled). The SDK routes its own calls to Supertab Connect — JWKS, token verification, events, and the RSL license fetch — through a backend that must be named exactly `stc-backend`, or those requests fail with a `502`.

  ```
  Name:                 stc-backend
  Address:              api-connect.supertab.co
  Port:                 443
  TLS:                  enabled
  SNI hostname:         api-connect.supertab.co
  Certificate hostname: api-connect.supertab.co
  Override host:        api-connect.supertab.co
  ```

* **Your content origin** (e.g. `content_origin`) → your site. Allowed traffic is forwarded here; pass its name as the third argument to the handler.

### Secret Store

Create a Fastly Secret Store named `supertab_config`, containing `MERCHANT_API_KEY` (from your Supertab Connect dashboard), and link it to the Compute service.

### Handler

```javascript theme={null}
/// <reference types="@fastly/js-compute" />
import { SupertabConnect, EnforcementMode } from "@getsupertab/supertab-connect-sdk";
import { SecretStore } from "fastly:secret-store";

const secrets = new SecretStore("supertab_config");
const merchantApiKey = (await secrets.get("MERCHANT_API_KEY")).plaintext();

addEventListener("fetch", (event) => {
  event.respondWith(
    SupertabConnect.fastlyHandleRequests(
      event,
      merchantApiKey,
      "content_origin",
      {
        enableRSL: true,                      // serve /license.xml from the SDK
        merchantSystemUrn: "YOUR_WEBSITE_URN",
        enforcement: EnforcementMode.OBSERVE, // see Enforcement modes
        analyticsEnabled: true,               // see Bot-event logging
        logEndpoint: "bot_events",
      }
    )
  );
});
```

Pass the `event` (the Fastly `FetchEvent`), not `event.request` — the SDK reads the request, client signals, and `waitUntil` from it. With `enableRSL: true`, `/license.xml` is handled internally; every other request goes through CAP.

### Enforcement modes

Set `enforcement` in the options:

| Mode                | Behavior                                               |
| :------------------ | :----------------------------------------------------- |
| `DISABLED`          | Skip verification entirely — all requests pass through |
| `OBSERVE` (default) | Verify tokens and record outcomes, but never block     |
| `ENFORCE`           | Block requests with missing or invalid license tokens  |

Start in `OBSERVE` while you validate the integration, then move to `ENFORCE` when you're ready to block.

### Bot detection

By default the SDK identifies known crawlers by their user agent. Pass a `botDetector` function to extend or override this logic.

```javascript theme={null}
const isBot = (request) => {
  const ua = request.headers.get("User-Agent") || "";
  return ua.includes("MyCustomBot") || ua.includes("Scraper");
};

SupertabConnect.fastlyHandleRequests(event, merchantApiKey, "content_origin", {
  botDetector: isBot,
  enforcement: EnforcementMode.ENFORCE,
});
```

***

## VCL and Compute (chaining)

Use this when you already run a VCL service and only want licensed requests to detour through Compute. The VCL service detects the `Authorization: License` header and chains those requests to a Compute validator, which runs the SDK and forwards to your normal origin. Everything else stays on your existing CDN path.

<Note>
  Because only licensed requests are chained, `/license.xml` never reaches Compute — serve it from the VCL layer (see [Serving the license on VCL](#serving-the-license-on-vcl)).
</Note>

### Compute validator service

The validator runs the same SDK handler as a standalone Compute service. `enableRSL` is omitted here (the license is served on VCL); it accepts the same `enforcement`, `botDetector`, and analytics options shown in the [Compute service](#compute-service) section.

```javascript theme={null}
/// <reference types="@fastly/js-compute" />
import { SupertabConnect } from "@getsupertab/supertab-connect-sdk";
import { SecretStore } from "fastly:secret-store";

addEventListener("fetch", (event) => {
  event.respondWith((async () => {
    const secrets = new SecretStore("supertab_config");
    const merchantApiKey = (await secrets.get("MERCHANT_API_KEY")).plaintext();

    return SupertabConnect.fastlyHandleRequests(
      event,
      merchantApiKey,
      "content_origin"
    );
  })());
});
```

It requires:

* A Secret Store called `supertab_config` containing `MERCHANT_API_KEY`, linked to the Compute service.
* A backend for your real origin, passed as the third argument (`content_origin`).
* A backend named exactly `stc-backend` → `api-connect.supertab.co:443` (same host/TLS settings as in [Backends](#backends) above) for the SDK's own Supertab calls.

### VCL snippets — `vcl_recv` and `vcl_pass`

On your VCL service, add a `recv` snippet to reroute licensed requests to the Compute validator:

```vcl theme={null}
if (req.http.Authorization ~ "^License ") {
  set req.backend = F_supertab_compute_validator;
  return (pass);
}
```

`F_supertab_compute_validator` refers to a host/backend named `supertab-compute-validator` that you define in your VCL service, pointing at the Compute service's autogenerated domain. Configure it with TLS enabled and the edgecompute domain set as the SNI, certificate, and override host — otherwise the CDN → Compute hop fails:

```
Name:                 supertab-compute-validator
Address:              <your-compute-service>.edgecompute.app
Port:                 443
TLS:                  enabled
SNI hostname:         <your-compute-service>.edgecompute.app
Certificate hostname: <your-compute-service>.edgecompute.app
Override host:        <your-compute-service>.edgecompute.app
```

Then add a `pass` snippet so the original request URL reaches Compute:

```vcl theme={null}
declare local var.scheme STRING;

if (req.is_ssl) {
  set var.scheme = "https";
} else {
  set var.scheme = "http";
}

set bereq.http.X-Original-Request-Url = var.scheme "://" req.http.host req.url;
```

`X-Original-Request-Url` is used to verify the license token's `aud` claim. Without it, CAP fails with an `insufficient_scope` error because the SDK can't confirm all properties required by the RSL spec.

**Note:** keep the rest of your VCL flow intact so non-licensed traffic never leaves the CDN path.

If the SDK rejects a token with an audience or scope error, confirm the `pass` snippet that sets `X-Original-Request-Url` runs before the request reaches Compute.

***

## Serving the license on VCL

On a VCL service, `/license.xml` is served by proxying to the Supertab Connect origin and rewriting the short path to the full URN path — the SDK is not involved. (Compute services do this via `enableRSL` instead.)

### Backend

Add a host pointing to the Supertab Connect origin:

```
Name:                 supertab-connect-backend
Address:              api-connect.supertab.co
Port:                 443
TLS:                  enabled
SNI hostname:         api-connect.supertab.co
Certificate hostname: api-connect.supertab.co
Override host:        api-connect.supertab.co
```

### Condition

Attach a request condition to `supertab-connect-backend`:

```vcl theme={null}
req.url ~ "^/merchants/systems/YOUR_WEBSITE_URN/license\.xml(\?|$)"
```

### VCL Snippet

Add a `recv` snippet at priority 100:

```vcl theme={null}
if (req.url.path == "/license.xml") {
  set req.url = "/merchants/systems/YOUR_WEBSITE_URN/license.xml";
}
```

This rewrites the short URL before the condition runs, so the backend condition matches and the request is routed to `api-connect.supertab.co`. Activate the new version once the backend, condition, and snippet are in place.

***

## Bot-Event Logging

<Note>
  This section covers Compute services, where the SDK emits the events. If you run **VCL only** and don't want a Compute service, a VCL snippet can build the same events instead — see [Bot Events on Fastly VCL](/reference/fastly/bot-events-on-vcl).
</Note>

When the SDK runs in a Compute service, it can emit one analytics event per request to a Fastly logging endpoint named `bot_events`. Supertab loads those events into your bot-traffic analytics. This is the recommended path: every request flows through Compute, so a Fastly log-streaming endpoint handles that volume without adding an outbound request per hit.

<Note>
  Omitting `logEndpoint` falls back to Supertab Connect's HTTP relay instead of S3 log streaming. That's fine for low volume, but on Fastly Compute the relay needs `stc-backend` to reach Supertab and adds an outbound request per hit — prefer the `bot_events` endpoint below for production traffic.
</Note>

### Enable analytics in the SDK

Pass the analytics options to `fastlyHandleRequests`:

```javascript theme={null}
SupertabConnect.fastlyHandleRequests(
  event,
  merchantApiKey,
  "content_origin",
  {
    analyticsEnabled: true,
    logEndpoint: "bot_events",
    merchantSystemUrn: "YOUR_WEBSITE_URN",
  }
);
```

You can find your Merchant System URN on the **View Website Details** page of the Merchant Portal, in the same place as your API keys. If you prefer not to hardcode it, store it in your Secret Store alongside `MERCHANT_API_KEY` (e.g. as `MERCHANT_SYSTEM_URN`) and read it the same way.

### Create the S3 logging endpoint

The SDK writes events to a log streaming endpoint that must exist on your Compute service. In the Fastly dashboard, go to **Resources** → **Log streaming** → **Create endpoint** → **Amazon S3** and set:

| Setting           | Value                                                   |
| :---------------- | :------------------------------------------------------ |
| **Name**          | `bot_events`                                            |
| **Bucket name**   | Sent to you by Supertab                                 |
| **Path**          | `bot-events/`                                           |
| **Domain**        | `s3.eu-central-1.amazonaws.com` (region `eu-central-1`) |
| **Access method** | `IAM role`                                              |
| **IAM role ARN**  | Sent to you by Supertab                                 |
| **Log format**    | **Blank**                                               |
| **Compression**   | none                                                    |
| **Period**        | `60` seconds                                            |

A few of these are easy to get wrong:

* The endpoint **name must be exactly `bot_events`**, matching the `logEndpoint` SDK option — otherwise the logs are silently dropped.
* The **log format must be Blank**. The SDK already writes one JSON object per line; the default (**Classic**) prepends a syslog header and corrupts every event.
* **Leave gzip compression off**. Supertab reads the `*.log` objects as plain newline-delimited JSON.
* The **regional domain** `s3.eu-central-1.amazonaws.com` is required because the bucket is not in `us-east-1`.

Save the endpoint and activate the service version to start shipping events.

***

## Purge cached license

When you publish a new license version, Fastly keeps serving the cached `license.xml` until it's purged. Purge that single URL to force a refresh:

* **VCL service:** dashboard → your service → **Purge** → enter `https://yourdomain.com/license.xml` → **Purge**.
* **Compute service:** dashboard → **Compute** → **Services** → your service → **Purge** → enter `https://yourdomain.com/license.xml` → **Purge**.

Confirm the update at `https://yourdomain.com/license.xml`.

***

## Manual verification

For fine-grained control on either Compute deployment, use `verifyAndRecord()` on a `SupertabConnect` instance instead of `fastlyHandleRequests`.

```javascript theme={null}
const supertab = new SupertabConnect({ apiKey: merchantApiKey });

const result = await supertab.verifyAndRecord({
  token: licenseToken,
  resourceUrl: request.url,
  userAgent: request.headers.get("User-Agent"),
});

if (result.valid) {
  // forward to origin
}
```

***

## Related Docs

<CardGroup cols={2}>
  <Card title="Deploy in Your CDN" icon="shield" href="/guides/deploy-cdn">
    CDN-agnostic guide covering RSL serving, CAP enforcement, and robots.txt.
  </Card>

  <Card title="Other CDNs" icon="server" href="/reference/others">
    Generic CDN patterns for platforms not listed above.
  </Card>
</CardGroup>
