After this page you can configure any part of a self-hosted stack and know what happens when a
variable is left empty. This page mirrors .env.example in the repo root; if they disagree,
.env.example wins and this page has a bug.
Every variable is optional unless marked REQUIRED. The stack runs end-to-end on the
zero-key fallbacks: polling adapter, mock Telegram, Stripe test mode.
| Variable |
Default |
Meaning |
WIRETAP_PROVIDER |
polling |
Which adapter the ingester uses: polling | yellowstone | helius. See Providers |
WIRETAP_RPC_URL |
http://127.0.0.1:8899 |
RPC endpoint for the polling adapter. Any Solana JSON-RPC endpoint works (devnet: https://api.devnet.solana.com) |
WIRETAP_PROGRAMS |
(empty) |
Comma-separated program IDs to track — the CLI registers these for you |
WIRETAP_RPC_BUDGET_RPS |
8 |
Polling budget: max JSON-RPC requests/second the adapter will spend |
WIRETAP_POLL_INTERVAL_MS |
2000 |
How often (ms) the ingester polls each tracked program — raise (e.g. 10000) to cut RPC/credit usage |
WIRETAP_COLD_START_MAX_SIGS |
300 |
Max signatures hydrated per poll cycle (bounds the cold-start backfill + each resume chunk) |
WIRETAP_MAINNET_RPC |
(falls back to public) |
RPC for the daily leaderboard block sampler (getBlock); a paid/Helius URL is recommended since the free endpoint restricts getBlock |
YELLOWSTONE_ENDPOINT |
(empty) |
Yellowstone gRPC endpoint (paid providers: Triton, Helius, Shyft…) |
YELLOWSTONE_X_TOKEN |
(empty) |
Yellowstone auth token |
HELIUS_API_KEY |
(empty) |
Helius enhanced WebSocket key |
| Variable |
Default |
Meaning |
CLICKHOUSE_URL |
http://127.0.0.1:8123 |
ClickHouse HTTP endpoint |
CLICKHOUSE_DB |
wiretap |
Database name (migrations create it) |
CLICKHOUSE_USER |
default |
ClickHouse user |
CLICKHOUSE_PASSWORD |
(empty) |
ClickHouse password |
WIRETAP_DB_PATH |
./wiretap.sqlite |
SQLite metadata store: accounts, API keys, program registry, subscription state |
| Variable |
Default |
Meaning |
API_PORT |
8790 |
API listen port |
API_SESSION_SECRET |
(generated in dev) |
Signs session cookies + deep-link tokens. REQUIRED in hosted mode; dev default is generated at first boot and stored next to the SQLite db |
TELEGRAM_OIDC_CLIENT_ID |
(empty) |
“Log in with Telegram” — the PRIMARY web sign-in (Telegram OpenID Connect). Client ID is the bot’s numeric id (the part before the colon in the bot token). Both this and the secret empty ⇒ /auth/telegram returns “not configured” and GitHub/dev-login stay available |
TELEGRAM_OIDC_CLIENT_SECRET |
(empty) |
Client Secret issued by @BotFather → Bot Settings → Web Login (register the allowed URLs there: your site + <api-base>/auth/telegram/callback). A web Telegram login resolves to the same account as that user’s bot /start |
GITHUB_OAUTH_CLIENT_ID |
(empty) |
GitHub OAuth — the secondary account-lite login |
GITHUB_OAUTH_CLIENT_SECRET |
(empty) |
— |
WIRETAP_DEV |
1 |
1 enables the dev-login + /v1/dev/bootstrap bypass (zero-config self-host). Set 0 on a public deploy and configure GitHub OAuth above, or anyone can mint an account |
WIRETAP_WHY_RPC |
(falls back to public) |
RPC for the free public /why live-lookup fallback (decode any pasted signature) |
| Variable |
Default |
Meaning |
TELEGRAM_BOT_TOKEN |
(empty) |
Empty ⇒ mock transport: bot logic runs fully, messages are logged/captured instead of sent. Real token in ~5 minutes |
| Variable |
Default |
Meaning |
STRIPE_SECRET_KEY |
(empty) |
Empty or test key ⇒ test mode; the flat subscription plans and 14-day trial all work with test keys |
STRIPE_WEBHOOK_SECRET |
(empty) |
Webhook signature verification |
STRIPE_METER_EVENT_NAME |
wiretap_events |
Legacy usage-meter event name; unused under flat per-program billing (billing is subscription-based, not metered) |
| Variable |
Default |
Meaning |
MCP_HTTP_PORT |
8791 |
HTTP transport port for the MCP server |
All optional. Every surface is a strict no-op when its key is empty (the default), so the
stack runs clean with analytics off. A slow, failing, or absent PostHog never blocks a page
render, an API request, or a bot reply. There are two distinct keys:
| Variable |
Default |
Meaning |
PUBLIC_POSTHOG_KEY |
(empty) |
Public client key (phc_…) — safe to ship to the browser. Baked into the web + docs static bundles at build time (Astro inlines PUBLIC_*), wired as a compose build arg on the web service. Enables pageview + autocapture (visits, users, funnels). Empty ⇒ PostHog is never loaded in the browser. Do-Not-Track is respected. No cookie-consent banner is shown yet (a deferred legal decision) |
PUBLIC_POSTHOG_HOST |
https://us.i.posthog.com |
Host for the browser bundle |
POSTHOG_API_KEY |
(empty) |
Server capture key — used by the api + bot services (posthog-node). Stays server-side; never sent to a browser. Server events: account_created, program_watched, api_key_minted, why_lookup, command_used, alert_sent. Empty ⇒ strict no-op. For this project, set it to the same phc_ key as PUBLIC_POSTHOG_KEY (a phc_ ingest key works for capture) |
POSTHOG_HOST |
https://us.i.posthog.com |
Host for the server SDK |
The operator sets all of these to the WireTap PostHog project’s phc_ key/host. In compose,
PUBLIC_POSTHOG_KEY is a build arg (baked at image build) while POSTHOG_API_KEY is a
runtime env on the api + bot services — set both in .env before docker compose … build.