@li2/analytics
v0.5.1
Published
Li2 Analytics SDK for conversion tracking
Readme
@li2/analytics
Conversion tracking SDK for Li2.ai. Track leads and sales from your marketing campaigns with automatic click ID attribution.
Installation
npm install @li2/analytics
# or
pnpm add @li2/analytics
# or
yarn add @li2/analyticsClient-Side SDK
The client-side SDK automatically captures click IDs from URLs (?uid=...) and cookies, making it easy to track conversions in the browser. You don't need to pass clickId manually - it's auto-detected.
Note: If you need to track conversions on the server (e.g., after a webhook or server-side payment confirmation), use
getClickId()to capture the click ID on the client and pass it to your server. See Server-Side SDK for details.
Installation Snippet
Add this snippet to your <head> tag. It loads the SDK asynchronously and queues any tracking calls made before the script loads.
<script>
!(function (c, n) {
c[n] = c[n] || function () { (c[n].q = c[n].q || []).push(arguments); };
["trackLead", "trackSale", "trackEvent", "identify"].forEach((t) => (c[n][t] = (...a) => c[n](t, ...a)));
var s = document.createElement("script");
s.defer = 1;
s.src = "https://unpkg.com/@li2/analytics/dist/index.global.js";
s.setAttribute("data-publishable-key", "li2_pk_...");
document.head.appendChild(s);
})(window, "li2Analytics");
</script>Script Tag Usage
<script
src="https://unpkg.com/@li2/analytics/dist/index.global.js"
data-publishable-key="li2_pk_..."
></script>
<script>
// Track a lead
li2Analytics.trackLead({
eventName: 'signup',
customerExternalId: 'user_123',
customerName: 'John Doe',
customerEmail: '[email protected]',
})
// Track a sale (click ID auto-detected from cookie/URL)
li2Analytics.trackSale({
customerExternalId: 'user_123',
amount: 4999, // $49.99 in cents
eventName: 'purchase',
invoiceId: 'inv_abc123',
})
// Track a direct sale (no tracked link — pass clickId: "" explicitly)
li2Analytics.trackSale({
customerExternalId: 'user_123',
amount: 2500,
clickId: '', // Direct Sale — no link attribution
})
// Track a named event
li2Analytics.trackEvent('button_clicked', { category: 'cta' })
</script>Script Tag Attributes
| Attribute | Description |
| --------- | ----------- |
| data-publishable-key | Your publishable API key (li2_pk_...) |
| data-api-url | Custom API endpoint (default: https://api.li2.ai) |
| data-debug | Enable debug logging (presence enables, no value needed) |
| data-cookie-options | JSON object for cookie customization (see below) |
| data-outbound | JSON array of domains for outbound link tracking (e.g., ["partner.com"]) |
| data-pageview | "true" to enable automatic pageview tracking |
| data-clicks | "true" to enable automatic click tracking (heatmap data) |
Cookie Options
By default, the SDK stores the click ID in a cookie scoped to the current domain with a 30-day expiration. Use data-cookie-options for cross-domain tracking or custom expiration.
<script
src="https://unpkg.com/@li2/analytics/dist/index.global.js"
data-publishable-key="li2_pk_..."
data-cookie-options='{"domain":".example.com","expiresInDays":60}'
></script>| Property | Type | Default | Description |
| -------- | ---- | ------- | ----------- |
| domain | string | (current domain) | Cookie domain for cross-subdomain tracking (e.g., .example.com) |
| expiresInDays | number | 30 | Days until the cookie expires |
| path | string | "/" | Cookie path |
Cross-domain tracking example: If users land on www.example.com but convert on app.example.com, set domain to .example.com to share the click ID across subdomains.
Outbound Link Tracking
Automatically append click IDs to outbound links and iframes pointing to specified domains. This is useful for tracking conversions across multiple domains or passing attribution data to partner sites.
Key Benefits:
- ✅ Reduced bundle size - Only loads when configured (separate module)
- ✅ Automatic tracking - No manual link modification needed
- ✅ Dynamic content support - Tracks links added after page load
- ✅ SPA compatible - Works with client-side routing
Script Tag Usage
Add the data-outbound attribute with a JSON array of domains to track:
<script
src="https://unpkg.com/@li2/analytics/dist/index.global.js"
data-publishable-key="li2_pk_..."
data-outbound='["partner.com", "checkout.example.com"]'
></script>The SDK will automatically:
- Find all
<a>and<iframe>elements pointing to the specified domains - Append the click ID as a
uidquery parameter - Monitor for dynamically added links (SPAs, AJAX content)
Module Import Usage
import { init } from '@li2/analytics'
init({
publishableKey: 'li2_pk_...',
outbound: ['partner.com', 'checkout.example.com'],
})Example
Before tracking:
<a href="https://partner.com/signup">Sign up</a>After tracking (automatic):
<a href="https://partner.com/signup?uid=abc123xyz">Sign up</a>The partner site can then read the uid parameter and use it for server-side conversion tracking.
How It Works
- Domain matching: Links are tracked if their hostname ends with any configured domain
- Normalization:
www.prefixes are automatically stripped for matching - Deduplication: Each link is only modified once to avoid duplicate parameters
- Periodic scanning: New links are detected every 2 seconds
- History API support: Links are re-scanned on navigation in SPAs
Note: The outbound module is loaded dynamically only when the outbound option is configured, keeping your bundle size minimal when not needed.
Pageview Tracking
Automatically track every page visit on your website, including SPA (React, Vue, Angular) navigation. Pageview data powers funnel analytics and drop-off analysis.
Key Benefits:
- ✅ MPA + SPA support - Works with traditional sites and single-page apps
- ✅ Automatic session management - Visitor and session IDs with 30-min timeout
- ✅ Batched delivery - Events buffered and sent every 5s to minimize requests
- ✅ Lazy-loaded - Only loads when enabled, keeping your bundle minimal
Script Tag Usage
Add data-pageview="true" to enable automatic pageview tracking:
<script
src="https://unpkg.com/@li2/analytics/dist/index.global.js"
data-publishable-key="li2_pk_..."
data-pageview="true"
></script>Configuration Attributes
| Attribute | Default | Description |
| --------- | ------- | ----------- |
| data-pageview | "false" | Enable pageview tracking |
| data-pageview-spa | "auto" | SPA mode: "auto", "manual", or "disabled" |
| data-pageview-hash | "false" | Track hash changes as separate pageviews |
| data-pageview-exclude | "" | Comma-separated URL patterns to exclude (e.g., "/admin/*,/api/**") |
| data-pageview-timeout | "30" | Session timeout in minutes |
| data-pageview-batch | "5000" | Batch send interval in milliseconds |
| data-pageview-search-params | "q,query,search,s,keyword" | URL params to detect as search queries |
| data-pageview-cookie-less | "false" | Use only localStorage (no cookies) |
Programmatic Usage
// Enable pageview tracking programmatically
li2Analytics.enablePageviewTracking({
spaMode: 'auto',
excludePatterns: ['/admin/*'],
sessionTimeout: 30,
});
// Manually track a pageview
li2Analytics.trackPageview({
pageUrl: 'https://example.com/products',
pageTitle: 'Products',
});
// Control tracking
li2Analytics.pageview.disable();
li2Analytics.pageview.enable();
li2Analytics.pageview.newSession();How It Works
- Page detection: Intercepts History API (
pushState,replaceState) andpopstateevents for SPA navigation - Session management: Assigns persistent
visitor_id(localStorage + cookie) andsession_id(sessionStorage) with configurable timeout - Batching: Buffers pageview events and flushes every 5 seconds via
fetch, or immediately viasendBeaconon page unload - Click ID linking: Automatically links pageviews to Li2 click IDs for attribution
Click Tracking
Automatically capture every click on your page to power heatmaps and rage click detection in the Li2 dashboard. Uses a single delegated listener and batched delivery — zero impact on page performance.
Key Benefits:
- ✅ Zero-config - One attribute enables it all
- ✅ Automatic deduplication - Rapid repeated clicks are deduplicated (50ms window)
- ✅ Element metadata - Captures tag, text, class, ID, and CSS selector path
- ✅ Rage click detection - Backend automatically detects frustration patterns
- ✅ Lazy-loaded - Module only loads when enabled
Script Tag Usage
Add data-clicks="true" to enable automatic click tracking:
<script
src="https://unpkg.com/@li2/analytics/dist/index.global.js"
data-publishable-key="li2_pk_..."
data-pageview="true"
data-clicks="true"
></script>Configuration Attributes
| Attribute | Default | Description |
| --------- | ------- | ----------- |
| data-clicks | "false" | Enable click tracking |
| data-clicks-exclude | "" | CSS selector for elements to exclude (e.g., ".no-track, #sensitive") |
| data-clicks-batch | "5000" | Batch send interval in milliseconds |
Note: Click tracking shares session config with pageview tracking. Set
data-pageview-timeout,data-pageview-cookieless, etc. once and both modules use the same session.
Programmatic Usage
import { init } from '@li2/analytics'
const sdk = init({ publishableKey: 'li2_pk_...' })
await sdk.enableClickTracking({
excludeSelector: '.no-track',
batchInterval: 3000,
})Event Tracking
Track named custom events (button clicks, form submissions, feature usage) that appear in your Li2 funnel analytics and event rules. Events flow through the same pipeline as pageviews — no extra setup needed.
Key Benefits:
- ✅ Funnel compatible - Events appear as steps in your funnel builder
- ✅ Event rules - Power automated tagging and retroactive classification
- ✅ Auto-init - Starts pageview pipeline automatically if not already running
- ✅ Category support - Group events for easier filtering
Script Tag Usage
<script>
// Track a button click
li2Analytics.trackEvent('cta_clicked')
// Track with a category
li2Analytics.trackEvent('video_played', { category: 'engagement' })
// Track form submission
document.querySelector('#signup-form').addEventListener('submit', () => {
li2Analytics.trackEvent('form_submitted', { category: 'conversion' })
})
</script>Module Import Usage
import { trackEvent } from '@li2/analytics'
// Track a named event
await trackEvent('plan_selected', { category: 'onboarding' })How It Works
Events are sent through the pageview pipeline with an event_name field set. This means:
- They are scoped to the current page URL and session
- They appear in funnel builder as matchable steps (type: "event")
- They trigger any matching event rules in the Li2 dashboard
- They are stored alongside pageview data for unified analysis
Module Import Usage
import { init, trackLead, trackSale } from '@li2/analytics'
// Initialize with your publishable key
init({
publishableKey: 'li2_pk_...',
debug: true, // optional: enable console logging
})
// Track a lead conversion
const leadResult = await trackLead({
eventName: 'signup',
customerExternalId: 'user_123',
customerName: 'John Doe',
customerEmail: '[email protected]',
})
if (leadResult.success) {
console.log('Lead tracked:', leadResult.customerId)
}
// Track a sale conversion
const saleResult = await trackSale({
customerExternalId: 'user_123',
amount: 4999, // Amount in cents ($49.99)
eventName: 'purchase',
paymentProcessor: 'stripe',
invoiceId: 'inv_abc123',
currency: 'usd',
})
if (saleResult.success) {
console.log('Sale tracked:', saleResult.saleEventId)
}Utility Functions
import { isTrackingAvailable, getClickId } from '@li2/analytics'
// Check if a click ID is available for attribution
if (isTrackingAvailable()) {
console.log('Click ID:', getClickId())
}
// Use getClickId() to pass the click ID to your server for server-side tracking
const clickId = getClickId() // Returns null if no click ID is availableDashboard Overlays
The SDK includes two dashboard-powered overlays that your team can activate directly from the Li2 dashboard — no additional developer configuration required.
Heatmap Overlay
Visualize where users are clicking on any page. Activated from the Heatmap section of your dashboard via the "View on site" button. When activated, a floating toolbar appears on your page showing:
- A Gaussian KDE heatmap rendered over your live page
- Click counts and opacity controls
- Device type filtering (desktop / tablet / mobile)
The SDK detects the ?li2_heatmap URL parameter and automatically loads the heatmap module. No code changes needed.
Visual Event Tagger
Tag DOM elements as named events directly on your live site — without writing code. Activated from the Event Rules section of your dashboard via the "Tag Events on Site" button.
When active, hovering over any element highlights it. Clicking it opens a panel where you can name the event and save it as an event rule. Tagged events appear immediately in your funnel builder and analytics.
The SDK detects the ?li2_tagger URL parameter and loads the tagger module automatically.
Security note: Both overlays require a time-limited session token generated by the dashboard. Direct URL access without a valid token shows an error.
Server-Side SDK
The server-side SDK is for use in Node.js, Next.js API routes, server actions, and other backend environments. It requires an API key for authentication.
Passing Click ID from Client to Server
Unlike the client-side SDK, the server cannot auto-detect the click ID. You need to capture it on the client and include it in your server requests:
// Client-side: capture the click ID
import { getClickId } from '@li2/analytics'
const clickId = getClickId()
// Include clickId when calling your server
fetch('/api/checkout', {
method: 'POST',
body: JSON.stringify({ clickId, ...otherData }),
})Setup
import { initServer } from '@li2/analytics'
const li2 = initServer({
apiKey: 'li2_sk_...', // Your secret API key
debug: true, // optional: enable console logging
})Track Lead (Server-Side)
// clickId must be captured from the client and passed to your server
const result = await li2.trackLead({
clickId: 'abc123', // Required for server-side tracking
eventName: 'signup',
customerExternalId: 'user_123',
customerName: 'John Doe',
customerEmail: '[email protected]',
metadata: {
plan: 'pro',
source: 'landing_page',
},
})
if (result.success) {
console.log('Lead tracked:', result.customerId)
}Track Sale (Server-Side)
// Attributed sale — linked to a tracked visit
const result = await li2.trackSale({
clickId: 'abc123', // Click ID from the client
customerExternalId: 'user_123',
amount: 9900, // Amount in cents ($99.00)
eventName: 'subscription',
paymentProcessor: 'stripe',
invoiceId: 'inv_xyz789',
currency: 'usd',
metadata: {
plan: 'annual',
coupon: 'SAVE20',
},
})
if (result.success) {
console.log('Sale tracked:', result.saleEventId)
}Direct Sale (No Link Attribution)
For sales that happen without a tracked link (e.g., in-store, phone, manual entry), pass an explicit empty string for clickId:
const result = await li2.trackSale({
clickId: '', // Empty string = Direct Sale (no link attribution)
customerExternalId: 'user_123',
amount: 5000,
customerEmail: '[email protected]',
customerName: 'John Doe',
})Important:
clickIdmust be explicitly provided. Omitting it entirely returns an error. Pass""for Direct Sale or a valid click ID for attributed sale.
Next.js Example
// app/api/checkout/route.ts
import { initServer } from '@li2/analytics'
const li2 = initServer({ apiKey: process.env.LI2_API_KEY! })
export async function POST(request: Request) {
const { clickId, userId, amount, invoiceId } = await request.json()
// Track the sale after successful payment
// clickId from client, or "" for direct sale
const result = await li2.trackSale({
clickId: clickId ?? '',
customerExternalId: userId,
amount,
invoiceId,
paymentProcessor: 'stripe',
})
return Response.json({ success: result.success })
}API Reference
Client-Side
| Function | Description |
| -------- | ----------- |
| init(config) | Initialize the SDK with configuration |
| trackLead(params) | Track a lead conversion event |
| trackSale(params) | Track a sale conversion event |
| trackEvent(eventName, options?) | Track a named custom event |
| trackPageview(options?) | Manually track a pageview |
| identify(params) | Link an anonymous visitor to a known customer |
| isTrackingAvailable() | Check if click ID is available |
| getClickId() | Get the current click ID |
| enablePageviewTracking(config?) | Enable pageview tracking programmatically |
| enableClickTracking(options?) | Enable click tracking programmatically |
| pageview.disable() | Pause pageview tracking |
| pageview.enable() | Resume pageview tracking |
| pageview.newSession() | Force a new session |
Server-Side
| Function | Description |
| -------- | ----------- |
| initServer(config) | Create a server-side SDK instance |
| trackLead(params) | Track a lead (clickId required) |
| trackSale(params) | Track a sale (clickId required — pass "" for Direct Sale) |
| identify(params) | Link anonymous visitor to customer (clickId required) |
TrackLead Parameters
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| clickId | string | Server only | Click ID for attribution |
| eventName | string | Yes | Name of the lead event |
| customerExternalId | string | No | Your unique customer identifier |
| customerName | string | No | Customer's name |
| customerEmail | string | No | Customer's email |
| customerAvatar | string | No | URL to customer's avatar |
| metadata | object | No | Additional data (max 10,000 chars) |
TrackSale Parameters
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| clickId | string | Server only | Click ID for attribution. Pass "" for Direct Sale (no link). |
| customerExternalId | string | Yes | Your unique customer identifier |
| amount | number | Yes | Amount in smallest currency unit |
| eventName | string | No | Name of sale event (default: "Purchase") |
| paymentProcessor | string | No | Payment processor (e.g., "stripe") |
| invoiceId | string | No | Your invoice/transaction ID |
| currency | string | No | Currency code (default: "usd") |
| customerName | string | No | Customer's name |
| customerEmail | string | No | Customer's email |
| metadata | object | No | Additional data (max 10,000 chars) |
TrackEvent Parameters
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| eventName | string | Yes | Name of the event (e.g., "cta_clicked") |
| options.category | string | No | Event category for grouping |
EnableClickTracking Options
| Option | Type | Default | Description |
| ------ | ---- | ------- | ----------- |
| excludeSelector | string | null | CSS selector for elements to exclude |
| batchInterval | number | 5000 | Batch flush interval in ms |
| sessionTimeout | number | 30 | Session timeout in minutes |
| cookieLessMode | boolean | false | Use localStorage only (no cookies) |
| cookieDomain | string | — | Cookie domain for cross-subdomain tracking |
License
MIT
