Basic Usage#

Learn the fundamentals of tracking with @pulsora/core.

Quick Start#

import { Pulsora } from '@pulsora/core';

// Initialize
const pulsora = new Pulsora();
pulsora.init({ apiToken: 'your-token' });

// Track pageview
pulsora.pageview();

// Track event
pulsora.event('button_click', { button: 'signup' });

// Identify user
pulsora.identify('user_123');

Pageview Tracking#

Automatic Pageview Tracking#

By default, Pulsora automatically tracks:

  • Initial page load
  • Browser navigation (back/forward)
  • SPA route changes (pushState/replaceState)
// Automatic tracking is enabled by default
pulsora.init({
  apiToken: 'your-token',
  autoPageviews: true, // This is the default
});

Manual Pageview Tracking#

Track pageviews manually when needed:

// Simple pageview
pulsora.pageview();

// Pageview with custom data
pulsora.pageview({
  url: '/custom-path',
  title: 'Custom Page Title',
  referrer: 'https://google.com',
});

SPA Pageview Tracking#

For single-page applications:

// React Router example
import { useLocation } from 'react-router-dom';

function App() {
  const location = useLocation();

  useEffect(() => {
    pulsora.pageview();
  }, [location]);

  return <Routes>...</Routes>;
}
// Vue Router example
router.afterEach((to, from) => {
  pulsora.pageview({
    url: to.fullPath,
    referrer: from.fullPath,
  });
});

Virtual Pageviews#

Track interactions as pageviews:

// Modal view
pulsora.pageview({
  url: '/virtual/modal/signup',
  title: 'Signup Modal',
});

// Tab changes
pulsora.pageview({
  url: '/dashboard#analytics',
  title: 'Dashboard - Analytics Tab',
});

Event Tracking#

Basic Events#

Track any user interaction:

// Simple event
pulsora.event('video_play');

// Event with properties
pulsora.event('video_play', {
  video_id: 'abc123',
  video_title: 'Getting Started',
  duration: 180,
});

Common Event Patterns#

Button Clicks#

// Generic button tracking
document.querySelectorAll('button').forEach((button) => {
  button.addEventListener('click', () => {
    pulsora.event('button_click', {
      button_text: button.textContent,
      button_id: button.id,
      button_class: button.className,
    });
  });
});

// Specific CTA tracking
document.getElementById('signup-cta').addEventListener('click', () => {
  pulsora.event('cta_click', {
    cta_id: 'header_signup',
    cta_text: 'Start Free Trial',
    cta_location: 'header',
  });
});

Form Interactions#

// Form start
document.getElementById('contact-form').addEventListener(
  'focus',
  (e) => {
    if (e.target.tagName === 'INPUT') {
      pulsora.event('form_start', {
        form_id: 'contact',
        field: e.target.name,
      });
    }
  },
  true,
);

// Form submission
document.getElementById('contact-form').addEventListener('submit', (e) => {
  e.preventDefault();

  pulsora.event('form_submit', {
    form_id: 'contact',
    fields_filled: ['name', 'email', 'message'],
  });

  // Submit form...
});

// Form abandonment
window.addEventListener('beforeunload', () => {
  const form = document.getElementById('contact-form');
  const hasValue = Array.from(form.elements).some((el) => el.value);

  if (hasValue && !form.dataset.submitted) {
    pulsora.event('form_abandon', {
      form_id: 'contact',
    });
  }
});

E-commerce Events#

// Product view
pulsora.event('product_view', {
  product_id: 'SKU123',
  product_name: 'Premium Plan',
  product_category: 'Subscriptions',
  price: 99.99,
});

// Add to cart
pulsora.event('add_to_cart', {
  product_id: 'SKU123',
  product_name: 'Premium Plan',
  price: 99.99,
  quantity: 1,
});

// Checkout start
pulsora.event('checkout_start', {
  cart_total: 99.99,
  item_count: 1,
  currency: 'USD',
});

// Purchase (frontend tracking)
pulsora.event('purchase', {
  order_id: 'ORDER123',
  total: 99.99,
  currency: 'USD',
  items: [
    {
      product_id: 'SKU123',
      product_name: 'Premium Plan',
      price: 99.99,
    },
  ],
});

Content Engagement#

// Article read time
let startTime = Date.now();

window.addEventListener('beforeunload', () => {
  const timeSpent = Math.round((Date.now() - startTime) / 1000);

  pulsora.event('article_read', {
    article_id: 'post-123',
    time_spent: timeSpent,
    scroll_depth: getScrollDepth(),
  });
});

// Video engagement
const video = document.getElementById('promo-video');

video.addEventListener('play', () => {
  pulsora.event('video_play', {
    video_id: 'promo-2024',
    video_duration: video.duration,
  });
});

video.addEventListener('ended', () => {
  pulsora.event('video_complete', {
    video_id: 'promo-2024',
  });
});

// Download tracking
document.querySelectorAll('a[download]').forEach((link) => {
  link.addEventListener('click', () => {
    pulsora.event('file_download', {
      file_name: link.download,
      file_url: link.href,
      file_type: link.href.split('.').pop(),
    });
  });
});

Event Naming Conventions#

Follow consistent naming patterns:

// Good - snake_case, descriptive, action-oriented
pulsora.event('button_click');
pulsora.event('form_submit');
pulsora.event('video_play');
pulsora.event('page_scroll');

// Bad - inconsistent, vague
pulsora.event('ButtonClick');
pulsora.event('submit');
pulsora.event('vid');
pulsora.event('user did something');

