Skip to Content
How-to guideSourcesAvailable

JavaScript SDK

Complete reference for the Vendo web tracking JavaScript SDK — all methods, configuration options, and advanced features.

Last reviewed July 25, 2026

The Vendo JavaScript SDK captures events from your website and sends them to your ingestion API. It handles batching, retries, session management, attribution tracking, and identity resolution automatically.

Installation

See Quickstart for the full snippet. After pasting it into your <head>, all methods are available on window.vendo.

Self-Hosted Snippet

If you prefer serving the SDK from your own domain, use the self-hosted async snippet. See Self-Hosting for setup instructions.

Direct Script

<script src="https://cdn.vendodata.com/sdk/v1/vendo.js"></script> <script> const tracker = VendoTracker.init('YOUR_WRITE_KEY', { endpoint: 'https://YOUR_TRACKING_ENDPOINT/collect', }); tracker.page(); // page views are explicit — init() never sends one </script>

Initialization

vendo('init', writeKey, options)

Initialize the SDK using the CDN snippet API. This is the recommended approach.

vendo('init', 'YOUR_WRITE_KEY', { host: 'https://YOUR_TRACKING_ENDPOINT', }); vendo('page'); // page views are explicit — init never sends one

The CDN snippet buffers all calls as arguments. When the SDK loads, autoboot() scans the queue for the init call, initializes the tracker, and replays any remaining buffered calls.

Explicit page views (0.2.0)init no longer sends a Page Viewed event automatically. Call vendo('page') (function-queue form) or vendo.page() (async/npm form) after init, and again on every client-side route change. The old trackPageViews / pageView options are deprecated no-ops.

The vendo('init', ...) call accepts these options:

OptionTypeDefaultDescription
hoststring""Base URL of your tracking endpoint. The SDK derives the collect endpoint as {host}/collect.
debugbooleanfalseLog event payloads, queue changes, batch sends, sendBeacon fallback, and flush results to the browser console.
trackPageViewsbooleanDeprecated no-op since 0.2.0. Has no effect; call vendo('page') explicitly. Alias for pageView.
pageViewbooleanDeprecated no-op since 0.2.0. Has no effect; call vendo('page') explicitly.
consentobject{}Consent configuration: groups, waitForConsent, requiredGroups. See Consent Management.
flushIntervalMsnumber5000How often (ms) to flush the event queue.
batchSizenumber20Max events per batch request.
maxQueueSizenumber200Max events to buffer locally before dropping oldest.
sessionTimeoutMsnumber1800000Session timeout in ms (default: 30 minutes). A new session starts after this period of inactivity.
exitIntentbooleantrueFlush pending events when the page is hidden or unloaded; does not create an exit-intent event.
storageKeystring"vendo"localStorage key prefix for SDK data.
requestTimeoutMsnumber30000Timeout for each HTTP request to /collect.

VendoTracker.init(writeKey, config)

Initialize the SDK using the direct API. Returns a tracker instance.

const tracker = VendoTracker.init('YOUR_WRITE_KEY', { endpoint: 'https://track.yourdomain.com/collect', debug: true, }); tracker.page(); // page views are explicit — init() never sends one
OptionTypeDefaultDescription
endpointstring"/collect"Full URL of the collect endpoint.

All other options are the same as vendo('init', ...).


Tracking Methods

track(event, properties, context)

Track a custom event.

vendo.track('Product Viewed', { sku: 'SKU-1', price: 29.99, category: 'shoes', currency: 'USD', }); vendo.track('Product Viewed', { sku: 'SKU-1' }, { page: { category: 'sale' } });
ParameterTypeRequiredDescription
eventstringYesName of the event (e.g., "Product Viewed", "Signup Completed").
propertiesobjectNoKey-value pairs of event properties.
contextobjectNoAdditional context to merge into the SDK’s automatic context envelope.

Events are queued locally and sent in the next batch flush. The SDK automatically stamps every event with these top-level fields — they sit alongside event and properties on the event object, not inside properties:

FieldDescription
messageIdUnique ID (UUID v4)
typeEvent type (track, page, …)
timestampISO 8601 timestamp
anonymousIdPersistent anonymous ID
userIdSet after identify() is called
sessionIdCurrent session ID

The write key is not a per-event field. It is sent once per batch — in the X-Write-Key header and as a batch-level writeKey on the request wrapper — not repeated on each event.

Everything else the SDK captures automatically (browser, OS, device, locale, page, screen, library, session, campaign/UTMs, click IDs, and consent) lives in the structured context object described below. UTM parameters and click IDs are populated when present (see Attribution).

Context Envelope

Every event also includes a structured context object. This is the preferred shape for shared metadata because it keeps event properties focused on the business event.

{ "context": { "source": "web", "library": { "name": "vendo-web-tracking", "version": "0.2.0" }, "session": { "id": "session-id" }, "page": { "url": "https://example.com/products/sku-1?utm_source=google", "path": "/products/sku-1", "title": "Product Page", "referrer": "https://google.com/" }, "campaign": { "utm_source": "google", "utm_medium": "cpc" }, "clickId": { "gclid": "..." }, "screen": { "width": 1440, "height": 900 }, "browser": "Chrome", "os": "Mac OS X", "device": "Desktop", "language": "en-US", "consent": { "analytics": true, "marketing": false } } }

