Modern, TypeScript-first analytics SDK for browser event tracking with comprehensive type safety and plugin architecture.
NPM (Recommended)
npm install td-web-sdkCDN Script
<script type="text/javascript">
!function(t,e){if(void 0===e[t]){e[t]=function(){e[t].clients.push(this),this._init=[Array.prototype.slice.call(arguments)]},e[t].clients=[];for(var r=function(t){return function(){return this["_"+t]=this["_"+t]||[],this["_"+t].push(Array.prototype.slice.call(arguments)),this}},s=["set","collectTags","blockEvents","unblockEvents","setSignedMode","setAnonymousMode","fetchServerCookie","fetchGlobalID","fetchUserSegments","fetchPersonalization","resetUUID","addRecord","trackEvent","trackPageview","trackClicks","ready"],c=0;c<s.length;c++){var o=s[c];e[t].prototype[o]=r(o)}var n=document.createElement("script");n.type="text/javascript",n.async=!0,n.src=("https:"===document.location.protocol?"https:":"http:")+"//cdn.treasuredata.com/sdk/web/0.1/td-sdk.min.js";var i=document.getElementsByTagName("script")[0];i.parentNode.insertBefore(n,i)}}("Treasure",this);
</script>// TypeScript
import Treasure from 'td-web-sdk'
const td = new Treasure({
writeKey: 'your-write-key',
database: 'your-database'
})
// Track your first event
td.trackEvent('user_actions', {
action: 'click',
button: 'signup'
})// JavaScript (Node.js/CommonJS)
const Treasure = require('td-web-sdk').default
// Or ES modules
import Treasure from 'td-web-sdk'
const td = new Treasure({
writeKey: 'your-write-key',
database: 'your-database'
})- TypeScript-first: Full type safety and IntelliSense support
- Modern Architecture: Composable plugin-based system
- Privacy Compliance: GDPR-ready with privacy controls
- Automatic UTM Collection: UTM parameters captured on init
- Cross-device: Global ID and server-side cookies for ITP compliance
- Zero Dependencies: Lightweight, self-contained
// Track page view
td.trackPageview('pageviews')
// With success/error callbacks
td.trackPageview('pageviews',
(response) => console.log('Pageview tracked!'),
(error) => console.error('Failed:', error)
)
// With personalization: configure it once on the constructor. When set, every
// trackEvent/trackPageview call fetches personalization INSTEAD of ingesting the
// event (the call no longer records to your database — see below)
const td = new Treasure({
writeKey: 'your-write-key',
database: 'your-database',
personalization: {
endpoint: 'personalization.example.com',
token: 'personalization_token',
database: 'personalization_db' // optional; defaults to the main `database`
}
})
// The personalization table comes from the tracking call ('pageviews' here),
// and the request payload is the event data (track values + globals + record)
td.trackPageview('pageviews',
(response) => console.log('Personalization fetched!'),
(error) => console.error('Failed:', error)
)// Basic event
td.trackEvent('events', {
event_type: 'purchase',
item_id: 'SKU-123',
revenue: 29.99
})
// With success/error callbacks
td.trackEvent('button_clicks', { button: 'header_cta' },
(response) => console.log('Tracked!'),
(error) => console.error('Failed:', error)
)// Set user properties for all events
td.set('$global', 'user_id', '12345')
td.set('$global', 'plan', 'premium')
// Set table-specific defaults
td.set('purchases', 'currency', 'USD')
// Multiple properties at once
td.set('$global', {
user_id: '12345',
plan: 'premium',
signup_date: '2024-01-15'
})// Track all clicks on buttons and links
td.trackClicks()
// Custom configuration
td.trackClicks({
tableName: 'ui_interactions',
element: document.getElementById('main-content')
})// Collect UTM parameters from URL
const utmParams = td.collectUTMParameters()
console.log(utmParams) // { utm_source: 'google', utm_campaign: 'summer2024' }
// Get previously collected UTMs
const storedUtms = td.getUTMParameters()const td = new Treasure({
writeKey: 'key',
database: 'db',
startInSignedMode: false // Default: anonymous mode
})
// Anonymous mode (default) - no PII collected
td.setAnonymousMode()
td.trackEvent('events', { action: 'view' })
// Sends: { action: 'view', td_version: '1.0.0' }
// Omits: td_client_id, td_ip, td_global_id
// Signed mode - PII collection enabled
td.setSignedMode()
td.trackEvent('events', { action: 'purchase' })
// Sends: { action: 'purchase', td_client_id: 'uuid', td_ip: '192.168.1.1' }// Temporarily block all events
td.blockEvents()
td.trackEvent('blocked', {}) // Not sent
// Resume tracking
td.unblockEvents()
td.trackEvent('tracked', {}) // Sent normally
// Check status
if (td.areEventsBlocked()) {
console.log('Tracking is currently blocked')
}const td = new Treasure({ writeKey: 'key', database: 'db' })
// Programmatically manage privacy based on user preferences
function handleUserPrivacyChoice(privacyLevel) {
switch (privacyLevel) {
case 'full_tracking':
td.unblockEvents()
td.setSignedMode()
break
case 'anonymous_only':
td.unblockEvents()
td.setAnonymousMode()
break
case 'no_tracking':
td.blockEvents()
break
}
}
// Example: User clicks privacy preference buttons
document.getElementById('accept-all').onclick = () => handleUserPrivacyChoice('full_tracking')
document.getElementById('essential-only').onclick = () => handleUserPrivacyChoice('anonymous_only')
document.getElementById('reject-all').onclick = () => handleUserPrivacyChoice('no_tracking')// 1. Enable Global ID collection
td.set('$global', 'td_global_id', 'td_global_id')
// 2. Switch to signed mode
td.setSignedMode()
// 3. Fetch Global ID
td.fetchGlobalID(
(globalId) => {
console.log('Global ID:', globalId)
// Use for cross-device analytics
},
(error) => console.error('Failed to get Global ID:', error),
false, // forceFetch
{
domain: '.yourdomain.com',
secure: true,
sameSite: 'None'
}
)const td = new Treasure({
writeKey: 'key',
database: 'db',
useServerSideCookie: true,
sscDomain: 'yourdomain.com'
})
td.fetchServerCookie(
(serverId) => console.log('Server ID:', serverId),
(error) => console.error('Server cookie failed:', error)
)// Fetch user segments for personalization
td.fetchUserSegments(
'audience_token_abc123',
(segments) => {
segments.forEach(segment => {
console.log('Segment:', segment.values)
console.log('Attributes:', segment.attributes)
})
},
(error) => console.error('Segmentation failed:', error)
)
// With custom keys
td.fetchUserSegments({
audienceToken: ['token1', 'token2'],
keys: { user_id: '12345', email: 'user@example.com' }
}, successCallback, errorCallback)// Manual personalization fetch
td.fetchPersonalization({
endpoint: 'personalization.example.com',
database: 'recommendations_db',
table: 'user_offers',
token: 'p13n_token_123'
}, {
user_id: '12345',
page_type: 'product_detail',
product_category: 'electronics'
}, (response) => {
console.log('Personalization response:', response)
})
// Personalization driven by tracking calls
// Configure personalization once on the constructor...
const td = new Treasure({
writeKey: 'your-write-key',
database: 'your-database',
personalization: {
endpoint: 'personalization.example.com',
token: 'p13n_token_123',
database: 'recommendations_db' // optional; defaults to the main `database`
}
})
// ...then trackEvent and trackPageview fetch personalization instead of
// ingesting the event. The personalization table is the tracking call's table,
// and the request payload is the event data ($global + table defaults + track
// values + record) — not recorded to your database.
td.trackEvent('events', { action: 'view' })
td.trackPageview('pageviews',
(response) => console.log('Personalization fetched'),
(error) => console.error('Personalization failed')
)For advanced users who need custom plugin combinations:
import {
createSDK,
session,
record,
track,
clicks,
utm,
globalId
} from 'td-web-sdk'
// Build custom SDK with only needed plugins
const sdk = createSDK({
writeKey: 'your-key',
database: 'your-db'
})
.use(session()) // Identity & consent management
.use(record()) // Core event submission
.use(track()) // Auto-tracked properties
.use(clicks()) // Click tracking (optional)
.use(utm()) // UTM collection (optional)
.use(globalId()) // Global ID (optional)
// Same API as the full Treasure constructor
sdk.trackEvent('events', { custom: 'data' })When using trackEvent() or trackPageview(), these properties are automatically included:
| Property | Description | Example |
|---|---|---|
td_version |
SDK version | "1.0.0" |
td_client_id |
Client UUID* | "abc-123-def" |
td_charset |
Page character set | "utf-8" |
td_language |
Browser language | "en-us" |
td_color |
Screen color depth | "24-bit" |
td_screen |
Screen resolution | "1920x1080" |
td_viewport |
Viewport size | "1200x800" |
td_title |
Page title | "Home Page" |
td_description |
Meta description | "Welcome to..." |
td_url |
Page URL | "https://example.com/page" |
td_user_agent |
User agent + SDK info | "Mozilla/5.0...;WEBSDK/1.0.0" |
td_platform |
Platform | "MacIntel" |
td_host |
Hostname | "example.com" |
td_path |
URL path | "/products/123" |
td_referrer |
Referrer URL | "https://google.com" |
Server-side properties (populated by Treasure Data):
| Property | Description | Signed Mode Only |
|---|---|---|
td_ip |
Request IP address | ✓ |
* Marked properties are considered PII and only sent in signed mode
const td = new Treasure({
// Required
writeKey: 'your-write-key', // Get from Treasure Data console
database: 'your-database', // Target database name
// Optional
host: 'us01.records.in.treasuredata.com', // API endpoint host
development: false, // Enable development mode (no events sent)
logging: true, // Enable console logging
startInSignedMode: false, // Default consent mode
jsonpTimeout: 10000, // Request timeout (ms)
})When set, every trackEvent and trackPageview call fetches personalization and renders any in-browser messages instead of ingesting the event to your database. The personalization table is the table passed to the tracking call, and the request payload is the event data ($global + table defaults + track values + record).
const td = new Treasure({
writeKey: 'key',
database: 'db',
personalization: {
endpoint: 'personalization.example.com', // Personalization API endpoint
token: 'p13n_token_123', // Personalization API token
database: 'recommendations_db' // Optional; defaults to the main `database`
}
})const td = new Treasure({
writeKey: 'key',
database: 'db',
storage: {
name: '_td', // Cookie name
expires: 63072000, // Expiry (seconds, 2 years default)
domain: '.yourdomain.com', // Cookie domain
path: '/' // Cookie path
}
})
// Disable cookie storage
const td = new Treasure({
writeKey: 'key',
database: 'db',
storage: 'none'
})const td = new Treasure({
writeKey: 'key',
database: 'db',
useServerSideCookie: true,
sscDomain: 'yourdomain.com', // Or function: () => window.location.hostname
sscServer: 'ssc.yourdomain.com' // Or function: (domain) => `ssc.${domain}`
})new Treasure(config: TDConfig): TreasureParameters:
config(Object, required): Configuration objectwriteKey(string, required): Write-only API key from Treasure Data consoledatabase(string, required): Target database namehost(string, optional): API endpoint host. Default:'us01.records.in.treasuredata.com'development(boolean, optional): Development mode - logs events without sending. Default:falselogging(boolean, optional): Enable console logging. Default:truestartInSignedMode(boolean, optional): Start in signed mode. Default:falsejsonpTimeout(number, optional): Request timeout in milliseconds. Default:10000storage(Object|string, optional): Cookie storage configuration or'none'to disableuseServerSideCookie(boolean, optional): Enable server-side cookie support. Default:falsepersonalization(Object, optional): Personalization config. When set, everytrackEvent/trackPageviewfetches personalization instead of ingesting the eventendpoint(string, required): Personalization API endpointtoken(string, required): Personalization API tokendatabase(string, optional): Personalization database name. Defaults to the maindatabase- The personalization table is the table passed to the tracking call (e.g.
'events','pageviews'), not configured here - The request payload is the event data (
$global+ table defaults + track values + the call'srecord), not configured here
Manual event submission without automatic tracking data.
Parameters:
table(string, required): Table name (3-255 chars, lowercase, numbers, underscore only)record(Object, required): Event data object to sendsuccess(Function, optional): Success callback(response: TrackResponse) => voiderror(Function, optional): Error callback(error: TDError) => void
Event tracking with automatic browser/session properties included. When personalization is configured on the constructor, fetches personalization instead of ingesting the event (see Behavior below).
Parameters:
table(string, optional): Table name. Default:'events'record(Object, optional): Additional event data. Default:{}success(Function, optional): Success callback(response: TrackResponse) => voiderror(Function, optional): Error callback(error: TDError) => void
Behavior:
- When
personalizationis not configured: records the event with automatic properties viaaddRecord, invoking thesuccess/errorcallbacks. - When
personalizationis configured (see Configuration Options): calls the personalization API instead of recording the event. The personalization table istable, and the request payload is the event data layered as$global→ table defaults → automatic track values →record.- Personalization responses trigger in-browser message rendering
- Personalization errors are logged
- The
success/errorcallbacks are not invoked on this path
Page view tracking with automatic browser/session properties. Delegates to trackEvent, so it shares the same personalization behavior.
Parameters:
table(string, optional): Table name. Default:'pageviews'success(Function, optional): Success callback(response: TrackResponse) => voiderror(Function, optional): Error callback(error: TDError) => voidoptions(Object, optional): Tracking optionspayload(Object, optional): Additional event data to merge into the tracking record
Behavior:
- Delegates to
trackEventwith the resolved table name andoptions.payloadas the record - When
personalizationis not configured on the constructor: records the pageview with automatic properties viaaddRecord - When
personalizationis configured: fetches personalization instead of ingesting (same XOR behavior astrackEvent). Personalization responses trigger in-browser message rendering and page personalization. Page personalization is suppressed while loaded in Personalization Studio
Set default properties for tables or globally.
Parameters:
table(string, required): Table name or'$global'for all tableskey(string, required): Property name (when using 3-parameter form)value(JSONValue, required): Property value (when using 3-parameter form)object(Object, required): Multiple properties object (when using 2-parameter form)
Retrieve stored default properties.
Parameters:
table(string, optional): Table name. Default:'$global'key(string, optional): Specific property name. If omitted, returns all properties for table
Returns: JSONValue - The property value or properties object
Enable signed mode - allows collection of PII (td_client_id, td_ip, td_global_id).
Enable anonymous mode - blocks PII collection.
Parameters:
keepIdentifier(boolean, optional): Keep existing cookies/identifiers. Default:false
Check current privacy mode.
Returns: boolean - True if in signed mode, false if anonymous
Block all event tracking. Events will not be sent or cached.
Resume event tracking.
Check if events are currently blocked.
Returns: boolean - True if events are blocked
Generate new client UUID and update cookie.
Parameters:
storage(Object, optional): Custom storage configurationclientId(string, optional): Specific UUID to set. If omitted, generates random UUID
Enable automatic click tracking for buttons and links.
Parameters:
options(Object, optional): Click tracking configurationtableName(string, optional): Table name. Default:'clicks'element(string|HTMLElement, optional): Target element or selector. Default:document
Extract UTM parameters from current URL.
Returns: Object - UTM parameters object (utm_source, utm_campaign, etc.)
Get previously collected UTM parameters.
Returns: Object - Stored UTM parameters
Fetch Treasure Data Global ID for cross-device tracking.
Prerequisites: Must call setSignedMode() and set('$global', 'td_global_id', 'td_global_id') first.
Parameters:
success(Function, optional): Success callback(globalId: string | null) => voiderror(Function, optional): Error callback(error: unknown) => voidforceFetch(boolean, optional): Skip cache and fetch fresh ID. Default:falseoptions(Object, optional): Cookie optionspath(string, optional): Cookie pathdomain(string, optional): Cookie domainsecure(boolean, optional): Secure flagmaxAge(number|string|Date, optional): Cookie expiry. Default:6000sameSite(string, optional): SameSite attribute ('None'|'Lax'|'Strict'). Default:'None'
Fetch server-side cookie for ITP compliance.
Prerequisites: Must enable with useServerSideCookie: true in config and call setSignedMode().
Parameters:
success(Function, optional): Success callback(serverSideId: string) => voiderror(Function, optional): Error callback(error: string | Error) => voidforceFetch(boolean, optional): Skip cache and fetch fresh cookie. Default:false
Fetch user segments for personalization.
Parameters (Form 1):
audienceToken(string|string[], required): Audience token(s)success(Function, optional): Success callback with segment dataerror(Function, optional): Error callback
Parameters (Form 2):
options(Object, required): Segmentation optionsaudienceToken(string|string[], required): Audience token(s)keys(Object, optional): Additional key-value data
success(Function, optional): Success callback with segment dataerror(Function, optional): Error callback
Fetch personalization data from CDP API.
Parameters:
config(Object, required): Personalization configurationendpoint(string, required): API endpoint URLdatabase(string, required): Database nametable(string, required): Table nametoken(string, required): API token
data(Object, optional): Additional request datasuccess(Function, optional): Success callback(response: Object) => voiderror(Function, optional): Error callback(error: Error) => void
Collect conversion tracking tags for ad platforms.
Parameters:
options(Object, optional): Collection optionstable(string, optional): Table name for storing tagssuccess(Function, optional): Success callback(response: TrackResponse) => voiderror(Function, optional): Error callback(error: TDError) => void
const td = new Treasure({ writeKey: 'key', database: 'ecommerce' })
// Product view
td.trackEvent('product_views', {
product_id: 'SKU-123',
category: 'electronics',
price: 299.99,
currency: 'USD'
})
// Purchase
td.trackEvent('purchases', {
order_id: 'ORDER-456',
items: ['SKU-123', 'SKU-789'],
total: 349.98,
payment_method: 'credit_card'
})
// Set user context
td.set('$global', {
user_id: '12345',
customer_tier: 'gold',
signup_date: '2024-01-15'
})const td = new Treasure({ writeKey: 'key', database: 'saas_analytics' })
// Feature usage
td.trackEvent('feature_usage', {
feature: 'dashboard_export',
plan: 'pro',
execution_time_ms: 1250
})
// User onboarding
td.trackEvent('onboarding_steps', {
step: 'profile_completed',
step_number: 3,
time_to_complete_sec: 45
})
// Error tracking
td.trackEvent('errors', {
error_type: 'validation_failed',
form: 'user_signup',
field: 'email'
})const td = new Treasure({ writeKey: 'key', database: 'content_analytics' })
// Article engagement
td.trackEvent('content_engagement', {
article_id: 'post-123',
engagement_type: 'scroll_75_percent',
time_on_page_sec: 120,
reading_speed_wpm: 200
})
// Video tracking
td.trackEvent('video_events', {
video_id: 'vid-789',
event: 'play',
position_sec: 0,
duration_sec: 300
})
// Newsletter signup
td.trackEvent('conversions', {
type: 'newsletter_signup',
source: 'article_cta',
article_category: 'technology'
})Events not appearing in Treasure Data:
- Check
development: falsein config - Verify
writeKeyanddatabaseare correct - Ensure events aren't blocked:
td.areEventsBlocked() - Check browser console for error messages
TypeScript errors:
npm install --save-dev @types/node # If using Node.js typesGlobal ID not working:
- Must call
td.setSignedMode()first - Must enable with
td.set('$global', 'td_global_id', 'td_global_id') - Check HTTPS requirement for secure cookies
Server-side cookie fails:
- Verify
useServerSideCookie: truein config - Check
sscDomainconfiguration - Ensure signed mode is enabled
const td = new Treasure({
writeKey: 'key',
database: 'db',
development: true, // Events logged, not sent
logging: true // Enable debug logs
})- Modern: Chrome 90+, Firefox 88+, Safari 14+, Edge 90+
- Baseline: All browsers with ES2022 support
- Polyfills: None required for target browsers
- All requests use HTTPS
- Write-only API keys (no read access)
- Optional PII collection controls
- SameSite=None cookies for cross-site tracking
- No sensitive data in localStorage
This project uses automated code quality checks that run before each commit:
- Type checking - TypeScript compilation validation
- Linting - ESLint rules enforcement
- Formatting - Prettier code formatting
To enable automatic code quality checks on commit:
npm run hooks:installThis configures git to run type-check, linting, and formatting before each commit. If formatting changes are needed, the commit will be blocked and you'll need to review and stage the changes.
You can also run these checks manually:
npm run type-check # TypeScript compilation check
npm run lint # ESLint linting
npm run lint:fix # Auto-fix linting issues
npm run format # Apply Prettier formatting
npm run format:check # Check formatting without applying changes