Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.scanova.io/llms.txt

Use this file to discover all available pages before exploring further.

Custom events let you track specific user actions that matter to your business — beyond what auto-tracking captures. You define the event name and the metadata, and the SDK sends it with full QR attribution attached automatically.

Syntax

scanova('track', 'event_name', { key: 'value' });
  • event_name — a string that describes the action. Use snake_case.
  • metadata — an optional object with any key-value data relevant to the event. Max 10 KB.
You can call scanova('track', ...) at any point after scanova('init', ...) runs — from event listeners, async callbacks, or any other JavaScript context.

Examples

Button click

Track when a user clicks a specific call-to-action:
document.getElementById('start-trial-btn').addEventListener('click', () => {
  scanova('track', 'cta_click', {
    button_text: 'Start Free Trial',
    section: 'hero',
    plan: 'pro'
  });
});

Sign-up completed

Send this after your sign-up form submission is confirmed (client-side):
scanova('track', 'signup_completed', {
  method: 'email',
  plan: 'free'
});
For purchase or sign-up confirmations that happen server-side, use Server Events instead. Server events are more reliable and cannot be blocked by browser extensions.

Video engagement

video.addEventListener('play', () => {
  scanova('track', 'video_play', { video_id: 'intro-tour' });
});

video.addEventListener('ended', () => {
  scanova('track', 'video_complete', { video_id: 'intro-tour' });
});

Product interaction

document.querySelectorAll('.product-card').forEach(card => {
  card.addEventListener('click', () => {
    scanova('track', 'product_click', {
      product_id: card.dataset.productId,
      product_name: card.dataset.productName,
      position: card.dataset.position
    });
  });
});

Tab or accordion interaction

document.querySelectorAll('.tab-btn').forEach(btn => {
  btn.addEventListener('click', () => {
    scanova('track', 'tab_click', { tab_name: btn.textContent.trim() });
  });
});
document.querySelectorAll('a[href^="http"]').forEach(link => {
  link.addEventListener('click', () => {
    scanova('track', 'external_link_click', { destination: link.href });
  });
});

Choosing between custom events and auto-tracking

SituationUse
Track all link and button clicks with minimal setupautoClicks: true
Track a specific button with custom metadatascanova('track', ...)
Track all form submissionsautoForms: true
Track a specific form with field-level context (non-PII)scanova('track', ...)
Any interaction the auto-tracker does not coverscanova('track', ...)
You can use both together — autoClicks: true plus selective custom events for high-value actions.

Event naming best practices

  • Use snake_case: cta_click, not ctaClick or CTAClick
  • Be specific enough to be self-explanatory in reports: signup_completed is better than completed
  • Be consistent: pick one name and stick to it. Changing event names later fragments your historical data
  • Do not include user-identifying information in the event name

Metadata best practices

  • Keep metadata flat where possible — deeply nested objects are harder to query
  • Max object size: 10 KB
  • Max nesting depth: 5 levels
  • Never include raw email addresses, phone numbers, or other PII — use server events with user_identifiers for that
  • Use stable keys — changing key names later fragments your data
// Good
scanova('track', 'download_click', {
  file_name: 'product-guide.pdf',
  section: 'resources'
});

// Avoid
scanova('track', 'download_click', {
  user_email: 'john@example.com',  // never include PII
  data: { nested: { too: { deep: { for: 'queries' } } } }
});

When to use server events instead

Use Server-Side Events rather than custom browser events when:
  • The action happens on your server (payment confirmation, CRM creation, email verification)
  • You need to pass a conversion value (order total, subscription price)
  • You want to include hashed user identifiers for identity matching
  • You need guaranteed delivery (server events cannot be blocked by ad blockers)