The ingestion API normalizes this context into typed warehouse columns and still falls back to the legacy flat properties for backwards compatibility.

page(name, properties, context)

Track a page view. Automatically captures page URL, path, title, and referrer.

// Basic page view vendo.page(); // Named page view with custom properties vendo.page('Pricing', { variant: 'annual' });

Page views are always explicit: init never sends one automatically (since 0.2.0), so call page() once after init and on every client-side route change.

ParameterTypeRequiredDescription
namestringNoPage name. Defaults to "Page Viewed".
propertiesobjectNoAdditional page properties.
contextobjectNoAdditional context to merge into the automatic context envelope.

Page events are written to the events table with type: "page".

identify(userId, traits, context)

Associate the current visitor with a known user ID and set user traits.

vendo.identify('user-123', { email: 'jane@example.com', name: 'Jane Smith', plan: 'pro', created_at: '2024-01-15T00:00:00Z', });
ParameterTypeRequiredDescription
userIdstringYesUnique user identifier from your system.
traitsobjectNoUser properties (email, name, plan, etc.).
contextobjectNoAdditional context to attach to the identify call.

After calling identify():

  • The userId is persisted in localStorage and attached to all subsequent events
  • An identify event is sent to the users table in BigQuery
  • The anonymous ID is preserved, allowing you to link pre-login and post-login activity

Call identify() after login, signup, or whenever user info changes.

group(groupId, traits, context)

Associate the current user with a group (company, organization, account).

vendo.group('org-42', { name: 'Acme Inc', plan: 'Enterprise', employee_count: 150, });
ParameterTypeRequiredDescription
groupIdstringYesUnique group identifier.
traitsobjectNoGroup properties.
contextobjectNoAdditional context to attach to the group call.

Group events are written to the groups table in BigQuery.

alias(userId, previousId, context)

Merge two user identities. Use this when a user creates an account and you want to link their anonymous activity to the new account.

vendo.alias('user-123', 'anon-456');
ParameterTypeRequiredDescription
userIdstringYesThe new canonical user ID.
previousIdstringYesThe previous anonymous or temporary ID.
contextobjectNoAdditional context to attach to the alias call.

Alias events are written to the aliases table in BigQuery.


Queue Management

flush()

Immediately send all queued events. Useful before a user navigates away.

vendo.flush();

The SDK flushes automatically on the configured interval (flushIntervalMs, default 5 seconds) and when the batch size is reached. You rarely need to call this manually.

debugState()

Return the current SDK state without sending an event. Use this while validating an implementation.

window.vendo.debugState();

Example response:

{ endpoint: "https://track.yourdomain.com/collect", storageKey: "vendo", anonymousId: "anon-id", userId: "user-123", sessionId: "session-id", queueLength: 0, optOut: false, consent: {}, writeKeyPresent: true, writeKeySuffix: "abcd", config: { batchSize: 20, flushIntervalMs: 5000, maxQueueSize: 200 } }

reset()

Clear all stored user data — anonymous ID, user ID, session, attribution, and the event queue. Call this on logout.

vendo.reset();

After calling reset():

  • A new anonymous ID is generated on the next event
  • User ID is cleared
  • Session is reset
  • Attribution data (UTMs, click IDs) is cleared
  • Event queue is cleared

Privacy

optOut()

Opt the user out of tracking. No events are collected or sent.

vendo.optOut();

optOut() immediately purges any queued events (including the persisted localStorage queue) and writes a persistent opt-out flag, so the opt-out survives page reloads: on the next page load the SDK starts opted out and neither replays nor resumes tracking.

optIn()

Opt the user back in after an optOut() call. Clears the persisted opt-out flag and re-enables tracking.

vendo.optIn();

Use these for GDPR/CCPA compliance. When opted out, all tracking methods become no-ops.

setConsent(groups)

Update the visitor’s consent state. Pass an object of consent group names to booleans; the values are merged into the current consent state and attached to every subsequent event at context.consent.

vendo.setConsent({ analytics: true, marketing: false });

If the SDK was initialized with waitForConsent: true, granting one of the required consent groups here (consent.requiredGroups, default ["analytics"]) flips the SDK out of its holding state and flushes the events that were queued while it waited. A decision that grants none of the required groups (e.g. “Reject all”, or necessary: true alone) resolves as denied and purges the held events. Without waitForConsent: true, consent values are stamped onto events but never gate sending.

getConsent()

Return a copy of the current consent groups.

vendo.getConsent(); // → { analytics: true, marketing: false }

For a full walkthrough of consent, waitForConsent, and automatic detection of consent-management platforms (OneTrust, Usercentrics, CookiePro, CookieFirst), see Consent Management.


Identity and Session Helpers

getAnonymousId()

Return the current persistent anonymous ID.

