Web SDK
The Kixo Web SDK auto-tracks clicks, page views, sessions, errors, scroll depth, web vitals, rage-clicks, dead-clicks, and heatmap data with a one-line embed. Network request monitoring is available as an opt-in setting. Distributed as a native ES module and works in modern browsers.
Installation
Script tag (CDN)
Add the snippet before the closing </head> tag. Note the type="module" — required because the SDK is an ES module. Session replay is code-split into a version-matched recorder chunk that only loads after replay has been enabled, so the base bundle stays small while replay is off.
<script
type="module"
src="https://cdn.kixo.io/kixo.min.js?project_id=YOUR_PROJECT_ID&api_key=YOUR_API_KEY">
</script>Note
The SDK reads project_id and api_key from the script URL and initializes itself. To configure options in application code, drop the URL params and call Kixo.init({...}) instead — the global Kixo object is available once the module has loaded.
<script type="module" src="https://cdn.kixo.io/kixo.min.js"></script>
<script type="module">
Kixo.init({
projectId: 'YOUR_PROJECT_ID',
apiKey: 'YOUR_API_KEY',
});
</script>npm
Use this when you want to configure options in application code rather than through the script URL. It exposes the same Kixo API as the CDN embed.
npm install @kixo.io/webimport Kixo from '@kixo.io/web';
Kixo.init({
projectId: 'YOUR_PROJECT_ID',
apiKey: 'YOUR_API_KEY',
});No-Code Platforms
If you are building with an AI-powered builder like Lovable, Bolt, v0, or Replit, paste the script-tag snippet directly into your builder's chat or code-injection settings. Most builders support adding scripts to the <head> of your site.
Configuration
The two-line embed uses the local analytics defaults below. Request monitoring remains opt-in. Session replay is intentionally absent from Kixo.init(): its enable switch, sampling, privacy, duration, and capture settings come only from the project dashboard.
Kixo.init({
projectId: 'YOUR_PROJECT_ID', // required
apiKey: 'YOUR_API_KEY', // required
// Per-tracker toggles — all default to true except network.
autoTrack: {
pageViews: true,
clicks: true,
scrollDepth: true,
sessions: true,
forms: true,
network: false, // opt in only when you need request telemetry
errors: true,
performance: true,
rageClicks: true,
deadClicks: true,
},
// Heatmap recording (clicks + scroll on by default; mouse-move opt-in).
heatmap: {
enabled: true,
clicks: true,
moves: false,
scroll: true,
},
});Note
Project-controlled config. Dashboard settings can disable local analytics trackers. Replay has no local positive enable flag at all: configure it underSettings → Session replay, and the SDK follows the latest project policy on its next config refresh.
Auto-tracked events
With the default configuration, Kixo automatically captures these events with no additional code:
page_view— every navigation (initial load + SPA route changes)session_start/session_endclick— all click interactions with element selectorscroll_depth— 25 / 50 / 75 / 100 % thresholdsrage_click— repeated clicks on the same elementdead_click— clicks on non-interactive elementserror— uncaught JavaScript exceptions + promise rejectionsperformance— page-load and Web Vitals metrics (LCP, FCP, FID, CLS, INP, TTFB)network_request— optional request timing when network tracking is enabledheatmap_click/scroll— heatmap data
See the full list in the Events Reference.
Custom events
Kixo.track()
Send a custom event with optional properties.
Kixo.track('purchase_completed', {
product_id: 'SKU-123',
amount: 49.99,
currency: 'USD',
});Typed event helpers
Sugar over Kixo.track() for the events Kixo recognizes by name (purchase, signup, subscribe_start,trial_start, cancel, upgrade,activation, share, invite). Typed wrappers buy compile-time property validation and a single source of truth for key names — backend's standard-event detector matches verbatim.
Kixo.trackPurchase({ amount: 49.99, currency: 'USD', productId: 'pro_yearly' });
Kixo.trackSubscriptionStart({
plan: 'pro',
amount: 9.99,
currency: 'USD',
interval: 'month',
});
Kixo.trackSignup({ method: 'google' });
Kixo.trackTrialStart({ plan: 'pro', days: 14 });
Kixo.trackCancel({ plan: 'pro', reason: 'too_expensive' });
Kixo.trackUpgrade({ fromPlan: 'free', toPlan: 'pro' });
Kixo.trackActivation({ event: 'first_post_published' });
Kixo.trackShare({ channel: 'twitter', contentId: 'post_123' });
Kixo.trackInvite({ channel: 'email', recipientCount: 5 });Kixo.identify()
Associate the current device with a known user. Reserved standard property keys carry a $-prefix (Mixpanel convention) so they namespace away from your own custom traits and promote to the dashboard's profile columns — see the Standard property catalog below for the full 37-key list.
Kixo.identify('user_123', {
$email: 'jane@example.com', // identity
$name: 'Jane Doe', // identity
$plan: 'pro', // subscription pack
$lifetime_orders: 12, // e-commerce pack
signup_source: 'twitter_ad', // custom trait
});Kixo.setUserProperty() — tag a user for segmentation
Attach arbitrary key/value attributes to the current user. Values can be strings, numbers, or booleans — the boolean form is the cleanest way to tag a user for later targeting in segments, email campaigns, or chat queries.
// Tag a user as subscribed — instant segment "Subscribed users"
Kixo.setUserProperty('subscribe', true);
// Mark a VIP — used in campaign targeting + chat ("show me VIPs")
Kixo.setUserProperty('vip', true);
// Numeric and string values work too
Kixo.setUserProperty('plan_tier', 'enterprise');
Kixo.setUserProperty('lifetime_orders', 42);
// Bulk-set
Kixo.setUserProperties({ subscribe: true, plan_tier: 'enterprise' });Properties persist in localStorage across reloads and auto-attach to subsequent events. Use them in chat with prompts like "build an email campaign for users where subscribe is true" — Kixo synthesizes a segment + drafts the template automatically. Cleared on Kixo.reset().
Kixo.group()
Associate the user with a company or organization.
Kixo.group('company_456', {
name: 'Acme Inc',
plan: 'enterprise',
});Kixo.reset()
Clear identity, super-properties, and the persisted queue. Call this on logout so subsequent events are not attributed to the previous user.
Kixo.reset();Standard property catalog
Reserved property keys carry a $ prefix so they namespace away from your custom traits. Kixo's catalog covers 37 keys across 3 universal packs (identity, geo, lifecycle) and 5 B2B vertical packs (subscription, e-commerce, media, marketplace, loyalty). Set whichever apply to your product — the dashboard adapts and renders only the packs you populate.
Identity
Always relevant. Sets the profile header columns.
| Key | Type | Description |
|---|---|---|
$email | string | Primary email, often the merge key for identity stitching. |
$phone | string | E.164 phone number. |
$name | string | Full display name. |
$first_name | string | Given name. |
$last_name | string | Family name. |
$avatar_url | string | Full URL to the user's avatar image. |
Geo
Geographic context.
| Key | Type | Description |
|---|---|---|
$country | string | ISO 3166 country code. |
$city | string | City name. |
$region | string | State or province. |
$timezone | string | IANA zone like America/Los_Angeles. |
$language | string | IETF tag like en or ru-RU. |
$locale | string | Full locale identifier. |
Lifecycle
When did we see them.
| Key | Type | Description |
|---|---|---|
$created | ISO8601 | Signup or account creation time. |
$last_seen | ISO8601 | Last engagement time. |
Subscription
Set if your product has plans.
| Key | Type | Description |
|---|---|---|
$plan | string | Tier slug — free, pro, enterprise. |
$subscription_status | string | active / trial / cancelled / past_due. |
$trial_ends | ISO8601 | When the current trial expires. |
$mrr | number | Monthly recurring revenue in account currency. |
$subscription_started | ISO8601 | When the current subscription began. |
E-commerce
Set if you sell products.
| Key | Type | Description |
|---|---|---|
$lifetime_orders | number | Count of completed orders. |
$lifetime_revenue | number | Total spend. |
$aov | number | Average order value. |
$last_purchase | ISO8601 | Most recent successful purchase. |
$first_purchase | ISO8601 | First successful purchase. |
$cart_abandoned_count | number | Lifetime count of cart abandonments. |
Media
Set if you publish content.
| Key | Type | Description |
|---|---|---|
$content_tier | string | free / premium / paid. |
$subscribed_categories | CSV string or array | Categories the user follows. |
$watch_time_total | number | Lifetime watch time in seconds. |
$last_played | ISO8601 | Most recent playback start. |
Marketplace
Set if you're a two-sided platform.
| Key | Type | Description |
|---|---|---|
$seller_tier | string | Seller-side tier slug. |
$buyer_tier | string | Buyer-side tier slug. |
$listings_count | number | Active listings the user owns. |
$reviews_count | number | Reviews the user has received. |
$verified | boolean | KYC status. |
Loyalty
Set for engagement and rewards programs.
| Key | Type | Description |
|---|---|---|
$loyalty_points | number | Current redeemable points balance. |
$vip_level | string | VIP tier slug. |
$referral_count | number | Successful referrals attributed to this user. |
Tip
Don't see your pattern? Use bare keys for custom traits. They surface in the dashboard's Custom Traits panel without polluting the profile columns. The 5 vertical packs above are opinionated guesses at the most common B2B shapes — customer-specific terminology (e.g. shipping_plan) stays bare.
Super-properties
Per-session key/value pairs auto-attached to every outbound event. Different from identify() traits (which describe the identity); super-properties describe session context — active A/B variant, build flavor, opted-in feature flags, affiliate ref. Persisted in localStorage across reloads; cleared on reset(). Per-event properties on track() always win on key collision.
Kixo.setSuperProperty('build_flavor', 'beta');
Kixo.setSuperProperties({ ab_variant: 'B', referrer_campaign: 'autumn-launch' });
// Sugar for A/B tracking — keys as 'experiment_<id>' so backend
// can run direct WHERE filters on experiment analysis.
Kixo.setExperimentVariant('checkout_v2', 'variant_a');
Kixo.unsetSuperProperty('build_flavor');
Kixo.clearSuperProperties();Heatmaps
Heatmap recording is on by default — clicks and scroll depth, both sampled at 100 %. Mouse movement is opt-in (high-volume; enable per- page if useful).
Kixo.init({
projectId: 'YOUR_PROJECT_ID',
apiKey: 'YOUR_API_KEY',
heatmap: { moves: true }, // turn on full-resolution mouse-move
});Session replay
Session replay records an rrweb DOM snapshot and mutation stream so the dashboard can reconstruct the page as a scrubbable session alongside the event trail. It is a DOM reconstruction rather than a screen-video recording. Replay is off by default. Enable it for the project under Dashboard → Settings → Session replay; no application-code change is required. When enabled, the recorder is fetched from a separate version-matched chunk after replay is enabled.
Note
The dashboard is the source of truth. Set Enable replay, Mask inputs, maximum duration, and the advanced capture controls there. captureOnCellular is stored in the same project policy for iOS and Android; browsers do not expose a dependable Wi-Fi-versus-cellular signal, so the Web SDK reports and ignores that native-only restriction.
What gets masked
Replay is designed to be safe to turn on. Three layers protect sensitive content, all on by default:
- Input masking is project-controlled — while Dashboard's Mask inputs setting is on (the default), typed characters are replaced with asterisks before they leave the browser. Turn it off only for a specific, low-sensitivity need; identity, authentication, and payment fields remain masked.
- The
data-kixo-maskattribute blocks an element and its entire subtree. Put it on any container that may hold personal or confidential content; the replay contains a placeholder, not that subtree's text or DOM content.html<div data-kixo-mask> <!-- payment fields, account numbers, private messages… --> <!-- captured as a blank placeholder, never as pixels --> </div> - Sensitive fields are always masked — inputs that look like a password, card number, CVV, SSN, secret, or token (by type, name, id, or autocomplete) are masked even when the project'sMask inputs setting is off. Visible text and serialized DOM attributes also pass through Kixo's PII sanitizer before upload.
Data collection
The SDK captures the trackers enabled in your integration and project settings, plus the events and properties your application sends.
Where recordings go
The SDK gzips rrweb events into bounded segments, asks Kixo for a project-scoped signed upload URL, and uploads those segments directly to replay storage. Open the reconstructed session under Replay → Sessions; it links to the same session's analytics trail.
Note
Replay is subject to your plan. How many sessions are captured and retained depends on your project plan; on lower tiers Kixo still records lightweight session metadata so the session shows up in your lists and analytics.
Feature flags
Check flag values at runtime via Kixo.getFeatureFlag().
const variant = Kixo.getFeatureFlag('new_checkout');
if (variant === 'enabled') {
showNewCheckout();
} else {
showLegacyCheckout();
}Delivery and offline behavior
The SDK queues events locally, sends them in batches, and retries transient failures with backoff. If collection is paused from project settings, new events are not sent until collection is enabled again.
Diagnostics
Read-only health snapshot — useful for "why aren't my events flowing?" debugging in dev tools.
const diag = Kixo.diagnostics();
console.log(diag);