---
title: "@togohq/sdk-browser"
description: "Every method and option of the browser SDK, with its defaults and limits."
canonical: "https://www.togohq.ai/docs/reference/sdk-browser"
applies_to: "@togohq/sdk-browser 1.x"
updated: "2026-11-05T00:00:00Z"
---

# @togohq/sdk-browser

Every method and option of the browser SDK, with its defaults and limits.

```bash
npm install @togohq/sdk-browser
```

Browser only, zero runtime dependencies, at most 15 KB minified. On a server `init()` returns a
client that does nothing and logs one warning; send server events with
[`@togohq/sdk-node`](/docs/reference/sdk-node).

**Nothing on the client throws** — not a bad key, not an oversized property, not a reserved name.
Each is a `console.error` prefixed `[togo]` that says what is wrong, and the call returns
normally, so analytics can never break the handler it sits in.

## `init(options)`

```ts
import { init } from '@togohq/sdk-browser';

const analytics = init({ writeKey: 'togo_pkt_…' });
```

Returns a client at once and never blocks; call it as early as you can. It checks the write key
in the background. A rejected key logs one error, and the client stops sending while every call
keeps returning normally; events already queued stay on the device and are retried on the next
page load.

## Options

| Option                   | Default                | What it does                                                                              |
| ------------------------ | ---------------------- | ----------------------------------------------------------------------------------------- |
| `writeKey`               | —                      | Required. `togo_pkt_…` (test) or `togo_pkl_…` (live)                                      |
| `endpoint`               | `https://in.togohq.ai` | Where events are sent: a proxy, or another ingress                                        |
| `defaultProperties`      | —                      | Properties added to every `track()` event, fixed for the client's life                    |
| `pageContext`            | `true`                 | `false` sends no URL, path, referrer or campaign; the time zone is still sent             |
| `sessionTimeoutSeconds`  | `1800` (30 min)        | The idle window that ends a session, in seconds. `<= 0` turns sessions off                |
| `sessionTimeoutMs`       | —                      | Deprecated: the same window in milliseconds. Still honoured; `sessionTimeoutSeconds` wins |
| `sessionId`              | —                      | Your own session id. It wins, and the SDK keeps no session state                          |
| `consent`                | `'not_required'`       | `'not_required'`, `'pending'`, `'granted'` or `'denied'`                                  |
| `consentBufferMaxEvents` | `100`                  | Events held in memory while consent is `pending`; the oldest are dropped                  |
| `onDenied`               | `'drop'`               | What happens to an event under `denied`. `'drop'` is the only value                       |
| `deviceId`               | —                      | Your own device id, for a host that owns identity                                         |
| `cookieDomain`           | probed                 | The cookie's domain. By default the widest one the browser accepts                        |
| `cookieSameSite`         | `'Lax'`                | The cookie's `SameSite` attribute                                                         |

On `defaultProperties`: an event's own value for the same key wins, and the SDK logs one error for
the collision. They are kept through `reset()` and never added to `identify()` or
`setPersonProperties()`.

## `track(eventName, properties?)`

```ts
analytics.track('checkout_started', { plan: 'pro', seats: 5 });
```

Queues one event. The name is any string that does not start with `$`; property values are
strings, numbers, booleans or `null`. Every event also carries the page's URL and path (read at
each call), the referrer and the `utm_*` campaign values (read once, at `init()`), and the
visitor's time zone. The query string and `#fragment` are never sent, and an email address in a
path, referrer or campaign value is replaced with `REDACTED_EMAIL`.

Returns the event's `eventId`, or `undefined` when nothing will be sent — a refused name, consent
`denied`, or a client that does nothing (a malformed write key, a key already rejected, or on a
server). The key is checked in the background, so a call made before a rejection comes back still
returns an id. Under `pending` consent the event is held with that id and sent under it once
consent is granted, or discarded if it is denied. An id means the event was queued, not that it
arrived; the edge can still reject it. Your agent passes
these ids to [`verify_tracking_by_event_ids`](/docs/reference/mcp-tools#verify_tracking_by_event_ids)
to check exactly what a test run sent ([Check that events arrive](/docs/verify)).

## `identify(userId)`

Links this browser to your user id. Call it after sign-in; repeating the same id does nothing, and
a different id resets first. Returns the `eventId` of the identify call it sent, or `undefined` when
it sends nothing — the same id again, consent `denied`, or a client that does nothing.
[Identify people when they sign in](/docs/guides/identify).

## `setPersonProperties(ops)`

```ts
analytics.setPersonProperties({
  set: { plan: 'pro' },
  setOnce: { first_plan: 'free' },
  unset: ['trial'],
});
```

Updates the person's profile; only defined keys, plus `email` and `name`, are kept. Works before
and after `identify()`. Returns the profile write's `eventId`, or `undefined` when it sends
nothing — an empty call, consent `denied`, or a client that does nothing.
[Set person properties](/docs/guides/person-properties).

## `reset()`

Call on sign-out. Rotates the anonymous id and the session and keeps the device id, so the next
person on this browser is not credited to the last.

## `flush()`

`await analytics.flush()` sends everything queued now. Events otherwise go in batches — at 50
queued, or 5 seconds after the first, or when the page is hidden — and the batching is not
configurable. Call `flush()` after an event that must leave before the page does, such as a click
that navigates to another site:

```ts
analytics.track('app_store_clicked', { store: 'ios' });
await analytics.flush();
window.location.href = appStoreUrl;
```

## `getAnonymousId()`, `getDeviceId()`, `getSessionId()`

Read the current ids, for example to [forward them to your server](/docs/guides/server-events).
Each returns `undefined` until the first event the visitor's consent allows, and never creates an
id as a side effect. The person behind those ids is worked out by Togo once the events
arrive, so your code works with `userId` and these ids ([People and identity](/docs/concepts/people)).

## `setConsent(state)` and `getConsent()`

Change or read the consent state. `'denied'` deletes every key the SDK stored on the device.
[Connect a consent banner](/docs/guides/consent).

## Delivery and retries

A network error or a `5xx` re-queues the batch, and each event keeps the same event id across
attempts, so a retry is recognised as the same event. A `4xx` is not retried. Events queued while
offline are sent later and keep the time they happened.

## Limits

| What                  | Limit                                                  |
| --------------------- | ------------------------------------------------------ |
| Property value length | 1,024 characters                                       |
| Properties per event  | 256                                                    |
| Batch size            | 1 MB, 500 events — the SDK batches below these for you |

An event over a limit is logged at the call site, sent, and refused by Togo — never truncated.
See [Event diagnostics](/docs/reference/event-diagnostics).
