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

# Set Up baselayer.js

> Load baselayer.js on your pages so Baselayer can see which visits are agents, and forward its token to your server.

For your web team. baselayer.js is a small browser module that tells Baselayer what happens on your pages: page views, page exits, navigations and interactions. Baselayer uses it, with what your KYA SDK reports, to show you which visits are agents and what they did.

The snippet never receives a verdict about a visitor and never changes your page. Human visits are never stored. See [What baselayer.js Reports](https://docs.baselayer.com/docs/kya-acceptance-browser-records.md).

## What You Need

| Value | What it is | Where it comes from |
| - | - | - |
| Application ID | Your KYA application's ID, a UUID | Your Baselayer team |
| Browser key | A public key that lets the snippet send records for your application | see [Browser Keys](https://docs.baselayer.com/docs/kya-acceptance-configuring.md#browser-keys) |
| API origin | `https://api.baselayer.com` | The same host as the rest of the API |

Your Baselayer team also adds your site's origins to the application's allowed origins. A page on any other origin has its records refused. See [Allowed Origins](https://docs.baselayer.com/docs/kya-acceptance-configuring.md#allowed-origins).

A browser key is public: it ships in your page. Keep your API key on your server.

## Install

baselayer.js is one ES module. Pick how to load it:

| Option | When to use it | How |
| - | - | - |
| Module script | Modern sites | `<script type="module">` with `import` |
| Classic script | Older sites or CMSs | `import()` inside a plain `<script>` |
| Pinned release | You want one fixed version | Load `/v1/<version>/baselayer.js`. See [Pin a Release](#pin-a-release). |
| Staging build | Testing before production | Load from `js.staging.baselayer.com` with staging keys. See [Test Against Staging](#test-against-staging). |

Load it with `import` and call `init` once per page:

```html theme={null}
<script type="module">
  import { init } from "https://js.baselayer.com/v1/baselayer.js";

  init({
    applicationId: "<application id>",
    browserKey: "<browser key>",
    apiOrigin: "https://api.baselayer.com",
  });
</script>
```

A classic script cannot use `import` or a top-level `await`, so it loads the module with a dynamic `import()` and waits on the promise:

```html theme={null}
<script>
  import("https://js.baselayer.com/v1/baselayer.js")
    .then((baselayer) => {
      baselayer.init({
        applicationId: "<application id>",
        browserKey: "<browser key>",
        apiOrigin: "https://api.baselayer.com",
      });
    })
    .catch((error) => {
      // The page works without the snippet; log and carry on.
      console.warn("baselayer.js did not load", error);
    });
</script>
```

The examples below are module scripts, where a top-level `await` works. A module is loaded once per page, so importing it again returns the same running snippet.

### Options

| Option | Meaning |
| - | - |
| `applicationId` | Your application's ID |
| `browserKey` | Your browser key |
| `apiOrigin` | Baselayer's API origin: `https` and no path |
| `consent` | `false` sets no cookie, loads no detection script and sends nothing. Defaults to `true`. |
| `excludePaths` | Path patterns never recorded. None by default. |
| `routes` | Your route templates, such as `"/orders/{order_id}"`, tried in order, so a page is reported by its route rather than its raw path |

A malformed option throws a `TypeError`. Calling `init` again with valid options replaces the running session.

List any page you want left out in `excludePaths`. A pattern ending in `/*` matches the pages below a path but not the path itself, so `/your/page/*` covers `/your/page/details` and you list `/your/page` too.

### Content Security Policy

A page with a Content Security Policy must allow:

* `script-src https://js.baselayer.com` and `https://<application id>.collect.baselayer.com`;
* `connect-src https://<application id>.collect.baselayer.com https://api.baselayer.com`.

If the policy blocks the detection script, the snippet carries on without it and `token()` resolves to `null`.

baselayer.js leaves `window` alone. To let other scripts on your page call it, assign it yourself: `window.baselayer = baselayer`.

## Forward the Token to Your Server

`token()` resolves to a short-lived detection token. Send it to your own server in the `X-Baselayer-Token` header, where the [KYA SDK](https://docs.baselayer.com/docs/kya-sdk-quickstart.md) reads it:

```html theme={null}
<script type="module">
  import { token } from "https://js.baselayer.com/v1/baselayer.js";

  const detectionToken = await token();
  await fetch("/api/cart", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      ...(detectionToken ? { "X-Baselayer-Token": detectionToken } : {}),
    },
    body: JSON.stringify({ item_id: "sku-123" }),
  });
</script>
```

`token()` waits at most 2 seconds. It resolves to `null` on a timeout, when the detection script fails or is blocked, with `consent: false`, or before `init`. Treat `null` as "no token" and carry on: the request is still decided on what your server sees.

## Record a Page View Yourself

The snippet records page views, page exits and single-page-app route changes on its own. `track("page_view")` queues a page view when your app shows a new page without changing the URL. It returns `true` when the record was queued. Any other kind returns `false`.

```html theme={null}
<script type="module">
  import { track } from "https://js.baselayer.com/v1/baselayer.js";

  track("page_view");
</script>
```

## Stop the Snippet

`destroy()` sends the current page's exit, sends what is queued, stops the detection script and removes the snippet's history hooks. A single-page app calls it when it leaves the pages the snippet serves.

```html theme={null}
<script type="module">
  import { destroy } from "https://js.baselayer.com/v1/baselayer.js";

  destroy();
</script>
```

## Pin a Release

`/v1/baselayer.js` is always the current release, cached for 5 minutes. To pin one release, load `/v1/<version>/baselayer.js`, for example `https://js.baselayer.com/v1/0.1.2/baselayer.js`. Baselayer never republishes a pinned release, and it is cached for a year.

## Test Against Staging

Baselayer's staging environment serves its own build of the snippet. Use a staging application ID and a staging browser key, which your Baselayer team provides, and point both origins at staging:

```html theme={null}
<script type="module">
  import { init } from "https://js.staging.baselayer.com/v1/baselayer.js";

  init({
    applicationId: "<staging application id>",
    browserKey: "<staging browser key>",
    apiOrigin: "https://api.staging.baselayer.com",
  });
</script>
```

Use staging values throughout: each build talks only to its own environment. If your page has a Content Security Policy, allow `https://<staging application id>.collect.staging.live.baselayer.com`, `https://js.staging.baselayer.com` and `https://api.staging.baselayer.com` in place of the production hosts.

## Check It Works

Test browser visits on [staging](#test-against-staging), with your staging application ID and browser key. Open a page with the snippet, then list your visits with your staging API key. A visit appears about a minute after its first record:

```bash theme={null}
curl "https://api.staging.baselayer.com/acceptance/visits?limit=1" \
  -H "X-API-Key: $BASELAYER_STAGING_API_KEY"
```

Requests your KYA SDK reports show up in production too, at `https://api.baselayer.com` with your production API key.

Baselayer stores agent visits only, so on staging, test with an automated browser if your own visit does not appear. See [Reading Agent Activity](https://docs.baselayer.com/docs/kya-acceptance-reading-activity.md) for what the response holds.


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