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

# Web SDK

> Load revbridge.js in the browser to capture page views, sessions, and events, and identify users with automatic anonymous-to-known profile linking.

The Web SDK (`revbridge.js`) is the browser counterpart to the [Events API](/developer/ingesting-events). It captures page views, sessions, and custom events from the client, manages an anonymous identity, and links anonymous history to a known profile when a visitor logs in — all through a single `<script>` tag.

Unlike the server-side Events API, the Web SDK runs in untrusted browser code, so it authenticates with a **publishable key** (`rbpk_`) that can only ingest events. See [Key types](/developer/authentication#key-types).

## Before you start

<Steps>
  <Step title="Get a publishable key">
    In the dashboard, open **Settings → API Keys** and copy your **Publishable key** (it starts with `rbpk_`). This key is safe to embed in browser code: it can only send events, never read data or send messages.
  </Step>

  <Step title="Add the SDK to your site">
    Paste the install snippet (below) into the `<head>` of every page you want to track, before your own analytics code.
  </Step>

  <Step title="Verify events arrive">
    Open your site, then check **People** or your event stream in the dashboard. A `page_view` event should appear within a few seconds.
    <Check>Events tagged `channel: web` confirm the Web SDK is live.</Check>
  </Step>
</Steps>

## Install

Choose the script snippet for a no-build install, or the npm package for bundled apps. Both load the same SDK and expose the same `rbd` API.

<Accordion title="Script tag (recommended)">
  Add this to your page `<head>`. Replace `rbpk_YOUR_WRITE_KEY` with your publishable key from **Settings → API Keys**.

  ```html theme={null}
  <script async
    src="https://storage.googleapis.com/rbd-web-sdk-prod/sdk/latest/snippet.js"
    data-rbd-src="https://storage.googleapis.com/rbd-web-sdk-prod/sdk/latest/rbd.min.js"
    data-write-key="rbpk_YOUR_WRITE_KEY"></script>
  ```

  The loader creates a `window.rbd` stub immediately, so you can call `rbd.track(...)` right away — calls are queued and replay once the SDK finishes loading. `data-write-key` auto-initializes the SDK; omit it if you prefer to call `rbd.init()` yourself.
</Accordion>

<Accordion title="npm">
  ```bash theme={null}
  npm install @rbd/web-sdk
  ```

  ```javascript theme={null}
  import { createAnalytics } from '@rbd/web-sdk'

  export const rbd = createAnalytics()
  rbd.init('rbpk_YOUR_WRITE_KEY')
  ```
</Accordion>

<Warning>
  Only use a publishable `rbpk_` key in browser code. Never embed a secret `rbk_` / `rbak_` key — those carry full account permissions. See [Key types](/developer/authentication#key-types).
</Warning>

## Configure

Pass options as the second argument to `init(writeKey, options)`. Every option is optional.

| Option                    | Type                              | Default                                  | Description                                                                                                                 |
| ------------------------- | --------------------------------- | ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `endpoint`                | string                            | `https://api.revbridge.ai/ingest/events` | Ingest endpoint. Use `https://api-dev.revbridge.ai/ingest/events` for development.                                          |
| `autoPageview`            | `'history' \| 'initial' \| false` | `'history'`                              | Send a `page_view` on load and on SPA route changes (`history`), only on load (`initial`), or never (`false`).              |
| `consentMode`             | `'opt-out' \| 'opt-in'`           | `'opt-out'`                              | `opt-out` tracks until the user declines; use `opt-in` for GDPR / LGPD, where nothing is persisted or sent until `optIn()`. |
| `sessionTimeoutMs`        | number                            | `1800000`                                | Inactivity window before a new session starts (30 minutes).                                                                 |
| `flushAt`                 | number                            | `30`                                     | Flush after this many queued events.                                                                                        |
| `flushIntervalMs`         | number                            | `10000`                                  | Flush at least this often (10 seconds).                                                                                     |
| `ecommerce.trackPurchase` | boolean                           | `true`                                   | Set `false` on Shopify storefronts to avoid double-counting purchases already synced server-side.                           |
| `defaultProperties`       | object                            | `{}`                                     | Properties merged into every event.                                                                                         |
| `debug`                   | boolean                           | `false`                                  | Log SDK activity to the console.                                                                                            |

<Info>
  The SDK batches events and delivers them with `fetch` (using `keepalive` on page exit), retries on `429` / `5xx`, and coordinates across tabs so a batch is never sent twice.
</Info>

## Track events

`rbd.track(name, properties?)` captures a custom event; `rbd.page(properties?)` captures a `page_view` (also sent automatically when `autoPageview` is on). Every event automatically carries `channel: web`, the `session_id`, and page context (`page_url`, `page_path`, `page_title`, `referrer`, and UTM parameters).

```javascript theme={null}
rbd.track('newsletter_signup', { plan: 'pro', source: 'footer' })
rbd.page({ title: 'Pricing' })
```

## Identify users

Call `rbd.identify(userId?, traits?)` when a visitor logs in or gives you their identity. The anonymous ID stays stable, and every event from then on carries both the `anon_id` and the person identifiers you provide.

```javascript theme={null}
rbd.identify('usr_001', {
  email: 'jane@example.com',
  phone_number: '+5511999887766',
  first_name: 'Jane',
})
```

### Anonymous to known linking

The first time a visitor identifies on a device, RevBridge **adopts** the anonymous profile: all of that visitor's prior anonymous activity is re-pointed onto the now-known person, so you keep the full journey from first touch. This happens automatically for Web SDK traffic — you do not need to replay history or resend the `anon_id` alongside every identifier as you would server-side.

<Info>
  Adoption applies to Web SDK ingestion (events sent with a publishable key, which RevBridge tags as `source: web`). If the device already belongs to a different known person, for example a previous login on a shared computer, it is **not** adopted — this protects shared devices. See [Anonymous adoption](/developer/user-identification#anonymous-adoption-on-identify) for the full rules.
</Info>

<Warning>
  On shared devices, call `rbd.reset()` on logout. This rotates the anonymous ID and clears stored identifiers, so the next visitor starts a fresh anonymous profile.
</Warning>

## Track commerce

The `rbd.ecommerce.*` helpers emit typed events that fill RevBridge's native commerce columns (revenue, product IDs, order ID, and so on), so they power shopping segments and revenue attribution without custom mapping.

| Helper                              | Event              | Fills                                            |
| ----------------------------------- | ------------------ | ------------------------------------------------ |
| `ecommerce.productView(product)`    | `product_view`     | `product_ids`, `product_categories`              |
| `ecommerce.addToCart(product)`      | `add_to_cart`      | `product_ids`, `event_value` (price × quantity)  |
| `ecommerce.removeFromCart(product)` | `remove_from_cart` | `product_ids`                                    |
| `ecommerce.checkoutStarted(cart)`   | `checkout_started` | `product_ids`, `event_value`, `item_count`       |
| `ecommerce.purchase(order)`         | `purchase`         | `revenue`, `currency`, `order_id`, `product_ids` |
| `ecommerce.refund(refund)`          | `refund`           | `revenue` (normalized negative), `order_id`      |
| `ecommerce.search(query)`           | `search`           | `query`, `results_count`                         |
| `ecommerce.wishlistAdd(product)`    | `wishlist_add`     | `product_ids`                                    |
| `ecommerce.couponApplied(coupon)`   | `coupon_applied`   | `event_value` (discount)                         |

```javascript theme={null}
rbd.ecommerce.productView({ product_id: 'SKU-789', category: 'footwear', price: 129.9 })
rbd.ecommerce.addToCart({ product_id: 'SKU-789', quantity: 1, price: 129.9 })
rbd.ecommerce.purchase({
  order_id: 'ORD-12345',
  revenue: 129.9,
  currency: 'BRL',
  products: [{ product_id: 'SKU-789', category: 'footwear' }],
})
```

<Tip>
  On Shopify storefronts, set `ecommerce.trackPurchase: false` in `init()` — purchases already arrive through the server-side Shopify sync, and the SDK still captures the browsing funnel (`product_view → add_to_cart → checkout_started`). Pass the Shopify customer ID as the `userId` in `identify()` to unify web and store activity.
</Tip>

## Manage consent

The SDK tracks a page-level consent state (`pending` / `granted` / `denied`) that gates what it collects, plus per-channel marketing consent on the profile.

**Tracking consent.** In `opt-in` mode nothing is written or sent until you call `rbd.optIn()`; events are buffered in memory meanwhile. `rbd.optOut()` stops tracking and clears stored data. The SDK also honors Global Privacy Control by default.

**Channel consent.** `rbd.setConsent(update)` records marketing opt-ins on the profile for segmentation:

```javascript theme={null}
rbd.setConsent({ email: true, sms: false, whatsapp: true })
```

<Info>
  Only explicit `true` / `false` values are sent. An omitted channel stays "not informed", which is distinct from an opt-out. See the [consent flags](/developer/user-identification#consent-flags) model.
</Info>

## API reference

| Method                                | Description                                                                     |
| ------------------------------------- | ------------------------------------------------------------------------------- |
| `init(writeKey, options?)`            | Boot the SDK with your publishable key. Safe to call once.                      |
| `track(name, properties?)`            | Capture a custom event.                                                         |
| `page(properties?)`                   | Capture a `page_view`.                                                          |
| `identify(userId?, traits?)`          | Set person identifiers and trigger anonymous adoption.                          |
| `setUserProperties(props)`            | Set last-write-wins profile attributes.                                         |
| `setConsent(update)`                  | Record per-channel marketing consent.                                           |
| `register(props)` / `unregister(key)` | Add or remove super-properties sent on every event.                             |
| `reset()`                             | Log out: rotate the anonymous ID and clear identifiers (use on shared devices). |
| `optIn()` / `optOut()`                | Grant or deny tracking consent.                                                 |
| `flush()`                             | Deliver queued events immediately.                                              |
| `getAnonymousId()` / `getSessionId()` | Read the current anonymous and session IDs.                                     |
| `ready(cb?)`                          | Run a callback once the SDK is initialized.                                     |

## Next steps

<CardGroup cols={2}>
  <Card title="Key types" icon="key" href="/developer/authentication#key-types">
    Publishable and secret keys, and where each one belongs.
  </Card>

  <Card title="User Identification" icon="fingerprint" href="/developer/user-identification">
    Merge keys and anonymous adoption in depth.
  </Card>

  <Card title="Event Types" icon="list" href="/developer/event-types">
    Standard properties and the `web` channel.
  </Card>

  <Card title="Events API" icon="paper-plane" href="/developer/ingesting-events">
    The server-side counterpart for backend events.
  </Card>
</CardGroup>
