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.
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)
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?)
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
to check exactly what a test run sent (Check that events arrive).
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.
setPersonProperties(ops)
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.
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:
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.
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).
setConsent(state) and getConsent()
Change or read the consent state. 'denied' deletes every key the SDK stored on the device.
Connect a consent banner.
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.