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

Script tag

Add Voidhash to a site without a JavaScript build, such as Webflow, WordPress or plain HTML.

The script-tag build, voidhash.global.js, is the web SDK as one file that a <script> tag loads from Voidhash's CDN. It includes everything it needs, about 44 kB gzipped, and records the same page views, campaigns, events, identity and consent as the npm package.

Add the snippet

Put both tags in the <head> of every page:

<script>
  window.voidhash = window.voidhash || { q: [] };
  [
    "track",
    "page",
    "identify",
    "signOut",
    "reset",
    "setAnalyticsConsent",
    "setAdDataSharing",
    "setPersonAttributes",
    "on",
  ].forEach(function (method) {
    window.voidhash[method] =
      window.voidhash[method] ||
      function () {
        window.voidhash.q.push([method, arguments]);
      };
  });
  ["getDistinctId", "getSessionId", "getFeatureVariant"].forEach(function (method) {
    window.voidhash[method] = window.voidhash[method] || function () {};
  });
  window.voidhash.isFeatureEnabled =
    window.voidhash.isFeatureEnabled ||
    function (key) {
      var flags = (window.voidhash.options || {}).featureFlags || {};
      return (flags.defaults || {})[key] === true;
    };
  window.voidhash.playStoreUrl =
    window.voidhash.playStoreUrl ||
    function (packageName) {
      return "https://play.google.com/store/apps/details?id=" + encodeURIComponent(packageName);
    };
</script>
<script
  async
  src="https://cdn.voidhash.com/web/latest/voidhash.global.js"
  data-publishable-key="vh_pk_..."
></script>

The first tag lets the page call window.voidhash before the file has loaded. It queues calls to the listed methods, isFeatureEnabled() returns the flag's default, and the other methods that return a value return undefined. The second tag loads the SDK without holding up the page. When the file arrives, it creates the client as window.voidhash, records the page view and campaign, then makes the queued calls in order.

Keep the async attribute. If the file cannot load, your page works as before: queued calls are never made, flags read as their defaults and getDistinctId() returns undefined.

Choose a version

/web/latest/voidhash.global.js serves the newest build; pages pick up a new one within about five minutes. For a production site, load a fixed version instead, so a new build never changes a page you tested. A version's file never changes, so add its integrity hash:

<script
  async
  src="https://cdn.voidhash.com/web/0.0.1-alpha.1-g83f7412/voidhash.global.js"
  integrity="sha384-..."
  crossorigin="anonymous"
  data-publishable-key="vh_pk_..."
></script>

The first line of each file names its version, and openssl computes the hash:

curl -s https://cdn.voidhash.com/web/latest/voidhash.global.js | head -n 1
# /*! @voidhash/web 0.0.1-alpha.1-g83f7412 | MIT */

curl -s https://cdn.voidhash.com/web/0.0.1-alpha.1-g83f7412/voidhash.global.js \
  | openssl dgst -sha384 -binary | openssl base64 -A

To serve the file yourself, install the package as in the quickstart and copy dist/voidhash.global.js to your static files.

Options

The tag's data- attributes set client options:

AttributeOption
data-publishable-keypublishableKey. Without a key here or in window.voidhash.options, no client starts.
data-base-urlbaseUrl, for a first-party proxy or a tracking domain.
data-analytics-consentanalyticsConsent: granted, denied or pending.
data-analytics-consent-sourceanalyticsConsentSource: sdk or app.
data-store-before-consent"false" sets storeBeforeConsent: false.
data-cross-subdomain-identityPresent (any value but "false") turns on crossSubdomainIdentity.
data-capture-page-views"false" turns off automatic page views.
data-capture-page-leaves"false" turns off automatic page leaves.
data-capture-outbound-clicks"false" turns off automatic outbound clicks.

For options an attribute cannot carry, such as functions, set window.voidhash.options in the first tag and leave data-publishable-key out:

<script>
  window.voidhash = window.voidhash || { q: [] };
  window.voidhash.options = {
    publishableKey: "vh_pk_...",
    analytics: {
      sanitizeUrl: function (url) {
        return url.pathname.indexOf("/account/") === 0 ? null : url;
      },
    },
    featureFlags: { defaults: { "new-checkout": true } },
  };
  // ... the rest of the snippet above ...
</script>
<script async src="https://cdn.voidhash.com/web/latest/voidhash.global.js"></script>

A data- attribute wins over the same option. If an option is invalid, the SDK does not start and reports the error in the browser console; the page is unaffected.

Track events and identify visitors

Call the client from anywhere on the page:

<button onclick="voidhash.track('trial_started', { plan: 'pro' })">Start your free trial</button>
voidhash.identify("user_123", { email: "ada@example.com" });

Methods that return a value, such as getDistinctId() for Stripe purchases, work once the client has started:

voidhash.on("initialized", function (event) {
  document.querySelector("#checkout").dataset.visitor = event.distinctId;
});

Ask for consent

Where consent comes first, start with consent pending and nothing stored, then pass the answer from your consent banner. Calls made before the file loads are queued.

<script
  async
  src="https://cdn.voidhash.com/web/latest/voidhash.global.js"
  data-publishable-key="vh_pk_..."
  data-analytics-consent="pending"
  data-store-before-consent="false"
></script>
voidhash.setAnalyticsConsent(analyticsAllowed ? "granted" : "denied");

With a consent tool such as Cookiebot or OneTrust, also add data-analytics-consent-source="app". See Privacy and consent.

Content Security Policy

Besides the connect-src entries, allow https://cdn.voidhash.com, or the origin you serve the file from, in script-src. The inline snippet needs a nonce or hash in script-src, or move it into a file of its own.

Next steps

  • Identify users
  • Track events
  • Privacy and consent

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

PreviousWeb quickstartNextIdentify users

On this page

Add the snippetChoose a versionOptionsTrack events and identify visitorsAsk for consentContent Security PolicyNext steps