Skip to main content

Events Tracking Guide

In this guide: Learn how to use the Li2 Analytics SDK to track lead events (signups, form submissions) and sale events (purchases, subscriptions) with real-world examples.

Prerequisites

Before tracking events, ensure you have:

SDK Installed

Completed the Setup Guide and installed Li2 Analytics SDK

Tracking Enabled

Enabled conversion tracking for your touchpoint in Settings

Lead Tracking

A lead event marks when a customer shows genuine interest in your product or service. This is a critical middle step between visit and sale.

When to Track Leads?

When customers fill out contact forms, request consultations, or ask for demos.Examples: “Contact us” forms, “Schedule demo” forms, “Get a quote”
When customers create new accounts or sign up for trials.Examples: Free plan signup, Start trial, Create account
When customers subscribe to newsletters or email updates.Examples: Subscribe to newsletter, Get blog updates
When customers perform high-intent actions.Examples: Add to cart, Download whitepaper, View pricing page

How to Track Leads

Use when: Tracking directly in the browser after user submits a form or signs up.
// After user successfully submits a form
li2Analytics.trackLead({
  eventName: "Contact Form Submitted",
  customerExternalId: "user_12345", // Your internal user ID
  customerEmail: "[email protected]",
  customerName: "John Doe",
  metadata: {
    formType: "contact",
    message: "Interested in premium plan",
    source: "landing_page"
  }
})
.then(result => {
  if (result.success) {
    console.log('Lead tracked!', result.customerId);
  } else {
    console.error('Failed:', result.message);
  }
});
Automatic Click ID: The SDK automatically retrieves the click ID from the li_cid cookie - you don’t need to pass it manually.

Lead Parameters

ParameterTypeRequiredDescription
eventNamestringName of the lead event (e.g., “Signup”, “Contact Form”)
customerExternalIdstringCustomer ID in your system
customerEmailstringCustomer email (recommended)
customerNamestringCustomer name
customerAvatarstringAvatar URL
metadataobjectAdditional data (max 10,000 chars)
clickIdstringServer onlyClick ID (only needed for server-side tracking)
Best Practice for customerExternalId: Use a persistent and unique ID:
  • ✅ User ID from database: "user_12345"
  • ✅ Email if no account yet: "[email protected]"
  • ❌ Session ID (not persistent): "sess_abc123"
This ID is used to link lead → sale events for the same customer.

Sale Tracking

A sale event marks successful conversion - the customer has completed a purchase transaction.

When to Track Sales?

When customers complete payment and the order is confirmed.Timing: After payment processor confirms success (webhook from Stripe, PayPal, etc.)
When customers subscribe to a paid plan (monthly/annual).Timing: After first payment succeeds or trial converts to paid
When customers pay for services (consulting, booking, etc.).Timing: After payment confirmed or booking confirmed with payment

How to Track Sales

Use when: Tracking immediately after checkout success on thank-you page.
// On Thank You Page after successful checkout
li2Analytics.trackSale({
  customerExternalId: "user_12345",
  amount: 4999, // $49.99 in cents
  eventName: "Product Purchase",
  currency: "usd",
  invoiceId: "inv_abc123", // Unique invoice ID
  paymentProcessor: "stripe",
  customerEmail: "[email protected]",
  customerName: "John Doe",
  metadata: {
    productId: "prod_premium",
    productName: "Premium Plan - Annual",
    discount: "SAVE20"
  }
})
.then(result => {
  if (result.success) {
    console.log('Sale tracked!', result.saleEventId);
  }
});
Amount Format: ALWAYS use the smallest currency unit (cents, pence, etc.)
  • 4999 (means $49.99)
  • 49.99 (will be interpreted as $0.4999)

Sale Parameters

ParameterTypeRequiredDescription
customerExternalIdstringCustomer ID (must match lead event)
amountnumberAmount (smallest unit: cents, pence)
eventNamestringSale event name (default: “Purchase”)
currencystringCurrency code (default: “usd”)
invoiceIdstringInvoice/transaction ID (for deduplication)
paymentProcessorstringPayment processor (“stripe”, “paypal”, etc.)
customerEmailstringEmail (auto-creates customer if not found)
customerNamestringCustomer name
metadataobjectAdditional data (max 10,000 chars)
clickIdstringServer onlyClick ID (only needed for server-side tracking)
Multi-currency Support: Li2 currently supports revenue tracking in 2 currencies:
  • USD (US Dollar): currency: "usd"
  • VND (Vietnamese Dong): currency: "vnd"
  • Li2 automatically converts to your organization’s default currency for total revenue calculation
  • Original currency is preserved in event data

Common Use Cases

Funnel: Visit → Trial Signup → Paid Subscription

