VoidhashDocs
DevelopersHelp centerGuidesAPI reference
Dashboard
Get started
Introduction
Quickstart
How Voidhash works
Glossary
Versions and releases
Concepts
Teams, projects and environments
API keys
Products and perks
Offers
Subscription lifecycle
People and identity
Events
Features
Paywalls in your app
Feature flags and A/B tests
Paywall components
Push notifications
Ad attribution in your app
Client SDKs
React Native
Swift
Kotlin
Web
Your backend
Node.js
PHP
Go
Rust
Other languages
Payment sources
Forward store notifications
Developer tools
CLI
MCP server
Query analytics with VoidQL
Web SDK
Web quickstart
Script tag
Identify users
Evaluate feature flags
Track
Track events
Page views and attribution
Privacy
Privacy and consent
Browser storage
Connect a consent tool
Keep data out of analytics
Revenue and attribution
Sell on the web
Stripe revenue
Web-to-app handoff
Delivery
First-party proxy
Tracking domain
Reference
Web SDK reference
Errors
Troubleshooting

Web quickstart

Add Voidhash analytics, attribution and identity to a website, React app or Next.js app.

Add the web SDK to an existing website so it records page views, campaign attribution and product events, and links signed-in visitors to your users. It takes about ten minutes.

The web SDK does not present paywalls or make purchases. Web purchases go through Stripe, and the SDK only supplies the buyer's ID: see Sell on the web and Connect Stripe (Help center).

Before you start

  • A Voidhash project and its publishable key from Settings → API keys. Use the vh_pk_test_... key on staging sites and the vh_pk_... key in production; see API keys.
  • A site built with a bundler. Sites without one, such as Webflow or WordPress, use the script tag instead.

Set up

Install the SDK

Install the SDK from the Voidhash package registry. effect 4 is a peer dependency; an app that already uses effect 4 keeps its version.

npm install @voidhash/web@https://pkg.voidha.sh/@voidhash/web/branch:main effect@^4.0.3

npm install @voidhash/web installs an older preview that doesn't match these docs. To pin a build for production, see Install.

Configure the client

Each setup records page views, including client-side route changes, and campaign attribution as soon as the client initializes. Routers built on the History API need no extra code.

Create the client in a module your page's entry script imports:

src/lib/voidhash.ts
import { createVoidhashClient } from "@voidhash/web";

export const voidhash = createVoidhashClient({
  publishableKey: "vh_pk_...",
});

void voidhash.initialize();

Put the test key in an environment file. Vite exposes only variables that start with VITE_:

.env.local
VITE_VOIDHASH_KEY=vh_pk_test_...

Wrap your app in the provider. It creates the client and initializes it on mount.

src/main.tsx
import { VoidhashProvider } from "@voidhash/web/react";
import { createRoot } from "react-dom/client";

import { App } from "./App";

createRoot(document.getElementById("root")!).render(
  <VoidhashProvider config={{ publishableKey: import.meta.env.VITE_VOIDHASH_KEY }}>
    <App />
  </VoidhashProvider>,
);

In the App Router, render the provider from a client component of your own, so you can pass function options such as onDiagnostic. Put the test key in an environment file; Next.js exposes only variables that start with NEXT_PUBLIC_ to the browser:

.env.local
NEXT_PUBLIC_VOIDHASH_KEY=vh_pk_test_...
app/providers.tsx
"use client";

import { VoidhashProvider } from "@voidhash/web/react";

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <VoidhashProvider config={{ publishableKey: process.env.NEXT_PUBLIC_VOIDHASH_KEY! }}>
      {children}
    </VoidhashProvider>
  );
}
app/layout.tsx
import { Providers } from "./providers";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}

The provider is safe to server-render; the client initializes after hydration. Do not call initialize() at the top level of a module, because client components also run on the server. In the Pages Router, render the provider in pages/_app.tsx.

Then track a product event, for example when a visitor starts a checkout:

await voidhash.track("checkout_started", { plan: "yearly" });

In React, take track from useAnalytics(). track() queues the event and never waits for the network. See Track events.

Identify signed-in visitors

When a visitor signs up or signs in, call identify() with your own stable user ID. Their earlier anonymous activity, including the campaign that brought them, joins that user.

await voidhash.identify("user_123", { email: "ada@example.com" });

Use the same user ID in your mobile app, and call signOut() when the user signs out. See Identify users.

Check your data

Open your site, browse a few pages, then open Activity → Analytics events in Studio. Page views appear within a few seconds. Events sent with a test key appear only when Studio shows the Test environment. If nothing arrives, see Troubleshooting.

If your site needs consent before analytics, as in the EU, start with analyticsConsent: "pending" and storeBeforeConsent: false, then pass the visitor's answer to setAnalyticsConsent(). See Ask for consent first.

Next steps

  • See a complete sample site: page views, campaign attribution, consent, sign-up and checkout.
  • Record page views and campaign attribution
  • Attribute Stripe revenue to visitors
  • Send requests through your own domain

Something wrong or missing on this page? Tell us by email or on Discord.

PreviousWeb SDKNextScript tag

On this page

Before you startSet upInstall the SDKConfigure the clientIdentify signed-in visitorsCheck your dataNext steps