JavaScript SDK
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
CDN Snippet (Recommended)
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"
});
</script>npm
Coming soon — The npm package
@vendo/trackingis not yet published. For now, use the CDN snippet above.
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',
trackPageViews: true
});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.
The vendo('init', ...) call accepts these options:
| Option | Type | Default | Description |
|---|---|---|---|
host | string | "" | Base URL of your tracking endpoint. The SDK derives the collect endpoint as {host}/collect. |
debug | boolean | false | Log all SDK activity to the browser console. |
trackPageViews | boolean | false | Automatically send a page view on initialization. Alias for pageView. |
pageView | boolean | false | Automatically send a page view on initialization. |
flushIntervalMs | number | 5000 | How often (ms) to flush the event queue. |
batchSize | number | 20 | Max events per batch request. |
maxQueueSize | number | 1000 | Max events to buffer locally before dropping oldest. |
sessionTimeoutMs | number | 1800000 | Session timeout in ms (default: 30 minutes). A new session starts after this period of inactivity. |
exitIntent | boolean | false | Automatically track exit intent events. |
storageKey | string | "vendo" | localStorage key prefix for SDK data. |
requestTimeoutMs | number | 10000 | Timeout 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
});| Option | Type | Default | Description |
|---|---|---|---|
endpoint | string | "/collect" | Full URL of the collect endpoint. |
All other options are the same as vendo('init', ...).
Tracking Methods
track(event, properties)
Track a custom event.
vendo.track("Product Viewed", {
sku: "SKU-1",
price: 29.99,
category: "shoes",
currency: "USD"
});| Parameter | Type | Required | Description |
|---|---|---|---|
event | string | Yes | Name of the event (e.g., "Product Viewed", "Signup Completed"). |
properties | object | No | Key-value pairs of event properties. |
Events are queued locally and sent in the next batch flush. The SDK automatically adds these properties to every event:
| Property | Description |
|---|---|
messageId | Unique ID (UUID v4) |
timestamp | ISO 8601 timestamp |
anonymousId | Persistent anonymous ID |
userId | Set after identify() is called |
sessionId | Current session ID |
writeKey | Your write key |
page_url | Current URL |
page_path | Current path |
page_title | Current page title |
referrer | Document referrer |
browser | Browser name |
os | Operating system |
device | Device/platform |
locale | Browser locale |
screen_width | Screen width (px) |
screen_height | Screen height (px) |
user_agent | Full user agent string |
tracking_library_name | "vendo-web-tracking" |
tracking_library_version | SDK version |
UTM parameters and click IDs are also included when present (see Attribution).
page(name, properties)
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" });| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | No | Page name. Defaults to "Page Viewed". |
properties | object | No | Additional page properties. |
Page events are written to the events table with type: "page".
identify(userId, traits)
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"
});| Parameter | Type | Required | Description |
|---|---|---|---|
userId | string | Yes | Unique user identifier from your system. |
traits | object | No | User properties (email, name, plan, etc.). |
After calling identify():
- The
userIdis persisted in localStorage and attached to all subsequent events - An identify event is sent to the
userstable 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)
Associate the current user with a group (company, organization, account).
vendo.group("org-42", {
name: "Acme Inc",
plan: "Enterprise",
employee_count: 150
});| Parameter | Type | Required | Description |
|---|---|---|---|
groupId | string | Yes | Unique group identifier. |
traits | object | No | Group properties. |
Group events are written to the groups table in BigQuery.
alias(userId, previousId)
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");| Parameter | Type | Required | Description |
|---|---|---|---|
userId | string | Yes | The new canonical user ID. |
previousId | string | Yes | The previous anonymous or temporary ID. |
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.
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();optIn()
Opt the user back in after an optOut() call.
vendo.optIn();Use these for GDPR/CCPA compliance. When opted out, all tracking methods become no-ops.
Attribution Tracking
The SDK automatically captures UTM parameters and advertising click IDs from the URL on page load.
UTM Parameters
| Parameter | Example |
|---|---|
utm_source | google |
utm_medium | cpc |
utm_campaign | spring_sale_2026 |
utm_content | banner_a |
utm_term | analytics tool |
utm_id | camp_12345 |
utm_source_platform | google |
utm_campaign_id | 12345678 |
utm_creative_format | image |
utm_marketing_tactic | prospecting |
Click IDs
| Parameter | Platform |
|---|---|
gclid | Google Ads |
fbclid | Meta Ads |
msclkid | Microsoft Ads |
ttclid | TikTok Ads |
sccid | Snapchat Ads |
dclid | Google Display |
twclid | Twitter/X |
wbraid | Google Web-to-App |
li_fat_id | |
ko_click_id | Kochava |
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:
| Key | Contents |
|---|---|
vendo | Anonymous ID, user ID, session, UTM parameters, click IDs |
vendo_queue | Pending 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
- Batch flush attempts and responses
- Session rotation events
- Attribution parameter capture
Remove debug: true before going to production.
Error Handling and Retries
Failed requests are retried automatically with exponential backoff:
| Attempt | Delay |
|---|---|
| 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: 1000), 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', { trackPageViews: true });
</script>
</head>For React Router, track route changes with a component:
// 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
Related
- Quickstart — Get started in 5 minutes
- API Reference —
/collectendpoint and event schema - Self-Hosting — Deploy the ingestion API