Step 1: User clicks touchpoint link
Li2 automatically captures click ID and saves to cookie
Step 2: User signs up for trial (Lead Event)
// After signup form successfully submits
li2Analytics.trackLead({
  eventName: "Trial Signup",
  customerExternalId: newUser.id,
  customerEmail: newUser.email,
  customerName: newUser.name,
  metadata: {
    plan: "pro_trial",
    trialDays: 14
  }
});
Step 3: User subscribes after trial (Sale Event)
// In Stripe webhook handler
await li2.trackSale({
  clickId: savedClickId, // Saved during signup
  customerExternalId: user.id,
  amount: 2900, // $29/month
  currency: "usd",
  eventName: "Subscription Started",
  paymentProcessor: "stripe",
  invoiceId: invoice.id,
  metadata: {
    plan: "pro_monthly",
    billingInterval: "month"
  }
});

Best Practices

CRITICAL: Use the SAME customerExternalId for both lead and sale events for the same customer.
// ✅ CORRECT: Same ID
trackLead({ customerExternalId: "user_123", ... })
trackSale({ customerExternalId: "user_123", ... })

// ❌ WRONG: Different IDs
trackLead({ customerExternalId: "user_123", ... })
trackSale({ customerExternalId: "order_456", ... }) // Li2 can't link them
Why: Li2 uses customerExternalId to link lead → sale and aggregate metrics.
When webhooks retry (Stripe, PayPal typically retry on timeout), invoiceId helps Li2 prevent duplicates within a 7-day window:
trackSale({
  invoiceId: "inv_abc123", // Unique per transaction
  amount: 4999,
  // ...
});
How it works:
  • Within 7 days: Li2 caches and returns the old response, no duplicate created
  • After 7 days: Cache expires, may create a new sale event if sent again
Use case: Sufficient to handle common webhook retries (Stripe retries within 72h). Not permanent deduplication.
Store additional information in metadata for later analysis:
metadata: {
  // Campaign tracking
  utm_source: "facebook",
  utm_campaign: "summer_sale",

  // Product details
  productCategory: "electronics",
  sku: "PROD-123",

  // Customer insights
  isReturningCustomer: true,
  customerSegment: "vip"
}
Metadata limit: 10,000 characters (JSON stringified)
Tracking failures shouldn’t block user experience:
try {
  const result = await li2Analytics.trackSale({...});
  if (!result.success) {
    // Log error but DON'T show to user
    console.error('Tracking failed:', result.message);
    // Optionally: retry or log to error tracking service
  }
} catch (error) {
  console.error('Tracking error:', error);
  // User still sees purchase success message
}

Utility Functions

Li2 Analytics SDK provides helper functions:

isTrackingAvailable()

Check if a click ID is available (did the user come from a tracked link):
if (li2Analytics.isTrackingAvailable()) {
  // User came from a Li2 touchpoint
  trackLead({...});
} else {
  // User came from direct traffic or other sources
  // Skip tracking or handle differently
}

getClickId()

Get the current click ID (useful when you need to send it to your server):
const clickId = li2Analytics.getClickId();

if (clickId) {
  // Send to server for later tracking
  await fetch('/api/save-lead', {
    method: 'POST',
    body: JSON.stringify({ clickId, ...formData })
  });
}

Troubleshooting

Checklist:
  1. Verify response: Check console or Network tab
    const result = await trackLead({...});
    console.log(result); // { success: true/false, message: ... }
    
  2. Click ID available?
    console.log('Click ID:', li2Analytics.getClickId());
    // If null → user didn't come from tracked link
    
  3. Touchpoint has conversion tracking enabled?
    • Go to touchpoint Settings → Conversion Tracking must be ON
  4. Allowed hostnames configured?
    • Settings → Analytics → Allowed Hostnames must include current domain
  5. Publishable key correct?
    • Verify key in script tag matches Settings → Analytics
// ❌ Missing customerExternalId
trackLead({
  eventName: "Signup"
  // customerExternalId: ... <- MISSING
});

// ✅ Fixed
trackLead({
  eventName: "Signup",
  customerExternalId: user.id // REQUIRED
});
Common cause: customerExternalId doesn’t match.
// Lead event
trackLead({ customerExternalId: "user_123", ... })

// Sale event - MUST USE SAME ID
trackSale({ customerExternalId: "user_123", ... }) // ✅
trackSale({ customerExternalId: "order_456", ... }) // ❌
Verify: Check customer profile in dashboard to see if it has both lead and sale events.
Check amount format: Must use smallest currency unit
// ❌ WRONG
trackSale({ amount: 49.99, currency: "usd" }) // → $0.49 (!!)

// ✅ CORRECT
trackSale({ amount: 4999, currency: "usd" }) // → $49.99
VND Example:
// ✅ CORRECT
trackSale({ amount: 500000, currency: "vnd" }) // → 500,000 VND
Server cannot auto-detect click ID. You MUST capture it from the client:
// ❌ WRONG: Server-side tracking without clickId
li2.trackLead({
  eventName: "Signup",
  customerExternalId: "user_123"
  // clickId: ... <- MISSING
});

// ✅ CORRECT: Capture from client, send to server
// Client:
const clickId = li2Analytics.getClickId();
fetch('/api/signup', {
  body: JSON.stringify({ clickId, ...data })
});

// Server:
li2.trackLead({
  clickId: clickId, // From client
  eventName: "Signup",
  customerExternalId: "user_123"
});

Next Steps