StackSee Analytics
Providers

Visitors Provider

Lightweight, privacy-friendly web analytics with Stripe revenue attribution

Visitors.now is a lightweight, privacy-focused web analytics platform with built-in Stripe revenue attribution.

Installation

No npm package required. VisitorsClientProvider loads the tracking script directly from the Visitors CDN at runtime.

Client-Side Usage

import { createClientAnalytics } from '@stacksee/analytics/client';
import { VisitorsClientProvider } from '@stacksee/analytics/providers/client';

const analytics = createClientAnalytics({
  providers: [
    new VisitorsClientProvider({
      token: process.env.NEXT_PUBLIC_VISITORS_TOKEN!,
      persist: true // sets data-persist on the script tag
    })
  ]
});

await analytics.initialize();

Configuration Options

OptionTypeRequiredDescription
tokenstringYesYour Visitors project token from the dashboard
persistbooleanNoEnable persist mode — sets data-persist on the script tag so a visitor cookie is written. Required for cross-session tracking and Stripe revenue attribution (default: false)
debugbooleanNoEnable debug logging (default: false)
enabledbooleanNoDisable the provider entirely (default: true)

Tracking Events

Page Views

Page views are tracked automatically when the Visitors script loads. Calling analytics.pageView() is optional and results in a debug log only — no duplicate event is sent.

Custom Events

analytics.track('button_clicked', {
  button: 'cta',
  page: 'pricing',
  value: 99
});

Property values must be string or number. Object and array values are silently dropped to match the Visitors API contract.

Identify Users

analytics.identify('user-123', {
  email: 'user@example.com',
  name: 'Jane Smith',
  plan: 'pro',
  seats: 5
});

Calls visitors.identify({ id, ...traits }). Non-scalar trait values are filtered out automatically.

Identification requires persist: true in your VisitorsClientProvider config. EU users must give explicit consent before calling identify().

Page Leave

analytics.pageLeave({ section: 'hero' });

Sends a page_leave custom event via visitors.track().

Stripe Revenue Attribution

Visitors.now can attribute Stripe revenue to individual visitors through a fallback chain: checkout metadata → previous attribution → email matching.

How It Works

  1. The Visitors script sets a visitor cookie in the browser (requires persist mode)
  2. You read the cookie value and pass it in the Stripe checkout session metadata
  3. Visitors.now matches the purchase to the visitor session

Implementation

Step 1 — Identify users when they sign in (required for email-based fallback):

analytics.identify('user-123', {
  email: 'user@example.com',
  name: 'Jane Smith'
});

Step 2 — Read the visitor cookie on the client and send it to your server:

// Get the visitor ID for Stripe attribution
const visitorId = visitorsProvider.getVisitorId();

// Send to your server when creating a checkout session
const response = await fetch('/api/create-checkout', {
  method: 'POST',
  body: JSON.stringify({ visitorId, priceId: 'price_xxx' })
});

Step 3 — Pass the visitor ID in your Stripe checkout session (server-side):

// pages/api/create-checkout.ts (Next.js example)
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`,
    // Pass the visitor cookie for revenue attribution
    metadata: {
      visitor: visitorId ?? ''
    }
  });

  return Response.json({ url: session.url });
}

Revenue attribution requires:

  • persist: true set in VisitorsClientProvider config (adds data-persist to the script tag so the visitor cookie is written)
  • A Stripe API key connected under Settings → Integrations
  • visitors.identify() called when users sign in (for email-based fallback)

Framework Examples

Next.js App Router

// lib/analytics.ts
import { createClientAnalytics } from '@stacksee/analytics/client';
import { VisitorsClientProvider } from '@stacksee/analytics/providers/client';

export const visitorsProvider = new VisitorsClientProvider({
  token: process.env.NEXT_PUBLIC_VISITORS_TOKEN!,
  persist: true,
  debug: process.env.NODE_ENV === 'development'
});

export const analytics = createClientAnalytics({
  providers: [visitorsProvider]
});
// app/layout.tsx
'use client';
import { useEffect } from 'react';
import { usePathname } from 'next/navigation';
import { analytics } from '@/lib/analytics';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  const pathname = usePathname();

  useEffect(() => {
    analytics.initialize();
  }, []);

  useEffect(() => {
    analytics.pageView({ path: pathname });
  }, [pathname]);

  return <html><body>{children}</body></html>;
}

Provider Behaviour Reference

MethodBehaviour
initialize()Injects 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 Features

  • No cookies by default — opt in via persist: true
  • GDPR-compliant — identify() requires explicit EU consent when persist mode is enabled
  • Bot filtering built-in

Resources