Guides
Analytics
Track what users actually do. Not just what you hope they do.
Analytics
Track what users do. Which features get used, where people drop off, what leads to conversions.
Tracking Events
The track() Method
import { useTrack } from '@thisbefine/analytics/next';
const MyComponent = () => {
const trackUpgrade = useTrack('plan_upgraded');
const handleUpgrade = (plan: string) => {
trackUpgrade({
previousPlan: 'free',
newPlan: plan,
source: 'pricing_page',
});
};
return <button onClick={() => handleUpgrade('pro')}>Upgrade</button>;
};import { getAnalytics } from '@thisbefine/analytics';
const analytics = getAnalytics();
analytics?.track('plan_upgraded', {
previousPlan: 'free',
newPlan: 'pro',
source: 'pricing_page',
});Event Properties
Properties give context. Numbers, strings, booleans, arrays, objects all work:
track('purchase_completed', {
amount: 99.99,
quantity: 1,
currency: 'USD',
productId: 'prod_123',
isFirstPurchase: true,
items: ['item_1', 'item_2'],
metadata: { campaign: 'summer_sale' },
});Keep property values under 1KB when serialized.
Event Naming
Use object_action format with snake_case
// Good
track('button_clicked');
track('form_submitted');
track('signup_completed', { plan: 'pro' });
// Bad
track('click');
track('ButtonClickedEvent');
track('button_clicked', { button: 'signup' });Tracking Pageviews
Automatic Tracking
The <Analytics /> component tracks pageviews automatically by default:
<Analytics apiKey="tif_xxx" trackPageviews={true} />For Next.js, the /next export uses usePathname to track all client-side navigation. For plain React, it catches popstate events (browser back/forward).
Manual Pageview Tracking
For single-page apps with fancy routing:
import { usePage } from '@thisbefine/analytics/next';
import { usePathname } from 'next/navigation';
import { useEffect } from 'react';
const PageTracker = () => {
const page = usePage();
const pathname = usePathname();
useEffect(() => {
page(pathname, {
section: pathname.split('/')[1],
});
}, [pathname, page]);
return null;
};import { getAnalytics } from '@thisbefine/analytics';
getAnalytics()?.page('Dashboard', {
section: 'analytics',
tab: 'overview',
});Automatic Pageview Data
| Property | Value |
|---|---|
url | Full URL |
path | Path without query params |
referrer | Previous page |
title | Document title |
Add custom properties:
page('Product Page', { productId: 'prod_123', category: 'electronics' });Common Patterns
E-commerce
track('product_viewed', { productId: 'prod_123', name: 'Widget Pro', price: 49.99 });
track('cart_item_added', { productId: 'prod_123', quantity: 1, cartTotal: 49.99 });
track('checkout_started', { cartItems: 3, cartTotal: 149.97 });
track('purchase_completed', { orderId: 'ord_456', total: 149.97, items: 3 });SaaS
track('feature_used', { feature: 'export', format: 'csv', rowCount: 1000 });
track('limit_reached', { limit: 'api_calls', current: 10000, max: 10000 });
track('settings_updated', { setting: 'notifications', oldValue: true, newValue: false });User Journey
track('onboarding_step_completed', { step: 1, stepName: 'profile_setup', totalSteps: 5 });
track('onboarding_completed', { timeToComplete: 180, skippedSteps: [] });
track('activation_milestone', { milestone: 'first_project_created', daysFromSignup: 2 });Event Batching
Events are batched for efficiency:
- Send when 20 are queued (configurable via
flushAt) - Send every 10 seconds (configurable via
flushInterval) - Flush on page unload
Force Immediate Send
await getAnalytics()?.flush();
window.location.href = '/external-page';Privacy
Do Not Track
Respects browser DNT setting by default. When DNT is on, nothing is tracked.
<Analytics apiKey="tif_xxx" config={{ respectDNT: true }} />Opt-Out
import { useAnalytics } from '@thisbefine/analytics/next';
const PrivacySettings = () => {
const analytics = useAnalytics();
return (
<div>
<button onClick={() => analytics.optOut()}>Disable</button>
<button onClick={() => analytics.optIn()}>Enable</button>
<p>Status: {analytics.isOptedOut() ? 'Opted Out' : 'Active'}</p>
</div>
);
};Opt-out preference persists in localStorage.