@pulsora/react
v0.1.0
Published
React hooks for Pulsora Analytics - Privacy-first analytics tracking
Maintainers
Readme
@pulsora/react
React hooks for Pulsora Analytics. Privacy-first analytics tracking with idiomatic React integration.
Installation
npm install @pulsora/react @pulsora/coreQuick Start
import { PulsoraProvider, usePageview, useEvent } from '@pulsora/react';
function App() {
return (
<PulsoraProvider config={{ apiToken: 'your-api-token' }}>
<YourApp />
</PulsoraProvider>
);
}
function MyPage() {
usePageview(); // Automatic pageview tracking
const trackEvent = useEvent();
return (
<button onClick={() => trackEvent('button_click', { value: 'cta' })}>
Click Me
</button>
);
}API Reference
<PulsoraProvider>
Context provider that initializes Pulsora and makes it available to child components.
Props
interface PulsoraProviderProps {
config: PulsoraConfig;
children: ReactNode;
}
interface PulsoraConfig {
apiToken: string;
endpoint?: string; // Default: https://api.pulsora.co/api/ingest
debug?: boolean; // Default: false
autoPageviews?: boolean; // Default: true
maxRetries?: number; // Default: 10
retryBackoff?: number; // Default: 1000
}Example
import { PulsoraProvider } from '@pulsora/react';
function App() {
return (
<PulsoraProvider
config={{
apiToken: process.env.PULSORA_TOKEN,
debug: process.env.NODE_ENV === 'development',
}}
>
<YourApp />
</PulsoraProvider>
);
}usePulsora()
Access the Pulsora instance directly for advanced use cases.
Returns
PulsoraCore - The Pulsora tracker instance
Example
import { usePulsora } from '@pulsora/react';
function AdvancedComponent() {
const pulsora = usePulsora();
const handleAction = async () => {
const fingerprint = await pulsora.getVisitorFingerprint();
const sessionId = pulsora.getSessionId();
// Use these values as needed
console.log({ fingerprint, sessionId });
};
return <button onClick={handleAction}>Get Info</button>;
}usePageview(options?)
Automatically track pageviews.
Options
interface UsePageviewOptions {
trigger?: any; // Value that triggers pageview when it changes
disabled?: boolean; // Disable tracking
}Example - Basic Usage
import { usePageview } from '@pulsora/react';
function Page() {
usePageview(); // Tracks on mount
return <div>My Page</div>;
}Example - React Router
import { useLocation } from 'react-router-dom';
import { usePageview } from '@pulsora/react';
function App() {
const location = useLocation();
// Track pageview on route changes
usePageview({ trigger: location.pathname });
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
);
}Example - Next.js App Router
'use client';
import { usePathname } from 'next/navigation';
import { usePageview } from '@pulsora/react';
export function AnalyticsProvider({ children }: { children: React.ReactNode }) {
const pathname = usePathname();
usePageview({ trigger: pathname });
return <>{children}</>;
}Example - Next.js Pages Router
import { useRouter } from 'next/router';
import { usePageview } from '@pulsora/react';
function MyApp({ Component, pageProps }) {
const router = useRouter();
usePageview({ trigger: router.asPath });
return <Component {...pageProps} />;
}Example - Remix
import { useLocation } from '@remix-run/react';
import { usePageview } from '@pulsora/react';
export function Root() {
const location = useLocation();
usePageview({ trigger: location.pathname });
return (
<html>
<head />
<body>
<Outlet />
</body>
</html>
);
}useEvent()
Track custom events.
Returns
TrackEventFunction - Function to track events
type TrackEventFunction = (
eventName: string,
eventData?: Record<string, any>,
) => Promise<void>;Example
import { useEvent } from '@pulsora/react';
function ProductCard({ product }) {
const trackEvent = useEvent();
const handleAddToCart = () => {
trackEvent('add_to_cart', {
product_id: product.id,
product_name: product.name,
price: product.price,
category: product.category,
});
};
const handleViewDetails = () => {
trackEvent('view_product_details', {
product_id: product.id,
});
};
return (
<div>
<h3>{product.name}</h3>
<button onClick={handleViewDetails}>View Details</button>
<button onClick={handleAddToCart}>Add to Cart</button>
</div>
);
}Example - Form Tracking
import { useEvent } from '@pulsora/react';
function ContactForm() {
const trackEvent = useEvent();
const handleSubmit = (e) => {
e.preventDefault();
trackEvent('form_submit', {
form_id: 'contact',
fields: ['name', 'email', 'message'],
});
// Submit form...
};
const handleFieldFocus = (field) => {
trackEvent('form_field_focus', { field });
};
return (
<form onSubmit={handleSubmit}>
<input name="email" onFocus={() => handleFieldFocus('email')} />
<button type="submit">Submit</button>
</form>
);
}useIdentify()
Identify users and manage identification state.
Returns
interface UseIdentifyReturn {
identify: (customerId: string) => Promise<void>;
isIdentified: boolean;
reset: () => void;
}Example - User Login
import { useIdentify } from '@pulsora/react';
function LoginForm() {
const { identify, isIdentified } = useIdentify();
const handleLogin = async (email, password) => {
// Perform login logic...
const user = await api.login(email, password);
// Identify user for analytics
await identify(user.id);
};
return (
<div>
{isIdentified ? (
<p>Welcome back!</p>
) : (
<button onClick={() => handleLogin(email, password)}>Login</button>
)}
</div>
);
}Example - User Logout
import { useIdentify } from '@pulsora/react';
function LogoutButton() {
const { reset } = useIdentify();
const handleLogout = () => {
// Perform logout logic...
api.logout();
// Reset analytics identification
reset();
};
return <button onClick={handleLogout}>Logout</button>;
}Example - Auto-identify from Auth Context
import { useEffect } from 'react';
import { useAuth } from './auth-context';
import { useIdentify } from '@pulsora/react';
function AutoIdentify() {
const { user } = useAuth();
const { identify, isIdentified } = useIdentify();
useEffect(() => {
if (user && !isIdentified) {
identify(user.id);
}
}, [user, isIdentified, identify]);
return null;
}
// Use in your app:
function App() {
return (
<AuthProvider>
<PulsoraProvider config={{ apiToken: 'your-token' }}>
<AutoIdentify />
<YourApp />
</PulsoraProvider>
</AuthProvider>
);
}Complete Examples
Basic React App
import React from 'react';
import ReactDOM from 'react-dom/client';
import { PulsoraProvider, usePageview, useEvent } from '@pulsora/react';
function Home() {
usePageview();
const trackEvent = useEvent();
return (
<div>
<h1>Welcome</h1>
<button onClick={() => trackEvent('cta_click')}>Get Started</button>
</div>
);
}
function App() {
return (
<PulsoraProvider config={{ apiToken: 'your-api-token' }}>
<Home />
</PulsoraProvider>
);
}
ReactDOM.createRoot(document.getElementById('root')!).render(<App />);React Router SPA
import { BrowserRouter, Routes, Route, useLocation } from 'react-router-dom';
import { PulsoraProvider, usePageview, useEvent } from '@pulsora/react';
function Analytics() {
const location = useLocation();
usePageview({ trigger: location.pathname });
return null;
}
function App() {
return (
<PulsoraProvider config={{ apiToken: 'your-api-token' }}>
<BrowserRouter>
<Analytics />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
</Routes>
</BrowserRouter>
</PulsoraProvider>
);
}Next.js App
// app/providers.tsx
'use client';
import { PulsoraProvider } from '@pulsora/react';
import { usePathname } from 'next/navigation';
import { usePageview } from '@pulsora/react';
import { useEffect } from 'react';
function PageviewTracker() {
const pathname = usePathname();
usePageview({ trigger: pathname });
return null;
}
export function Providers({ children }: { children: React.ReactNode }) {
return (
<PulsoraProvider
config={{
apiToken: process.env.NEXT_PUBLIC_PULSORA_TOKEN!,
}}
>
<PageviewTracker />
{children}
</PulsoraProvider>
);
}
// app/layout.tsx
import { Providers } from './providers';
export default function RootLayout({ children }) {
return (
<html>
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}TypeScript Support
Full TypeScript support with exported types:
import type {
PulsoraConfig,
PulsoraCore,
EventData,
UsePageviewOptions,
TrackEventFunction,
UseIdentifyReturn,
} from '@pulsora/react';SSR Compatibility
The package is safe for server-side rendering. The Pulsora instance will only initialize in the browser.
Testing
Each package has its own test suite. Run tests from the package directory:
cd pulsora-packages/react
npm testBundle Size
- ESM: ~2KB (uncompressed, excluding peer deps)
- Gzipped: ~800 bytes (excluding peer deps)
Peer dependencies (@pulsora/core and react) are not included in the bundle.
Best Practices
1. Single Provider
Only use one <PulsoraProvider> at the root of your app:
// ✅ Good
<PulsoraProvider config={{ apiToken: 'token' }}>
<App />
</PulsoraProvider>
// ❌ Bad - don't nest providers
<PulsoraProvider config={{ apiToken: 'token' }}>
<PulsoraProvider config={{ apiToken: 'token' }}>
<App />
</PulsoraProvider>
</PulsoraProvider>2. Route Change Tracking
For SPAs, use usePageview with a trigger at the router level, not in individual pages:
// ✅ Good - track at router level
function App() {
const location = useLocation();
usePageview({ trigger: location.pathname });
return <Routes>...</Routes>;
}
// ❌ Inefficient - tracking in each page
function Page1() {
usePageview(); // Don't do this in every page
return <div>Page 1</div>;
}3. Event Naming
Use clear, consistent event names:
// ✅ Good
trackEvent('button_click', { button_id: 'cta' });
trackEvent('form_submit', { form_id: 'contact' });
trackEvent('add_to_cart', { product_id: 123 });
// ❌ Bad - vague names
trackEvent('click');
trackEvent('action');4. Identify Early
Identify users as soon as they log in:
function LoginPage() {
const { identify } = useIdentify();
const handleLogin = async (credentials) => {
const user = await api.login(credentials);
await identify(user.id); // Identify immediately
};
return <LoginForm onSubmit={handleLogin} />;
}Troubleshooting
Provider Not Found Error
If you see usePulsora must be used within a PulsoraProvider, make sure:
- You have
<PulsoraProvider>wrapping your app - The hook is called inside a component that's a child of the provider
Pageviews Not Tracked
If pageviews aren't being tracked:
- Check that
autoPageviewsis not disabled in config - If using
usePageviewwith a trigger, verify the trigger value changes - Check browser console for errors (enable
debug: true)
TypeScript Errors
If you get TypeScript errors about missing types:
npm install --save-dev @types/reactLicense
MIT
Support
- Documentation: https://pulsora.co/docs
- Issues: https://github.com/pulsora/pulsora/issues
- Email: [email protected]
