@pulsora/core
The core Pulsora package provides privacy-first analytics tracking for web browsers. It handles pageviews, custom events, and user identification without cookies or personal data collection.
When to Use Core Package
Choose @pulsora/core when you:
- Build with vanilla JavaScript - No framework required
- Need maximum flexibility - Direct control over all tracking calls
- Use non-React frameworks - Vue, Svelte, Angular, etc.
- Want minimal bundle size - ~2KB with zero dependencies
- Integrate server-side - Node.js, Deno, edge functions
- Build browser extensions - Lightweight and framework-agnostic
Use @pulsora/react instead if you're building a React application and want hooks like usePageview() and useEvent() - see React package comparison.
Core vs React Package
| Feature | @pulsora/core | @pulsora/react |
|---|---|---|
| Framework | Any (vanilla JS) | React only |
| Bundle size | 2.99KB gzipped | 3.8KB gzipped |
| TypeScript | ✅ Full support | ✅ Full support |
| Tracking API | Imperative | Hooks + Imperative |
| Router integration | Manual | Automatic |
| Learning curve | Simple | Requires React knowledge |
Example comparison:
// @pulsora/core (any framework)
import { Pulsora } from '@pulsora/core';
const pulsora = new Pulsora();
pulsora.init({ apiToken: 'pub_xxx' });
pulsora.pageview();
pulsora.event('click');
// @pulsora/react (React apps)
import { usePageview, useEvent } from '@pulsora/react';
function MyComponent() {
usePageview(); // Automatic on mount
const trackEvent = useEvent();
return <button onClick={() => trackEvent('click')}>Click</button>;
}
Learn more about React package →
Features
🔒 Privacy-First Design
- No cookies - Uses in-memory session storage
- No localStorage - All data is ephemeral by default
- Server-side visitor IDs - Backend generates anonymous identifiers
- GDPR compliant - Privacy by design
⚡ Performance
- ~2KB gzipped - Minimal impact on bundle size
- Async loading - Non-blocking script execution
- SendBeacon API - Reliable data transmission
- Automatic retries - Exponential backoff for failed requests
🎯 Automatic Tracking
- SPA support - Tracks route changes automatically
- Pageview tracking - Zero configuration required
- Referrer detection - Automatic source attribution
- Session management - 30-minute inactivity timeout
🔧 Developer Experience
- TypeScript support - Full type definitions included
- Framework agnostic - Works with any JavaScript framework
- Extensible - Plugin system for custom functionality
- Debug mode - Detailed console logging
How It Works
1. Server-Side Visitor Identification
When a visitor loads your site, Pulsora's backend generates an anonymous visitor identifier using:
fingerprint = SHA256(IP_Address + User_Agent + Website_ID + Salt)
This identifier is:
- ✅ Generated entirely server-side
- ✅ Anonymous (IP/UA never stored raw)
- ✅ Temporary (expires with salt rotation)
- ✅ GDPR compliant (pseudonymization)
The client receives this identifier and includes it with all tracking requests. No client-side fingerprinting techniques (Canvas, WebGL, Audio) are used.
Learn more about server-side fingerprinting →
2. Session Management
Sessions are managed entirely in memory:
- New session on first visit
- 30-minute inactivity timeout
- Persists across page navigation
- Resets on browser close
3. Event Tracking
All events include:
- Visitor fingerprint
- Session ID
- Timestamp
- Page URL
- Referrer
- Custom properties
Installation
Choose your preferred installation method:
NPM (Recommended for Apps)
npm install @pulsora/core
import { Pulsora } from '@pulsora/core';
const pulsora = new Pulsora();
pulsora.init({ apiToken: 'your-token' });
CDN (Recommended for Websites)
<script
async
src="https://cdn.pulsora.co/v1/pulsora.min.js"
data-token="your-token"
></script>
Basic Usage
Track Pageviews
Pageviews are tracked automatically by default, but you can also track them manually:
// Automatic (default behavior)
pulsora.init({
apiToken: 'your-token',
autoPageviews: true, // This is the default
});
// Manual tracking
pulsora.pageview();
// With custom properties
pulsora.pageview({
title: 'Custom Page Title',
url: '/custom-path',
referrer: 'https://google.com',
});
Track Events
Track any custom event with optional properties:
// Simple event
pulsora.event('video_play');
// Event with properties
pulsora.event('purchase', {
product: 'Pro Plan',
price: 99,
currency: 'USD',
});
// Form submissions
pulsora.event('form_submit', {
form_id: 'contact',
fields: ['name', 'email', 'message'],
});
Advanced Usage
Multiple Trackers
Create separate trackers for different purposes:
// Main website tracker
const mainTracker = new Pulsora();
mainTracker.init({ apiToken: 'main-token' });
// Blog tracker
const blogTracker = new Pulsora();
blogTracker.init({ apiToken: 'blog-token' });
// Track to specific tracker
mainTracker.event('main_site_event');
blogTracker.event('blog_event');
Get Tracking Data
Access fingerprint and session data for server-side attribution:
// Get visitor fingerprint (async)
const fingerprint = await pulsora.getVisitorFingerprint();
// Get session ID (sync)
const sessionId = pulsora.getSessionId();
// Use for payment attribution
fetch('/api/checkout', {
method: 'POST',
body: JSON.stringify({
product_id: 'pro-plan',
visitor_fingerprint: fingerprint,
session_id: sessionId,
}),
});
Custom Configuration
pulsora.init({
apiToken: 'your-token',
endpoint: 'https://custom.endpoint.com/ingest', // Custom endpoint
autoPageviews: false, // Disable automatic pageview tracking
debug: true, // Enable debug logging
maxRetries: 5, // Maximum retry attempts
retryBackoff: 2000, // Initial retry delay in ms
});
Browser Compatibility
Pulsora supports all modern browsers:
- ✅ Chrome/Edge (last 2 versions)
- ✅ Firefox (last 2 versions)
- ✅ Safari (last 2 versions)
- ✅ iOS Safari
- ✅ Chrome for Android
Bundle Size
The core package is optimized for minimal impact:
- Minified: 8.5KB
- Gzipped: 2.99KB
- Brotli: 2.7KB
Security Considerations
API Token Security
- Use public tokens only (never secret tokens in browser)
- Tokens are scoped to specific domains
- Rate limiting prevents abuse
Data Privacy
- No personal data is collected
- All data is anonymous by default
- User consent not required (no cookies)
- Right to deletion supported
Real-World Use Cases
SaaS Product Analytics
// Track feature usage in your dashboard
const pulsora = new Pulsora();
pulsora.init({ apiToken: 'pub_xxx' });
// Track page visits
pulsora.pageview();
// Track feature interactions
document.querySelector('#export-btn').addEventListener('click', () => {
pulsora.event('feature_used', {
feature: 'data_export',
format: 'csv',
});
});
// Track login events
function handleLogin(user) {
pulsora.event('user_login', {
plan: user.subscription_plan,
});
}
E-commerce Product Tracking
// Track product views
function trackProductView(product) {
pulsora.event('product_view', {
product_id: product.id,
category: product.category,
price: product.price,
});
}
// Track add to cart
function addToCart(product) {
pulsora.event('add_to_cart', {
product_id: product.id,
quantity: 1,
value: product.price,
});
}
// Send fingerprint with checkout for attribution
async function checkout(cart) {
const fingerprint = await pulsora.getVisitorFingerprint();
await fetch('/api/checkout', {
method: 'POST',
body: JSON.stringify({
items: cart.items,
visitor_fingerprint: fingerprint,
session_id: pulsora.getSessionId(),
}),
});
}
Vue.js Application
// plugins/pulsora.js
import { Pulsora } from '@pulsora/core';
export default {
install(app, options) {
const pulsora = new Pulsora();
pulsora.init({ apiToken: options.apiToken });
// Make available globally
app.config.globalProperties.$pulsora = pulsora;
app.provide('pulsora', pulsora);
// Track route changes
if (options.router) {
options.router.afterEach((to, from) => {
pulsora.pageview({
url: to.fullPath,
title: to.meta.title || document.title,
referrer: from.fullPath,
});
});
}
},
};
// main.js
import { createApp } from 'vue';
import router from './router';
import pulsoraPlugin from './plugins/pulsora';
const app = createApp(App);
app.use(pulsoraPlugin, {
apiToken: 'pub_xxx',
router,
});
Browser Extension
// background.js
import { Pulsora } from '@pulsora/core';
const pulsora = new Pulsora();
pulsora.init({
apiToken: 'pub_xxx',
endpoint: 'https://api.pulsora.co/ingest',
});
// Track extension installation
chrome.runtime.onInstalled.addListener((details) => {
if (details.reason === 'install') {
pulsora.event('extension_installed');
} else if (details.reason === 'update') {
pulsora.event('extension_updated', {
previous_version: details.previousVersion,
});
}
});
// Track feature usage
chrome.action.onClicked.addListener(() => {
pulsora.event('toolbar_icon_clicked');
});
Troubleshooting
Tracker Not Initializing
Symptoms:
pulsora.event()doesn't send data- No network requests to pulsora.co
- Console shows "Pulsora not initialized"
Solutions:
- Ensure
init()is called before tracking:
// ❌ Wrong - tracking before init
const pulsora = new Pulsora();
pulsora.event('click'); // Won't work!
pulsora.init({ apiToken: 'pub_xxx' });
// ✅ Correct - init first, then track
const pulsora = new Pulsora();
pulsora.init({ apiToken: 'pub_xxx' });
pulsora.event('click'); // Works!
- Wait for async init to complete:
const pulsora = new Pulsora();
await pulsora.init({ apiToken: 'pub_xxx' });
// Now ready to track
Duplicate Pageviews
Cause: Auto-pageview tracking enabled + manual pageview calls
Solution:
// Option 1: Disable auto-tracking
pulsora.init({
apiToken: 'pub_xxx',
autoPageviews: false, // Manual control
});
// Then track manually
pulsora.pageview();
// Option 2: Keep auto-tracking, don't call pageview() manually
pulsora.init({
apiToken: 'pub_xxx',
autoPageviews: true, // Let Pulsora handle it
});
// No manual pageview() calls needed
Events Not Showing in Dashboard
Debugging checklist:
- Enable debug mode:
pulsora.init({
apiToken: 'pub_xxx',
debug: true, // See console logs
});
// Console will show:
// [Pulsora] Initialized with token: pub_xxx
// [Pulsora] Event tracked: button_click
// [Pulsora] Request sent: 200 OK
- Check API token format:
// ❌ Wrong - using secret token
apiToken: 'sec_xxx'; // Don't use in browser!
// ✅ Correct - using public token
apiToken: 'pub_xxx';
- Verify domain whitelist:
- Go to Dashboard → Settings → Websites
- Add your domain (e.g.,
example.com) - Include subdomains if needed (e.g.,
*.example.com)
- Check network requests:
// Open DevTools → Network tab
// Filter by "pulsora" or "ingest"
// Look for POST requests with status 200
// If you see 403 errors:
// - Check API token is correct
// - Verify domain is whitelisted
// If you see 429 errors:
// - Rate limit exceeded
// - Wait a few minutes or contact support
TypeScript Type Errors
Error: Property 'init' does not exist on type 'Pulsora'
Solution:
// Ensure you're importing from the correct package
import { Pulsora } from '@pulsora/core'; // ✅ Correct
import { Pulsora } from 'pulsora'; // ❌ Wrong package name
// If using CDN with TypeScript:
// Create types/pulsora.d.ts
import type { PulsoraCore } from '@pulsora/core';
declare global {
interface Window {
pulsora: PulsoraCore;
}
}
export {};
getVisitorFingerprint() Returns Undefined
Cause: Fingerprint generation is async
Solution:
// ❌ Wrong - fingerprint not ready yet
const fingerprint = pulsora.getVisitorFingerprint();
console.log(fingerprint); // undefined
// ✅ Correct - await the promise
const fingerprint = await pulsora.getVisitorFingerprint();
console.log(fingerprint); // "abc123def456..."
// Or use .then()
pulsora.getVisitorFingerprint().then((fingerprint) => {
console.log(fingerprint);
});
Next Steps
- Installation Guide - Detailed setup instructions for NPM and CDN
- Configuration Options - All available settings and options
- Usage Guide - Comprehensive tracking examples
- API Reference - Complete method documentation
- React Package - If you're using React
- Revenue Tracking - Attribute purchases to visitors