Advanced Tracking Patterns#

Conversion Tracking#

// Track multi-step conversions
class ConversionTracker {
  constructor() {
    this.steps = [];
  }

  trackStep(stepName, data = {}) {
    this.steps.push(stepName);

    pulsora.event('conversion_step', {
      step_name: stepName,
      step_number: this.steps.length,
      ...data,
    });
  }

  complete(conversionType) {
    pulsora.event('conversion_complete', {
      conversion_type: conversionType,
      total_steps: this.steps.length,
      steps: this.steps,
    });
  }
}

// Usage
const signupTracker = new ConversionTracker();
signupTracker.trackStep('view_pricing');
signupTracker.trackStep('click_signup');
signupTracker.trackStep('fill_form');
signupTracker.trackStep('verify_email');
signupTracker.complete('signup');

Error Tracking#

// Global error handler
window.addEventListener('error', (event) => {
  pulsora.event('javascript_error', {
    message: event.error?.message || 'Unknown error',
    source: event.filename,
    line: event.lineno,
    column: event.colno,
    stack: event.error?.stack?.substring(0, 500),
  });
});

// Promise rejection handler
window.addEventListener('unhandledrejection', (event) => {
  pulsora.event('promise_rejection', {
    reason: String(event.reason).substring(0, 500),
    promise: String(event.promise),
  });
});

// API error tracking
async function apiCall(endpoint, options) {
  try {
    const response = await fetch(endpoint, options);

    if (!response.ok) {
      pulsora.event('api_error', {
        endpoint,
        status: response.status,
        statusText: response.statusText,
      });
    }

    return response;
  } catch (error) {
    pulsora.event('api_error', {
      endpoint,
      error: error.message,
    });
    throw error;
  }
}

Performance Tracking#

// Page load performance
window.addEventListener('load', () => {
  const perfData = performance.timing;
  const pageLoadTime = perfData.loadEventEnd - perfData.navigationStart;

  pulsora.event('page_performance', {
    page_load_time: pageLoadTime,
    dom_ready_time:
      perfData.domContentLoadedEventEnd - perfData.navigationStart,
    first_byte_time: perfData.responseStart - perfData.navigationStart,
  });
});

// Core Web Vitals
if ('PerformanceObserver' in window) {
  // Largest Contentful Paint
  new PerformanceObserver((list) => {
    const entries = list.getEntries();
    const lastEntry = entries[entries.length - 1];

    pulsora.event('web_vitals', {
      metric: 'LCP',
      value: lastEntry.renderTime || lastEntry.loadTime,
    });
  }).observe({ entryTypes: ['largest-contentful-paint'] });

  // First Input Delay
  new PerformanceObserver((list) => {
    const entry = list.getEntries()[0];

    pulsora.event('web_vitals', {
      metric: 'FID',
      value: entry.processingStart - entry.startTime,
    });
  }).observe({ entryTypes: ['first-input'] });
}

Best Practices#

1. Consistent Event Names#

// Create an events constants file
export const EVENTS = {
  // User events
  USER_SIGNUP: 'user_signup',
  USER_LOGIN: 'user_login',
  USER_LOGOUT: 'user_logout',

  // E-commerce events
  PRODUCT_VIEW: 'product_view',
  ADD_TO_CART: 'add_to_cart',
  PURCHASE: 'purchase',

  // Engagement events
  VIDEO_PLAY: 'video_play',
  ARTICLE_READ: 'article_read',
  SHARE: 'content_share',
};

// Use constants
pulsora.event(EVENTS.USER_LOGIN, { method: 'google' });

2. Meaningful Properties#

// Good - specific, measurable properties
pulsora.event('search', {
  query: 'analytics tools',
  results_count: 15,
  filters_used: ['price', 'features'],
  search_duration: 234,
});

// Bad - vague, unmeasurable properties
pulsora.event('search', {
  data: 'some search',
  success: true,
});

3. Avoid PII in Events#

// Good - use IDs, not personal info
pulsora.event('user_action', {
  user_id: 'user_123',
  account_type: 'premium',
});

// Bad - contains PII
pulsora.event('user_action', {
  email: 'john@example.com',
  full_name: 'John Doe',
  phone: '+1234567890',
});
// Track related events together
function trackCheckout(cart) {
  // Start checkout
  pulsora.event('checkout_start', {
    item_count: cart.items.length,
    total: cart.total,
  });

  // Track each step
  cart.items.forEach((item, index) => {
    pulsora.event('checkout_item', {
      position: index + 1,
      product_id: item.id,
      price: item.price,
      quantity: item.quantity,
    });
  });
}

Testing Your Implementation#

Enable Debug Mode#

pulsora.init({
  apiToken: 'your-token',
  debug: true,
});

// All tracking calls will be logged to console

Verify in Network Tab#

  1. Open Developer Tools
  2. Go to Network tab
  3. Filter by "ingest"
  4. Trigger events
  5. Inspect request payloads

Test Helper#

// Development testing helper
function testPulsora() {
  console.log('Testing Pulsora implementation...');

  // Test pageview
  pulsora.pageview({ title: 'Test Page' });

  // Test event
  pulsora.event('test_event', {
    timestamp: Date.now(),
    test: true,
  });

  // Test identification
  pulsora.identify('test_user_123');

  console.log('Is identified:', pulsora.isIdentified());
  console.log('Check Network tab for requests');
}

Next Steps#