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

First-party proxy

Send the SDK's requests through your own domain, so ad blockers and tracking prevention do not drop them.

A first-party proxy is a path on your own domain, such as https://www.example.com/vh, that forwards the SDK's requests unchanged to https://api.voidhash.com. Ad blockers and tracking prevention block known analytics hosts, which hides those visitors from your funnels and their purchases from your campaigns; requests to your own domain get through. API calls under /api/v1/ and events under /i/v1/ both go through the proxy.

On Voidhash Cloud, a tracking domain does the same without a proxy of your own, and keeps each visitor's location.

Pick a path

Choose a neutral path that is not used by your site, for example /vh. Avoid names such as /analytics, /track, or /voidhash; blocklists match on them.

Forward the path to Voidhash

Configure your host or server to forward every request under the path to https://api.voidhash.com, without the path prefix. Pick the recipe for your setup.

next.config.mjs
export default {
  async rewrites() {
    return [{ source: "/vh/:path*", destination: "https://api.voidhash.com/:path*" }];
  },
};

For a site on Vercel that does not use Next.js:

vercel.json
{
  "rewrites": [{ "source": "/vh/:path*", "destination": "https://api.voidhash.com/:path*" }]
}

A Worker on a route such as www.example.com/vh/*:

worker.ts
export default {
  async fetch(request: Request): Promise<Response> {
    const url = new URL(request.url);
    url.hostname = "api.voidhash.com";
    url.pathname = url.pathname.replace(/^\/vh/, "");
    return fetch(new Request(url, request));
  },
};
nginx.conf
location /vh/ {
  proxy_pass https://api.voidhash.com/;
  proxy_set_header Host api.voidhash.com;
  proxy_ssl_server_name on;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  # The SDK gives up on a request after 10 seconds; so does the proxy.
  proxy_connect_timeout 5s;
  proxy_send_timeout 10s;
  proxy_read_timeout 10s;
}

Keep the method, query string, body and headers as they are, and do not cache responses. Event batches are JSON sent as Content-Type: text/plain; forward them unchanged.

On a server you run, give the proxy a timeout of about 10 seconds, as in the nginx recipe. The SDK gives up by then, and a proxy waiting longer on an unreachable Voidhash holds connections your site needs. Self-hosted Next.js waits 30 seconds unless you set experimental.proxyTimeout.

Point the SDK at the proxy

Set baseUrl to the proxy's URL, including the path:

import { createVoidhashClient } from "@voidhash/web";

const voidhash = createVoidhashClient({
  baseUrl: "https://www.example.com/vh",
  publishableKey: "vh_pk_...",
});

Use the full URL, for example built from window.location.origin; a relative path does not work.

Check it

Open your site with the browser's developer tools on the Network tab. Requests go to /vh/i/v1/batch and /vh/api/v1/sdk/... on your own domain and answer with 2xx. Turn on an ad blocker and reload: the requests still go through.

Returning visitors are unaffected by the move: the SDK stores its state per project, not per baseUrl.

Location behind a proxy

Voidhash derives location from the address the request comes from. Behind a proxy, that is the proxy's address, so events carry the proxy's location, even if the proxy forwards X-Forwarded-For. Attribution, sessions, identity and revenue are unaffected.

Only some traffic through the proxy

To send only analytics through the proxy and keep API calls direct, set analytics.baseUrl instead:

import { createVoidhashClient } from "@voidhash/web";

const voidhash = createVoidhashClient({
  analytics: { baseUrl: "https://www.example.com/vh" },
  publishableKey: "vh_pk_...",
});

The proxy then only needs to forward /vh/i/v1/.... Ad blockers that block the API host still block feature flags and identify(), so forwarding everything is usually better.

Self-hosted Voidhash

A self-hosted deployment already runs on a domain you control. Point baseUrl at it, or put it behind the same kind of proxy with your deployment's URL as the destination.

Next steps

  • Tracking domain
  • Content Security Policy
  • Troubleshooting

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

PreviousWeb-to-app handoffNextTracking domain

On this page

Pick a pathForward the path to VoidhashPoint the SDK at the proxyCheck itLocation behind a proxyOnly some traffic through the proxySelf-hosted VoidhashNext steps