Skip to Content

JavaScript SDK

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

Last reviewed September 15, 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 SDK File

You can serve the SDK file from your own domain.

  1. Download https://cdn.vendodata.com/sdk/v1/vendo.js.
  2. Put the file on your web server, for example at /js/vendo.js.
  3. In Vendo, open the tracking source.
  4. In Installation Snippet, click the Self-hosted tab.
  5. Copy the snippet.
  6. Replace https://YOUR_DOMAIN/vendo.js with the address of your file.

When Vendo releases a new SDK version, download the file again. To run the ingestion API on your own servers, see Self-Hosting.

Known issue: The array-based snippet (vendo.load(...)) has only these methods before the SDK loads: track, identify, page, group, alias, reset, optOut, optIn and flush. It does not have setConsent, getConsent or debugState. Call these 3 methods only after the SDK loads. The snippet from the Vendo app does not have this limit.

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') after init, and again on every client-side route change. The old trackPageViews / pageView options are deprecated no-ops.

Call Form and Method Form

You can call every method in 2 forms:

  • The call form, for example vendo('track', 'Signup Completed'). It works before and after the SDK loads.
  • The method form, for example vendo.track('Signup Completed'). It works only after the SDK loads.

Use the call form in code that can run early, for example in the snippet or in a route listener. The SDK is not published as an npm package. Load it with the snippet or from https://cdn.vendodata.com/sdk/v1/vendo.js.

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, and flush results to the browser console.
trackPageViewsboolean—Deprecated no-op since 0.2.0. Has no effect. Call vendo('page') explicitly. Alias for pageView.
pageViewboolean—Deprecated 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. It does not create an exit-intent event.
storageKeystring"vendo"localStorage key prefix for SDK data.
requestTimeoutMsnumber30000Timeout for each HTTP request to /collect.
maxEventBytesnumber32000Max size of 1 event in bytes (UTF-8 JSON). The SDK drops a larger event. See Size Limits.
maxBatchBytesnumber256000Max size of 1 batch request in bytes. Events that do not fit wait for the next flush.
maxAttemptsnumber20Max number of sends for 1 event. After this number of failed sends, the SDK drops the event.
retryBaseMsnumber1000Delay before the first retry, in ms. The delay doubles after each failed send.
retryMaxMsnumber300000Max delay between retries, in ms (default: 5 minutes).

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 (for example, "Product Viewed" or "Signup Completed").
propertiesobjectNoKey-value pairs of event properties.
contextobjectNoAdditional context to merge into the SDK’s automatic context envelope.

The SDK queues events locally and sends them in the next batch flush. It automatically adds these top-level fields to every event. They are next to 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. The SDK sends it once per batch, in the X-Write-Key header and as a batch-level writeKey on the request wrapper. It does not repeat the write key 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). The SDK also copies most of these values into properties (or traits) as flat keys, for example page_url and utm_source.

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", "language": "en-US", "consent": { "analytics": true, "marketing": false } } }

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

page(name, properties, context)

Track a page view. The SDK automatically captures the 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. Since 0.2.0, init never sends one automatically. 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 (for example, email, name, plan).
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 queued events. One call sends 1 batch of up to batchSize events. This is useful before a user navigates away.

vendo.flush();

The SDK flushes automatically at the configured interval (flushIntervalMs, default 5 seconds) and when the queue reaches the batch size. You rarely need to call flush() yourself.

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 the stored user data: anonymous ID, user ID, session, attribution, and the stored event queue. Call this on logout.

vendo.reset();

After calling reset():

  • A new anonymous ID is generated on the next page load. Until then, events on the current page keep the old anonymous ID
  • User ID is cleared
  • Session is reset
  • Attribution data (UTMs, click IDs) is cleared
  • The stored event queue is cleared. Events that are already queued in memory on the current page are still sent

Privacy

optOut()

Opt the user out of tracking. The SDK does not collect or send events.

vendo.optOut();

optOut() immediately purges any queued events (including the persisted localStorage queue). It also writes a persistent opt-out flag, so the opt-out survives page reloads. On the next page load, the SDK starts opted out. It does not replay events or resume tracking.

Known issue: If you call identify() while the user is opted out, the SDK does not send an event. But it saves the user ID in memory and in localStorage. After optIn(), later events include that user ID.

optIn()

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

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 SDK merges the values into the current consent state. It attaches them to every later event at context.consent.

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

If you initialized the SDK with waitForConsent: true, the SDK holds events until a required consent group is granted (consent.requiredGroups, default ["analytics"]). When setConsent grants 1 of these groups, the SDK stops holding. It then flushes the events that it held while it waited. A decision that grants none of the required groups (for example, “Reject all”, or necessary: true alone) resolves as denied. The SDK then purges the held events. Without waitForConsent: true, the SDK adds consent values to events, but consent never gates sending.

With waitForConsent: true, after the SDK resolves as denied, it drops every later event. It does not hold them. The SDK sends events again only after consent grants a required group.

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. The anonymous ID, user ID, session, and attribution stay in localStorage. Use reset() when you want to clear stored data (for example, 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

Known issue: The SDK does not send the value of the Meta _fbc cookie. It sends only the fbclid URL parameter.

First-Touch vs Last-Touch

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

  • First-touch (for example, utm_source_first and gclid_first): Set once, on the first visit that has tracking parameters. Never overwritten.
  • Last-touch (for example, utm_source_last and gclid_last): Updated on every visit with new URL parameters.

The SDK attaches only the last-touch values to events: in context.campaign, in context.clickId, and as flat properties such as utm_source.


Session Management

The SDK tracks sessions automatically with 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
vendo_optoutThe opt-out flag (1). optOut() sets it and optIn() removes it

reset() clears vendo and vendo_queue. It does not clear vendo_optout.


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
  • 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

If a request fails with a network error, a timeout, a 429 status, or a 5xx status, the SDK retries it automatically with exponential backoff:

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

The delay doubles after each failed send, up to retryMaxMs (default: 5 minutes). If an event fails maxAttempts times (default: 20), the SDK drops it.

The SDK does not retry other failed responses. It drops those events.

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

Size Limits

The SDK measures the size of each event as UTF-8 JSON.

  • If an event is larger than maxEventBytes (default: 32,000 bytes), the SDK drops it. It does not queue or send the event.
  • The SDK puts no more than maxBatchBytes (default: 256,000 bytes) of events in 1 request. Events that do not fit wait for the next flush.
  • If a queued event is larger than maxBatchBytes, the SDK drops it at flush.

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(Array.prototype.slice.call(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. The component 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) | { page: () => void }; } } export function TrackPageViews() { const location = useLocation(); useEffect(() => { if (typeof window.vendo === 'function') { window.vendo('page'); } else { window.vendo?.page(); } }, [location]); return null; }

Add it inside your <BrowserRouter>:

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

Framework Guides

For framework-specific setup (for example, route-change tracking and plugins), 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?

When you contact support, give your workspace, the source or destination name, the job ID and the first error message.

support@vendodata.com
Last updated on