Debugging Guide
When events aren't showing up in your Pulsora dashboard, use these systematic debugging steps to diagnose and fix the issue quickly.
Quick Diagnosis Checklist
Before diving deep, check these common issues:
- Debug mode enabled in browser console
- Network requests reaching
pulsora.co/api/ingestwith 202 response - Correct API token being used (public
pub_for frontend, secretsec_for backend) - Domain whitelisted in Pulsora dashboard settings
- No ad blockers or privacy extensions blocking requests
- CSP headers allow connections to pulsora.co
1. Enable Debug Mode
const pulsora = new Pulsora();
pulsora.init({
apiToken: 'pub_123',
debug: true,
});
Debug mode logs every pageview, event, identify, retry, and failure:
[Pulsora] Initialized
[Pulsora] Pageview tracked: /pricing
[Pulsora] Retry in 1000ms (attempt 2)
Disable debug in production to avoid noisy consoles.
2. Check the Network Tab
- Filter requests by
ingest. - Ensure
POST https://pulsora.co/api/ingestreturns202. - Open a request to confirm the payload contains the right event name and metadata.
If you see net::ERR_BLOCKED_BY_CLIENT, an ad blocker is interfering. Pulsora uses a neutral domain, but some users run aggressive blocklists—see fallback strategies below.
3. Verify CSP Configuration
If requests are blocked by Content-Security-Policy:
connect-src https://pulsora.co;
script-src https://cdn.pulsora.co;
4. Monitor Retry Logs
Retries usually point to transient outages or missing tokens:
[Pulsora] Send failed HTTP 401
Double-check that you use the correct public token in the frontend and secret token on the backend.
5. React Hook Issues
usePulsoraundefined — Confirm the component is wrapped by<PulsoraProvider>.- Duplicate pageviews — Ensure
usePageviewis invoked once per navigation (e.g., a top-level analytics bridge).
6. Backend Troubleshooting
- Check server logs for
Revenueexceptions (validation errors list missing fields). - If a webhook handler fails, respond with non-2xx and let the payment processor retry after you fix the issue.
- Confirm that the backend sends requests with
X-API-Token: sec_....
7. Ad Blockers & Privacy Extensions
- Pulsora URLs are intentionally neutral, but some extensions block any analytics endpoint.
- Mitigation options:
- Use server-side tracking for critical events (e.g., call
/api/ingestfrom your backend). - Provide fallbacks in your product analytics dashboards (e.g., flag
blocked_by_clienterrors).
- Use server-side tracking for critical events (e.g., call
8. Platform-Specific Debugging
Next.js Debugging
App Router (Next.js 13+):
// app/providers.tsx
'use client';
import { PulsoraProvider } from '@pulsora/react';
import { useEffect } from 'react';
export function Providers({ children }) {
// Debug: Check if provider mounts
useEffect(() => {
console.log('[Debug] PulsoraProvider mounted');
console.log(
'[Debug] API Token:',
process.env.NEXT_PUBLIC_PULSORA_TOKEN?.slice(0, 10) + '...',
);
}, []);
return (
<PulsoraProvider
config={{
apiToken: process.env.NEXT_PUBLIC_PULSORA_TOKEN!,
debug: true, // Enable for development
}}
>
{children}
</PulsoraProvider>
);
}
Common Next.js issues:
- Environment variables not available:
# ❌ Wrong - not accessible in browser
PULSORA_TOKEN=pub_xxx
# ✅ Correct - prefix with NEXT_PUBLIC_
NEXT_PUBLIC_PULSORA_TOKEN=pub_xxx
- Hydration mismatches:
// Use 'use client' directive
'use client';
import { usePageview } from '@pulsora/react';
function Analytics() {
usePageview(); // Safe on client
return null;
}
- Route changes not tracked:
// Add pageview tracker at root layout
'use client';
import { usePathname } from 'next/navigation';
import { usePageview } from '@pulsora/react';
import { useEffect } from 'react';
export function PageviewTracker() {
const pathname = usePathname();
useEffect(() => {
console.log('[Debug] Route changed:', pathname);
}, [pathname]);
usePageview({ trigger: pathname });
return null;
}
React Debugging
Hook order issues:
// ❌ Wrong - hooks called conditionally
function MyComponent({ isEnabled }) {
if (isEnabled) {
const trackEvent = useEvent(); // Breaks React rules!
}
}
// ✅ Correct - hooks at top level
function MyComponent({ isEnabled }) {
const trackEvent = useEvent();
if (isEnabled) {
// Use the hook result conditionally
trackEvent('feature_enabled');
}
}
Provider context issues:
// Debug: Check if provider is accessible
import { usePulsora } from '@pulsora/react';
function DebugComponent() {
try {
const pulsora = usePulsora();
console.log('[Debug] Pulsora instance:', pulsora);
console.log('[Debug] Is initialized:', !!pulsora);
} catch (error) {
console.error('[Debug] Provider error:', error);
}
return null;
}
Vue.js Debugging
// plugins/pulsora.js
import { Pulsora } from '@pulsora/core';
export default {
install(app, options) {
console.log('[Debug] Installing Pulsora plugin');
console.log('[Debug] API Token:', options.apiToken?.slice(0, 10) + '...');
const pulsora = new Pulsora();
pulsora.init({
apiToken: options.apiToken,
debug: true,
});
// Make available globally
app.config.globalProperties.$pulsora = pulsora;
// Debug: Test tracking
console.log('[Debug] Testing event tracking...');
pulsora.event('plugin_installed');
},
};
9. Common Error Messages
"Failed to fetch"
Error in console:
POST https://pulsora.co/api/ingest net::ERR_FAILED
Causes:
- No internet connection
- Ad blocker or privacy extension
- Corporate firewall blocking analytics domains
- CSP blocking the request
Solutions:
// 1. Test basic connectivity
fetch('https://pulsora.co/api/ingest', {
method: 'HEAD',
})
.then(() => {
console.log('[Debug] Can reach Pulsora API');
})
.catch((err) => {
console.error('[Debug] Cannot reach Pulsora:', err);
});
// 2. Check for ad blockers
if (
typeof window.pulsora === 'undefined' &&
window.location.hostname !== 'localhost'
) {
console.warn('[Debug] Pulsora may be blocked by ad blocker');
}
// 3. Server-side tracking fallback
async function trackEventWithFallback(eventName, props) {
try {
// Try client-side first
await pulsora.event(eventName, props);
} catch (error) {
// Fall back to server-side endpoint
await fetch('/api/track', {
method: 'POST',
body: JSON.stringify({ event: eventName, props }),
});
}
}
"Invalid API token"
Error: 401 Unauthorized or 403 Forbidden
Debug steps:
// Check token format
const token = process.env.NEXT_PUBLIC_PULSORA_TOKEN;
console.log('[Debug] Token format:', {
exists: !!token,
length: token?.length,
prefix: token?.slice(0, 4),
isPublic: token?.startsWith('pub_'),
isSecret: token?.startsWith('sec_'),
});
// Frontend should use public tokens
if (!token?.startsWith('pub_')) {
console.error('[Debug] Frontend should use public token (pub_xxx)');
}
"net::ERR_BLOCKED_BY_CLIENT"
Error: Request blocked by browser extension
Detection:
// Detect ad blocker
async function detectAdBlocker() {
const testUrl = 'https://pulsora.co/api/ingest';
try {
await fetch(testUrl, { method: 'HEAD', mode: 'no-cors' });
console.log('[Debug] No ad blocker detected');
return false;
} catch (error) {
if (error.message.includes('blocked')) {
console.warn('[Debug] Ad blocker detected!');
return true;
}
throw error;
}
}
// Use on app startup
detectAdBlocker().then((isBlocked) => {
if (isBlocked) {
// Show message or use server-side tracking
console.log('[Debug] Switching to server-side tracking');
}
});
Mitigation:
// Server-side tracking proxy
// app/api/track/route.ts
import { Pulsora } from '@pulsora/core';
const pulsora = new Pulsora();
pulsora.init({
apiToken: process.env.PULSORA_PUBLIC_TOKEN!,
// Use custom endpoint to bypass blockers
endpoint: process.env.PULSORA_ENDPOINT
});
export async function POST(req: Request) {
const { event, props, fingerprint, sessionId } = await req.json();
await pulsora.event(event, props);
return Response.json({ success: true });
}
10. Performance Debugging
Slow Initialization
Issue: Pulsora takes too long to initialize
Debug:
console.time('[Debug] Pulsora Init');
const pulsora = new Pulsora();
await pulsora.init({
apiToken: 'pub_xxx',
debug: true,
});
console.timeEnd('[Debug] Pulsora Init');
// Should complete in <100ms typically
Optimization:
// Use dynamic import for code splitting
async function initAnalytics() {
const { Pulsora } = await import('@pulsora/core');
const pulsora = new Pulsora();
await pulsora.init({ apiToken: 'pub_xxx' });
return pulsora;
}
// Initialize on user interaction or after page load
document.addEventListener('DOMContentLoaded', () => {
setTimeout(() => initAnalytics(), 1000);
});
High Network Usage
Issue: Too many requests to Pulsora API
Debug:
// Count Pulsora requests
let requestCount = 0;
const originalFetch = window.fetch;
window.fetch = function (...args) {
if (args[0]?.includes('pulsora.co')) {
requestCount++;
console.log(`[Debug] Pulsora request #${requestCount}:`, args);
}
return originalFetch.apply(this, args);
};
// Check after 30 seconds
setTimeout(() => {
console.log(`[Debug] Total Pulsora requests: ${requestCount}`);
// Should be <10 for typical single-page app
}, 30000);
Common causes:
- Multiple
usePageview()calls - Event tracking in render loop
Fix:
// ❌ Wrong - tracks on every render
function Component() {
const trackEvent = useEvent();
trackEvent('page_view'); // Runs every render!
}
// ✅ Correct - tracks once on mount
function Component() {
usePageview(); // Tracks once
}
11. Production Debugging
Enable Selective Debug Mode
Only enable debug mode for admins or specific users:
const isDev = process.env.NODE_ENV === 'development';
const isAdmin = user?.role === 'admin';
const debugParam = new URLSearchParams(window.location.search).has('debug');
pulsora.init({
apiToken: 'pub_xxx',
debug: isDev || isAdmin || debugParam,
});
Monitor Failed Requests
// Log failed tracking attempts
const pulsora = new Pulsora();
// Wrap methods to catch errors
const originalEvent = pulsora.event.bind(pulsora);
pulsora.event = async function (name, props) {
try {
await originalEvent(name, props);
} catch (error) {
// Send to error tracking service
console.error('[Pulsora Error]', { name, props, error });
errorTracker.captureException(error, {
extra: { event: name, props },
});
}
};
Health Check Endpoint
// app/api/health/analytics/route.ts
import { Pulsora } from '@pulsora/core';
export async function GET() {
const pulsora = new Pulsora();
try {
await pulsora.init({
apiToken: process.env.PULSORA_PUBLIC_TOKEN!
});
// Test tracking
await pulsora.event('health_check');
return Response.json({
status: 'healthy',
service: 'pulsora',
timestamp: new Date().toISOString()
});
} catch (error) {
return Response.json({
status: 'unhealthy',
service: 'pulsora',
error: error.message
}, { status: 503 });
}
}
12. Support Checklist
When escalating to support, include:
Required Information
-
Environment details:
- Browser (Chrome, Firefox, Safari + version)
- OS (macOS, Windows, Linux)
- Framework (React, Next.js, Vue + version)
- Pulsora package versions
-
Console output:
- Screenshots with debug mode enabled
- Full error messages and stack traces
- Any warning messages
-
Network details:
- Request/response from Network tab
- Request headers (especially
X-API-Token) - Response status code and body
-
Code snippets:
- Pulsora initialization code
- Event tracking code that's failing
- Provider/hook usage if using React
-
Timing information:
- When the issue started (UTC timezone)
- Frequency (always, intermittent, specific users)
- Any recent changes to code or infrastructure
Debug Bundle Export
// Generate debug bundle for support
function exportDebugInfo() {
const debug = {
timestamp: new Date().toISOString(),
userAgent: navigator.userAgent,
url: window.location.href,
packages: {
core: '@pulsora/core@1.0.0', // Get from package.json
react: '@pulsora/react@1.0.0',
},
config: {
hasToken: !!process.env.NEXT_PUBLIC_PULSORA_TOKEN,
tokenPrefix: process.env.NEXT_PUBLIC_PULSORA_TOKEN?.slice(0, 4),
debug: pulsora.config.debug,
},
network: {
// Check connectivity
canReachAPI: false, // Set after testing
},
};
console.log('Debug Bundle:', JSON.stringify(debug, null, 2));
// Copy to clipboard
navigator.clipboard.writeText(JSON.stringify(debug, null, 2));
console.log('Debug bundle copied to clipboard');
}
// Run in console when debugging
exportDebugInfo();
Next Steps
- API Reference - Complete API documentation
- Performance Guide - Optimize tracking performance
- Error Handling - Handle tracking failures gracefully
- Support - Contact support with debug info