# The script

> Add Insights Orbit to a website with one script tag, its options, and serving it from your own domain.

Source: https://docs.bifrostorbit.com/insights/developers/the-script/

```html
<script defer data-site="SITE_KEY" src="https://api.bifrostorbit.com/insights/v1/script.js"></script>
```

The script is about 2 KB, loads with `defer` and uses no cookies. It reads the window's width and the browser's language, and the only thing it reads from storage is the visitor's own choice not to be counted (see below), which it writes only when the visitor asks. It counts page views, including websites that change pages without reloading (through `history.pushState` and the back button). It sends events in batches with `sendBeacon`: two seconds after the first one, at once after 20, straight after an outbound link, a download, a labelled click or a form, and when the page is hidden or closed. Browsers with Do Not Track or Global Privacy Control switched on, and automated browsers, send nothing.

## Options

| Attribute | What it does |
| --- | --- |
| `data-site` | The site's key, from **Install**. Required. |
| `data-api` | Where to send events, when you serve the endpoint from your own domain. |
| `data-disable` | Automatic events to switch off on this page, such as `outbound download form scroll 404`. Sites can also switch them off in their settings. Add `labels` to stop loading the site's labels. |
| `data-campaigns` | Count banners and popups: an element with `data-banner="LABEL"` or `data-popup="LABEL"` sends **Banner viewed** or **Popup viewed** once a page, and **Banner clicked** or **Popup clicked** when a link or button inside it is used, with the label. |
| `data-known-users` | Send the id given to `insights.identify(id)`. Dropped unless the site has known users switched on. |
| `data-consent` | `wait`: count nothing until your consent banner calls `insights.consent()` (see below). |

Each batch also carries the window's width and the browser's language. Insights Orbit keeps only the screen size group and the main language, such as `laptop` and `en`.

## Opting out

A visitor who opted out has `insights:off` in the website's `localStorage`, set to `off`, or `team` for your team's browsers. The script then sends nothing and loads nothing.

- `insights.optOut()` stops counting at once and keeps the choice. `insights.optOut(true)` marks the browser as your team's.
- `insights.optIn()` removes the choice; counting starts on the next page.
- Opening any page with `#insights-off`, `#insights-team` or `#insights-on` at the end of the address asks the visitor to confirm, then does the same. The opt-out page under **Site settings** links to your website this way.

Use these only when the visitor asks: they are the one thing the script keeps in the browser.

## Waiting for consent

If you ask visitors for consent before counting them, add `data-consent="wait"`:

```html
<script defer data-site="SITE_KEY" data-consent="wait" src="https://api.bifrostorbit.com/insights/v1/script.js"></script>
```

Until the page calls `insights.consent()`, the script sends nothing, loads nothing and reads nothing from the browser: not even Do Not Track, Global Privacy Control or the visitor's opt-out. Page views and events in the meantime wait in memory, up to 50, and are sent the moment consent is given, so the page where the visitor accepted still counts.

The script doesn't remember consent from one page to the next. Your consent banner keeps the visitor's choice and calls `insights.consent()` on every page once they have agreed:

```js
// after your banner reads or records the visitor's choice
window.insights?.consent()      // the visitor agreed
window.insights?.consent(false) // the visitor withdrew: stop and drop what is waiting
```

If your banner may run before the script has loaded, queue the call: `window.insights = window.insights || { q: [] }; window.insights.q.push(["consent"])`.

Do Not Track, Global Privacy Control and opt-outs still apply once consent is given.

## Labels

On Growth and up, the script reads the site's labels once per page, a small list cached for five minutes, and sends an event named after the label when a labelled button or link is clicked. See [Label buttons and links](https://docs.bifrostorbit.com/insights/everyone/labelled-events/). Give elements a `data-insights` name, such as `data-insights="demo-button"`, so labels keep finding them after a redesign.

Labelling mode opens your page with `?insights-label=` and a short-lived pass from Insights Orbit. The script then loads a separate file, `label.js`, for the labelling panel and counts nothing in that tab. The main script stays the same size for your visitors.

## Tags in the page

- `<meta name="insights" content="404">` on a not-found page sends a **404** event.
- `<meta name="insights-content" content="ENTRY_ID">` tags page views with a CMS Orbit entry.

## Serve it from your own domain

Some ad blockers block analytics on other domains. Serving the script and its endpoint from your own domain, through your own server, avoids that. Set `src` to your own address and `data-api` to your own collect address:

```html
<script defer data-site="SITE_KEY" data-api="/stats/collect" src="/stats/script.js"></script>
```

Your server must then pass each visitor's address on with the site's proxy token, or visits show your server's country, are undercounted and can be left out as data-centre traffic. See [Serve Insights Orbit from your own domain](https://docs.bifrostorbit.com/insights/developers/first-party-proxy/).

## Content Security Policy

If your website sends a `Content-Security-Policy` header, allow `https://api.bifrostorbit.com` in `script-src` and `connect-src`, or nothing extra when you [serve it from your own domain](https://docs.bifrostorbit.com/insights/developers/first-party-proxy/).
