VoidhashDocs
DevelopersHelp centerGuidesAPI reference
Dashboard
Guides
Launch
Go-live checklist
Make your first App Store purchase
Make your first Google Play purchase
Troubleshoot
Troubleshooting
Recover from incidents
SDK error codes
Purchase error codes
API error codes
FAQ
Recipes
Win back subscribers
Handle plan changes
Unlock the app after a web purchase
Link accounts across platforms
Handle refunds
Register devices for push
Migrate
Migrate to Voidhash
Migrate from RevenueCat
Migrate from Adapty
Migrate from Superwall
Run in observer mode
Privacy and hosting
Delete personal data
Self-hosting
Operate a self-hosted server

Self-hosting

What the self-hosted edition includes, what it needs to run, and its support status.

Voidhash comes in two editions: Voidhash Cloud, which we run for you, and the self-hosted Community edition, which you run from the public source on your own infrastructure. Both use the same SDKs, CLI and API.

Not yet supported for production

Self-hosting is in alpha and not yet supported for production use. Only the latest main branch receives security fixes, and there is no official container image or deployment template yet. A production support matrix will be published before the first public release.

What's included

The Community edition runs Studio, the API, the SDK endpoints, store and Stripe processing, payment sources, webhooks, perks and access checks, people, the built-in analytics reports, VoidQL through the API and the MCP tools, the CLI and the MCP server.

It doesn't include:

  • Billing. There are no plans, usage meters or spend caps.
  • Insights, Dashboards and Studio's Query page. Only the built-in analytics pages are available. VoidQL queries still run through the API and the MCP tools.
  • Hosted tracking domains. Point the web SDK at your own API domain instead; see Tracking domain.
  • Paywall location statistics and A/B test summary metrics.
  • Early-access features. Features that are in early access on Cloud, such as paywalls, feature flags, A/B tests, automations and push notifications, stay off: a self-hosted server has no supported way to turn them on.

Several built-in events are off by default on a self-hosted server, including $screen, $pageview, $app_opened and the paywall events. Turn on the ones you need in Settings → Events. See Events.

Run it locally

An evaluation install runs everything on your machine from a checkout of the public source, with PostgreSQL, ClickHouse, Redis and S3-compatible storage in Docker. It signs you in with a local root account, so it serves only loopback addresses.

Install the tools

You need Node.js 24 or later, Bun, git and a running Docker. pnpm 11.21.0 comes through Corepack. Rust with the wasm32-unknown-unknown target is optional: without it, custom component builds and the paywall designer canvas don't work.

Clone and install

git clone https://github.com/voidhashcom/voidhash.git
cd voidhash
corepack enable
corepack prepare pnpm@11.21.0 --activate
pnpm install --frozen-lockfile

Configure

cp .env.example .env.local
openssl rand -base64 32

Paste the generated value into .env.local as ENCRYPTION_KEY. It must be 32 bytes, base64 encoded; without it, Voidhash stores store and payment credentials as plain text. The file's other defaults work as they are, including the root account root / voidhash. Change VOIDHASH_ROOT_PASSWORD if you like.

Start the stack

pnpm vh doctor
pnpm dev

pnpm vh doctor checks the tools, Docker and your .env.local, and prints a fix for each problem. pnpm dev starts PostgreSQL 16, ClickHouse 25.8, Redis 7.4 and RustFS (S3-compatible storage) in Docker, creates the database and bucket, applies the database migrations, and starts the API, the worker and Studio. In a terminal it shows each service and its log; q or Ctrl-C stops the services and keeps your data.

ServiceAddressStarted with
Studiohttp://127.0.0.1:3000node scripts/dev.mjs in apps/www
APIhttp://127.0.0.1:8788bun src/main.ts in apps/backend
WorkerNo public addressbun src/worker.ts in apps/backend
Migrations—pnpm db:migrate, on every start

If another program holds these ports, every port moves up by 100. pnpm vh status prints the addresses in use.

Sign in

Open Studio at http://127.0.0.1:3000 and sign in with Username root and Password voidhash, or the values you set. Create a team and a project, then copy the publishable keys from Settings → API keys. There is no waitlist.

Point an SDK at it

Set the SDK's base URL to the API address, http://127.0.0.1:8788; see Point SDKs at your server. An iOS simulator reaches it at that address. An Android emulator reaches it at http://10.0.2.2:8788, and Android blocks plain HTTP unless a debug network security config allows cleartext traffic to that host. A physical device can't reach a loopback address.

To upgrade, run git pull and pnpm install --frozen-lockfile, then pnpm dev, which applies new migrations. pnpm vh down stops the stack from another terminal; pnpm vh down --wipe also deletes its data. To upgrade other installs, back them up or rotate their secrets, see Operate a self-hosted server.

Sign-in

The AUTH_PROVIDER setting chooses how people sign in to Studio.

