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',
});
4. Batch Related Events
// 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
- Open Developer Tools
- Go to Network tab
- Filter by "ingest"
- Trigger events
- 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
- API Reference - Complete method documentation
- Session Management - How visitor identification works
- SPA Support - Single-page app integration
- Examples - Real-world implementations