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

Sell on the web

Credit each web checkout to the visitor who bought, with Stripe or your own payment provider.

Web purchases run through your own checkout: your server picks the price, creates the checkout at your payment provider and sends the buyer there. Voidhash learns what was sold from Stripe's events or your backend's reports, and grants the product the sold price is mapped to. The web SDK's only part is the buyer's distinct ID: put it on the payment, and the purchase, its renewals and refunds are credited to that person and the campaign that brought them.

Send the distinct ID to your server

getDistinctId() returns the anonymous visitor's ID, or your user ID after identify(). Send it with your checkout request:

pricing.ts
import { voidhash } from "./lib/voidhash";

export async function buy(plan: string) {
  // Resolves at once if the client has started; before that there is no ID.
  await voidhash.initialize();

  const response = await fetch("/api/checkout", {
    body: JSON.stringify({ distinctId: voidhash.getDistinctId(), plan }),
    headers: { "content-type": "application/json" },
    method: "POST",
  });
  const { url } = await response.json();
  window.location.assign(url);
}

A signed-in user's distinct ID is your user ID, so your server often has it already; call identify() before checkout so the browser agrees. A visitor who buys before signing up is fine: the purchase moves to the user with the rest of their history when you call identify() later.

Put it on the payment

  • Stripe: set metadata.voidhash_distinct_id on the Checkout Session, and on subscription_data.metadata for a subscription. See Stripe revenue.
  • Another provider: store the distinct ID with your order and report the payment with it as distinctId. See Payment sources.

Stripe Payment Links, the pricing table and the Buy Button cannot carry a distinct ID per buyer, so anonymous visitors are not tied to those purchases. Create Checkout Sessions on your server instead.

Test it

Use the test publishable key (vh_pk_test_...) on your staging site, and create checkouts in Stripe test mode or your provider's sandbox. Test purchases appear under the Test environment in Studio and never unlock access in production. See Test purchases (Help center).

The web example sends the distinct ID to a stand-in checkout endpoint.

Next steps

  • Stripe revenue
  • Connect Stripe (Help center)
  • Check access from your backend with Node.js, PHP, Go, Rust or over HTTP

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

PreviousKeep data out of analyticsNextStripe revenue

On this page

Send the distinct ID to your serverPut it on the paymentTest itNext steps