ValueWhat you get
localA single root account from VOIDHASH_ROOT_USERNAME and VOIDHASH_ROOT_PASSWORD. No sign-up and no other team members. Works only on a loopback address (127.0.0.1, localhost, ::1) and never with NODE_ENV=production.
workosEmail and password sign-up, GitHub sign-in, team members and invitations, and SSO and directory sync. Needs your own WorkOS account (WORKOS_CLIENT_ID, WORKOS_API_KEY).

Any deployment that others reach over a network therefore needs workos.

Requirements

ComponentRequirement
API and workerTwo Bun processes built from the source; Node.js 24 or later and pnpm to build.
StudioA web server process from the same source.
PostgreSQLDevelopment and tests use PostgreSQL 16.
ClickHouse25.8 or later, reached over HTTP, with at least 2 GB of memory. Every API and worker process needs it.
RedisReached through BACKEND_REDIS_URL.
S3-compatible storageOne bucket for uploaded files and paywall assets.

Configuration

Configuration comes from environment variables. The repository's .env.example shows a working local setup, and .env.schema lists every supported setting. The main ones:

VariablePurpose
BACKEND_PUBLIC_URLThe public origin of your API, which SDKs and webhooks use.
BACKEND_DASHBOARD_URLThe public origin of Studio.
BACKEND_DATABASE_*PostgreSQL host, port, database name, user and password.
BACKEND_REDIS_URLRedis connection URL.
BACKEND_S3_*Bucket, region, endpoint and credentials of your object storage.
ANALYTICS_CLICKHOUSE_URL, ANALYTICS_CLICKHOUSE_*ClickHouse URL, database, user and password.
ANALYTICS_CLICKHOUSE_READER_*, ANALYTICS_CLICKHOUSE_AGENT_*Optional read-only users for reports and VoidQL. See Analytics users.
AUTH_PROVIDER, VOIDHASH_AUTH_SECRETSign-in provider and the session secret both processes share.
ENCRYPTION_KEYEncrypts stored store, payment and push credentials. Keep it safe; you can't read those credentials without it.
EXCHANGE_RATE_API_KEYConverts revenue in other currencies.

The API, the worker and Studio must use the same settings.

Point SDKs at your server

The SDKs and libraries default to Voidhash Cloud. Set each one's base URL to your BACKEND_PUBLIC_URL. The client SDKs send events to the base URL too. The server libraries send events to their own default, https://ingest.voidhash.com, whatever the base URL, so set their ingest URL to the same origin:

import Foundation
import Voidhash

var options = VoidhashOptions()
options.baseUrl = URL(string: "https://api.example.com")!

Voidhash.configure(publishableKey: "vh_pk_...", options: options)
import com.voidhash.sdk.Voidhash
import com.voidhash.sdk.VoidhashOptions

Voidhash.configure(
    context = this,
    publishableKey = "vh_pk_...",
    options = VoidhashOptions(baseUrl = "https://api.example.com"),
)
import { createVoidhashClient } from "@voidhash/react-native";

export const voidhash = createVoidhashClient("vh_pk_...", {
  baseUrl: "https://api.example.com",
});
import { createVoidhashClient } from "@voidhash/web";

export const voidhash = createVoidhashClient({
  publishableKey: "vh_pk_...",
  baseUrl: "https://api.example.com",
});
import { createVoidhashSdk } from "@voidhash/node";

export const voidhash = createVoidhashSdk({
  secretKey: process.env.VOIDHASH_SECRET_KEY!,
  baseUrl: "https://api.example.com",
  ingestUrl: "https://api.example.com",
});
use Voidhash\VoidhashClient;

$voidhash = VoidhashClient::create(getenv('VOIDHASH_SECRET_KEY'), [
    'baseUrl' => 'https://api.example.com',
    'ingestUrl' => 'https://api.example.com',
]);
client, err := voidhash.New(
	os.Getenv("VOIDHASH_SECRET_KEY"),
	voidhash.WithBaseURL("https://api.example.com"),
	voidhash.WithIngestURL("https://api.example.com"),
)
let voidhash = VoidhashClient::builder()
    .secret_key(std::env::var("VOIDHASH_SECRET_KEY")?)
    .base_url("https://api.example.com")
    .ingest_url("https://api.example.com")
    .build()?;

For the CLI, set VOIDHASH_API_URL and sign in again. For the MCP server, use https://api.example.com/api/mcp.

Licensing

CodeLicense
Client SDKs, server libraries and the CLIMIT
The API, worker and StudioAGPL-3.0-only

Apps that embed a Voidhash SDK aren't affected by the AGPL. You may modify and self-host the AGPL code, including commercially. If you run a modified version as a network service, the AGPL requires you to offer its source to its users. The license files in the repository are authoritative; this summary isn't legal advice.

Next steps

  • Teams, projects and environments
  • Connect a payment provider (Help center)
  • Operate a self-hosted server
  • Troubleshooting

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

PreviousDelete personal dataNextOperate a self-hosted server

On this page

What's includedRun it locallyInstall the toolsClone and installConfigureStart the stackSign inPoint an SDK at itSign-inRequirementsConfigurationPoint SDKs at your serverLicensingNext steps