vendo.getAnonymousId(); // → "anon-abc-123"

getSessionId()

Return the current session ID.

vendo.getSessionId(); // → "session-abc-123"

destroy()

Tear down the tracker instance. Removes the flush timer, consent-management-platform listeners, declarative-tracking listeners, and the pagehide / beforeunload / visibilitychange window listeners.

vendo.destroy();

destroy() does not clear stored data — anonymous ID, user ID, session, and attribution remain in localStorage. Use reset() when you want to clear stored data (e.g., on logout).


Attribution Tracking

The SDK automatically captures UTM parameters and advertising click IDs from the URL on page load.

UTM Parameters

ParameterExample
utm_sourcegoogle
utm_mediumcpc
utm_campaignspring_sale_2026
utm_contentbanner_a
utm_termanalytics tool
utm_idcamp_12345
utm_source_platformgoogle
utm_campaign_id12345678
utm_creative_formatimage
utm_marketing_tacticprospecting

Click IDs

ParameterPlatform
gclidGoogle Ads
fbclidMeta Ads
msclkidMicrosoft Ads
ttclidTikTok Ads
sccidSnapchat Ads
dclidGoogle Display
twclidTwitter/X
wbraidGoogle Web-to-App
gbraidGoogle App-to-Web
gad_sourceGoogle Ads
li_fat_idLinkedIn
epikPinterest
ko_click_idKochava
aleidAliExpress

First-Touch vs Last-Touch

The SDK stores both first-touch and last-touch values:

  • First-touch (utm_source_first, gclid_first, etc.) — Set once on the user’s first visit. Never overwritten.
  • Last-touch (utm_source_last, gclid_last, etc.) — Updated on every visit with new URL parameters.

Both are attached to every event as properties.


Session Management

Sessions are tracked automatically using an inactivity timeout (default: 30 minutes).

  • A session ID is generated on first activity
  • The session remains active as long as events occur within the timeout window
  • After the timeout, the next event starts a new session
  • Session ID is attached to every event as sessionId

Configure the timeout at initialization:

vendo('init', 'YOUR_WRITE_KEY', { host: 'https://track.yourdomain.com', sessionTimeoutMs: 3600000, // 1 hour });

Local Storage

The SDK uses localStorage with the configured prefix (default: vendo) to persist:

KeyContents
vendoAnonymous ID, user ID, session, UTM parameters, click IDs
vendo_queuePending events waiting to be sent

All data is cleared when reset() is called.


Debug Mode

Enable debug mode to log all SDK activity to the browser console:

vendo('init', 'YOUR_WRITE_KEY', { host: 'https://track.yourdomain.com', debug: true, });

Debug output includes:

  • Every tracked event with its full payload
  • Queue changes, batch flush attempts, responses, and flush failures
  • sendBeacon fallback attempts during page unload
  • Session rotation events
  • Attribution parameter capture

Use window.vendo.debugState() alongside console logs to confirm the active endpoint, queue length, session ID, and consent state.

Remove debug: true before going to production.


Error Handling and Retries

Failed requests are retried automatically with exponential backoff:

AttemptDelay
1st retry~1 second
2nd retry~2 seconds
3rd retry~4 seconds

Events remain in the queue across page loads (persisted in localStorage). If the queue exceeds maxQueueSize (default: 200), the oldest events are dropped.


React SPA (Vite / Create React App)

Add the CDN snippet to your index.html:

<!-- index.html --> <head> <script> (function (w, d, s, e, l, k) { w['VendoObject'] = e; w[e] = w[e] || function () { (w[e].q = w[e].q || []).push(arguments); }; w[e].l = 1 * new Date(); l = d.createElement(s); k = d.getElementsByTagName(s)[0]; l.async = 1; l.src = 'https://cdn.vendodata.com/sdk/v1/vendo.js'; k.parentNode.insertBefore(l, k); })(window, document, 'script', 'vendo'); vendo('init', 'YOUR_WRITE_KEY', { host: 'https://YOUR_TRACKING_ENDPOINT' }); vendo('page'); </script> </head>

For React Router, track route changes with a component. It fires on mount, so it also covers the initial page view — if you use it, remove the vendo('page') call from the head snippet to avoid a duplicate:

// components/TrackPageViews.tsx import { useEffect } from 'react'; import { useLocation } from 'react-router-dom'; declare global { interface Window { vendo?: (...args: unknown[]) => void; } } export function TrackPageViews() { const location = useLocation(); useEffect(() => { if (typeof window.vendo === 'function') { window.vendo('page'); } }, [location]); return null; }

Add it inside your <BrowserRouter>:

<BrowserRouter> <TrackPageViews /> <Routes>{/* your routes */}</Routes> </BrowserRouter>

Framework Guides

For framework-specific setup (route-change tracking, plugins, etc.), see the dedicated guides:

  • Next.js — App Router and Pages Router
  • Vue — Vue 3 plugin with Vue Router
  • Nuxt — Nuxt 3 client plugin

Need help?

Include your workspace, integration or job ID, and the first error message when you contact support.

support@vendodata.com
Last updated on