Visitors
Client-only, privacy-friendly web analytics with optional Stripe revenue attribution.
Visitors.now is a lightweight, privacy-focused web analytics service with built-in Stripe revenue attribution.
When to use it
- You want page-view analytics that sets no cookies by default.
- You want to attribute Stripe revenue to individual visitors.
- You care about GDPR-friendly defaults and built-in bot filtering.
Visitors is client-only. For backend events such as payments or signups you must not lose, pair it with a server provider like PostHog, Bento, or Pirsch.
Installation
No npm package required. VisitorsClientProvider loads the tracking script from the Visitors CDN at runtime.
Client-side usage
import { createClientAnalytics } from 'trakoo/client';
import { VisitorsClientProvider } from 'trakoo/providers/client';
export const visitorsProvider = new VisitorsClientProvider({
token: process.env.NEXT_PUBLIC_VISITORS_TOKEN!,
persist: true // sets data-persist on the script tag
});
export const analytics = createClientAnalytics({
providers: [visitorsProvider]
});
await analytics.initialize();
Page views
Page views are tracked automatically when the Visitors script loads. Calling analytics.pageView() is optional and produces a debug log only — it sends no duplicate event.
Custom events
analytics.track('button_clicked', {
button: 'cta',
page: 'pricing',
value: 99
});
Property values must be string or number. Object and array values are dropped to match the Visitors API contract.
Identify users
analytics.identify('user-123', {
email: 'user@example.com',
name: 'Jane Smith',
plan: 'pro',
seats: 5
});
This calls visitors.identify({ id, ...traits }). Non-scalar trait values are filtered out automatically.
Page leave
analytics.pageLeave({ section: 'hero' });
This sends a page_leave custom event via visitors.track().
Server-side usage
Visitors is client-only, so there is no server provider. Track backend events with a server-capable provider such as PostHog, Bento, or Pirsch.
Configuration
tokenstring
Your Visitors project token from the dashboard.
stringpersist?boolean
Sets data-persist on the script tag so a visitor cookie is written. Required for cross-session tracking and Stripe revenue attribution.
booleanfalsedebug?boolean
Enable debug logging.
booleanfalseenabled?boolean
Set to false to disable the provider entirely.
booleantrueStripe revenue attribution
Visitors.now can attribute Stripe revenue to individual visitors through a fallback chain: checkout metadata, then previous attribution, then email matching.
The Visitors script sets a visitor cookie in the browser (this needs persist: true). You read that cookie, pass it in your Stripe checkout session metadata, and Visitors matches the purchase back to the visitor session.
Identify users when they sign in
This enables the email-based fallback.
analytics.identify('user-123', {
email: 'user@example.com',
name: 'Jane Smith'
});Read the visitor cookie on the client
Send the visitor ID to your server when starting checkout.
const visitorId = visitorsProvider.getVisitorId();
const response = await fetch('/api/create-checkout', {
method: 'POST',
body: JSON.stringify({ visitorId, priceId: 'price_xxx' })
});Pass the visitor ID in the checkout session
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(req: Request) {
const { visitorId, priceId } = await req.json();
const session = await stripe.checkout.sessions.create({
mode: 'subscription',
line_items: [{ price: priceId, quantity: 1 }],
success_url: `${process.env.NEXT_PUBLIC_URL}/success`,
cancel_url: `${process.env.NEXT_PUBLIC_URL}/pricing`,
metadata: {
visitor: visitorId ?? ''
}
});
return Response.json({ url: session.url });
}Provider behaviour reference
| Method | Behaviour |
|---|---|
initialize() |
Injects the cdn.visitors.now/v.js script; idempotent |
track(event, ctx) |
Calls visitors.track(action, scalarProps) |
identify(id, traits) |
Calls visitors.identify({ id, ...scalarTraits }) |
pageView() |
No-op — page views are automatic |
pageLeave() |
Calls visitors.track('page_leave', ...) |
reset() |
No-op — Visitors has no native reset method |
getVisitorId() |
Reads the visitor cookie for Stripe attribution |
Privacy
- No cookies by default — opt in with
persist: true. - GDPR-friendly —
identify()requires explicit EU consent when persist mode is enabled. - Bot filtering built in.
