[relaybell docs › Browser SDK › Browser SDK reference](https://relaybell.com/docs/browser-sdk) · [All docs as Markdown](https://relaybell.com/docs.md) · [Index for AI assistants](https://relaybell.com/llms.txt)

# Browser SDK reference

> RelayBell.init() options (projectId, apiBase, swPath, swScope, externalId/userHash, tags, consent, autoCapture), window.relaybellInit and every SDK method.

## init() and options {#sdk-init}

```js
RelayBell.init({
  projectId: "YOUR_PROJECT_ID",   // required
  apiBase:   "https://relaybell.com", // optional: defaults to where relaybell-sdk.js was loaded from
  swPath:    "/sw.js",            // service-worker path on your domain
  externalId: "user_123",         // link this browser to your own user id
  userHash: "9f2c…",              // your server's signature of externalId (see Identity verification)
  tags: { plan: "pro" },          // custom attributes for segmentation
  requireConsent: false,          // true = wait for grantConsent() (CMP integration)
  policyVersion: "2026-01",       // recorded with consent for your audit trail
  autoCapture: false              // true = record pageviews + data-rb-event clicks (see below)
});
```

| Option | Description |
| --- | --- |
| `projectId` \* | Your website's Project ID (dashboard: **Install** page, or Settings → Developers). Without it `init()` throws `relaybell: projectId is required`. |
| `apiBase` | The relaybell address. Left out (or `null`), the origin `relaybell-sdk.js` was loaded from; `""` means the page's own origin. A trailing `/` is removed. |
| `swPath` | Where your copy of `sw.js` is, on your own domain. Default `"/sw.js"`. A full URL on another host (e.g. rewritten by a CDN plugin) is cut back to its path on the page's domain, since browsers only accept a same-origin service worker. |
| `swScope` | Optional scope for the service-worker registration, e.g. `"/folder/"` when `sw.js` isn't at the root. It is also how the SDK finds the registration again on later pages, so set it whenever `sw.js` lives in a folder. Left out, the browser's default (the folder `sw.js` is in). |
| `externalId`, `userHash` | Your own user id for this visitor, and your server's signature of it (see [Identity verification](https://relaybell.com/docs/identity)). Sent with the subscription and with every `track()` event. |
| `tags` | Custom attributes, `{ key: value }`; values are stored as text. Used by segments (`tag:KEY`) and [merge tags](https://relaybell.com/docs/sending#merge-tags) (`{KEY}`). Keys starting with `rb_` are reserved and ignored. |
| `requireConsent`, `policyVersion` | With `requireConsent: true` the SDK registers no service worker, shows no opt-in prompt and sends no auto-captured events until you call `grantConsent()` (remembered in the browser's `localStorage`; `revokeConsent()` forgets it and unsubscribes). On-site messages still show. `policyVersion` is stored with the opt-in. |
| `autoCapture` | `true` records `page_view` (including single-page-app route changes) and `[data-rb-event]` clicks; or pass `{ pageviews, clicks, scroll }` to choose (`scroll` sends `scroll_depth` at 25/50/75/100%; it is off unless you turn it on). Only for subscribed or identified visitors, and nothing at all while `requireConsent` is waiting for consent. See [Events](https://relaybell.com/docs/events-automation). |

`init()` returns a promise. Where push can't work it resolves `{ supported: false, needsInstall, reason }` (`needsInstall` is `true` on an iPhone/iPad outside a Home Screen web app); while waiting for consent, `{ supported: true, waitingForConsent: true }`.

**Call `init()` once per page.** A second call starts again from its own options. In React or Next.js, load the script with `next/script` (`strategy="afterInteractive"`) and call `RelayBell.init()` in its `onLoad` inside a client component (or set `window.relaybellInit`, below), and put `sw.js` in Next's `public/` folder so it is served at `/sw.js`. Step by step: [Next.js](https://relaybell.com/docs/install-nextjs), [React](https://relaybell.com/docs/install-react), [Vue and Nuxt](https://relaybell.com/docs/install-vue).

**Script loaded late?** If your own code may run before `relaybell-sdk.js` has loaded (a delayed or consent-gated script), set the options on the page instead — the SDK starts itself with them once it loads (on the page's `load` event, or straight away if that has passed), unless `init()` already ran:

```html
<script>window.relaybellInit = { projectId: "YOUR_PROJECT_ID", apiBase: "https://relaybell.com" };</script>
<script src="https://relaybell.com/relaybell-sdk.js" defer></script>
```

## Methods {#sdk-methods}

| Method | What it does |
| --- | --- |
| `init(opts)` | Registers the SW, shows the opt-in prompt, subscribes (see [options](https://relaybell.com/docs/browser-sdk#sdk-init)). |
| `subscribeNow()` | Triggers the browser permission prompt (call from a click). Resolves `{ supported, subscribed, permission?, reason? }` — `subscribed` is `true` only once relaybell has stored the subscription; `supported` is `false` where the browser can't do push (e.g. iOS Safari in a normal tab). Safe to call before `init()` has finished: it waits up to ~15 s, then resolves with `reason: "not_ready"`. |
| `isSubscribed()` | Resolves `true` if this browser has a push subscription for your site. Never prompts — use it to decide whether to show a “Notify me” button or to `track()` interest. |
| `identify(externalId, userHash)` | Links this browser to your own user id after the page has loaded (for example once the visitor signs in): an existing subscription is saved again with the id, and later `track()` events carry it. A browser with no id yet joins that user (a second device joins the same profile). A browser already linked to a different user moves to the new one only with a valid `userHash` (an account switch on a shared browser); without one it stays with the first user, so on a site without [identity verification](https://relaybell.com/docs/identity) call `unsubscribe()` when someone signs out of a shared browser. Calling it again with the same values does nothing; `identify(null)` stops sending an id from this page. `userHash` is optional unless you require [identity verification](https://relaybell.com/docs/identity). Safe to call before `init()`. |
| `unsubscribe()` | Removes this browser's push subscription and tells relaybell, which records the opt-out (webhook `subscriber.unsubscribed`). Resolves `{ unsubscribed: true }`. |
| `isSupported()` | `{ supported, browser, os, needsInstall, reason }` — feature detection, no network call. |
| `setTags({...})` | Merges the tags into the ones given to `init()` and, if this browser is subscribed, saves them (a key is overwritten, never removed). Resolves the merged tags. |
| `setTopics(["news"])` | Saves the topics this subscriber wants, by **slug**. It **replaces** the whole list (`[]` leaves every topic); unknown slugs are skipped. Works only for a browser with a push subscription: resolves `{ ok: true, applied }` (how many topics were saved), or `{ error: "subscriber_not_found" }`. |
| `showPreferences()` | Opens a preference-center modal of your topics, ticked with the subscriber's current choices; saving calls `setTopics()`. |
| `showInbox()` | Opens a modal of your 15 most recent broadcasts (never transactional, automation, journey or one-person sends). |
| `track(event, props)` | Sends a behavioral event (fires automations, journeys and attribution). From the browser, the person is the subscriber who owns **this browser's push subscription**: an event from a browser that isn't subscribed is stored but triggers nothing for anyone. Its `externalId` is kept only when verified, or when verification isn't required and no `userHash` is sent. |
| `trackConversion(value, props)` | Shorthand for `track("purchase", { value, ...props })`. |
| `grantConsent()` / `revokeConsent()` | For cookie-consent (CMP) gating when `requireConsent` is set: `grantConsent()` starts the SDK as `init()` would have; `revokeConsent()` forgets the consent and calls `unsubscribe()`. |

```js
// Behavioral tracking → powers cart abandonment, product alerts, attribution
RelayBell.track("cart.updated", { productId: "1234", product: "Blue Shoes", price: 49, url: location.href });
RelayBell.trackConversion(79.99, { orderId: "A123" });
```
