# Connect Insights Orbit with the CMS Orbit SDK

> Add the script, tag page views with CMS Orbit entries, track campaigns and serve it from your own domain, in a Next.js website or with the PHP, Swift and Kotlin SDKs.

Source: https://docs.bifrostorbit.com/insights/developers/cms-orbit-sdk/

A website built with `@bifrost-orbit-cms/sdk` sets up Insights Orbit in three steps. Everything is opt-in: without a site key, nothing is added to the page.

## 1. Add the script

Once the space is connected under **Settings**, **Insights Orbit** in CMS Orbit, every delivered page carries the site key in `page.insights.site` and its own id in `page.id`. Render `CmsInsights` once, in the root layout:

```tsx
import { CmsInsights } from "@bifrost-orbit-cms/sdk/react";

<CmsInsights site={process.env.NEXT_PUBLIC_INSIGHTS_SITE} src="/stats/script.js" api="/stats/collect" />
```

`site` is the key from **Install**. Pass `page={page}` instead on a page to take the key from the delivery. Without a key it renders nothing. Leave out `src` and `api` to load from Insights Orbit's own address.

| Prop | What it does |
| --- | --- |
| `site` | The site key. Wins over the key in `page`. |
| `page` | A delivered page: its site key and its id |
| `contentId` | The entry id for `<meta name="insights-content">`, when you have no `page` |
| `src` | Where the script loads from. `https://api.bifrostorbit.com/insights/v1/script.js` by default. |
| `api` | Where events go, as `data-api`. Set it whenever you set `src`. |
| `disable` | Automatic events to switch off, such as `['scroll', 'form']`, as `data-disable` |
| `campaigns` | Count banners and popups (step 3). On by default. |
| `waitForConsent` | Count nothing until your consent banner calls `insights.consent()`, as `data-consent="wait"`. Off by default. |

## 2. Tag page views with the entry

In each page's `generateMetadata`, add the entry's id, so its numbers follow it when its address changes:

```ts
import { insightsMetadata } from "@bifrost-orbit-cms/sdk/next";

return { ...toMetadata(page), ...insightsMetadata(page) };
```

This adds `<meta name="insights-content" content="ENTRY_ID">`. Without it, CMS Orbit falls back to the page's address.

## 3. Campaigns

`CmsInsights` adds `data-campaigns` to the script, which counts banners and popups by their tracking label: an element with `data-banner="LABEL"` or `data-popup="LABEL"` sends **Banner viewed** or **Popup viewed** once when it appears, and **Banner clicked** or **Popup clicked** when a link or button inside it is used. Put the attribute on the element that shows the campaign:

```tsx
<div data-banner={banner.trackingLabel ?? undefined}>…</div>
```

Set `campaigns={false}` to switch this off.

## Serve it from your own domain

To get past ad blockers and keep each visitor's address, add a proxy route and the site's proxy token:

```ts
// app/stats/[...path]/route.ts
import { createInsightsProxy } from "@bifrost-orbit-cms/sdk/next";

export const { GET, POST } = createInsightsProxy();
```

Set `INSIGHTS_PROXY_TOKEN` on the server, from **Site settings**, **First-party proxy**, and load the script with `src="/stats/script.js"` and `api="/stats/collect"` as in step 1. With `trailingSlash: true` in `next.config.ts`, use `api="/stats/collect/"`. The whole setup, and what happens without the token, is in [Serve Insights Orbit from your own domain](https://docs.bifrostorbit.com/insights/developers/first-party-proxy/).

`insightsRewrites()` serves the same addresses through `rewrites` in `next.config.ts`, but rewrites can't pass on the visitor's address. Prefer the route.

## PHP, Swift and Kotlin

The CMS Orbit SDKs for PHP (`bifrost-orbit/cms-sdk`), Swift and Kotlin write the same tags for server-rendered HTML: the script with the page's site key, and `<meta name="insights-content">` with its entry id. Without a site key they write nothing, so the call can stay in a layout.

```php
use BifrostOrbit\Cms\Insights;

echo Insights::tags($page, ['src' => '/stats/script.js', 'api' => '/stats/collect']);
```

```swift
let head = CMSInsights.tags(page: page, src: "/stats/script.js", api: "/stats/collect")
```

```kotlin
val head = CmsInsights.tags(page, src = "/stats/script.js", api = "/stats/collect")
```

Each takes `site`, `contentId`, `src`, `api`, `disable`, `campaigns` and `waitForConsent`, like `CmsInsights`. They don't include a proxy: pass `/stats/` on to Insights Orbit in your own server as described in [Serve Insights Orbit from your own domain](https://docs.bifrostorbit.com/insights/developers/first-party-proxy/), or leave out `src` and `api`.
