PostHog keys
Is the PostHog project API key safe to expose in the browser?
PostHog's docs say the project token, which starts with phc_ and is still called the project API key in many examples, is ok to be public: it initializes PostHog, captures events and evaluates feature flags, and has no access to your private data. That is why it sits in NEXT_PUBLIC_POSTHOG_KEY or VITE_POSTHOG_KEY. The keys that must stay on the server are the personal API key, which starts with phx_ and reads and writes your PostHog data with your account's access, and the project secret API key or legacy feature flags secure API key, which start with phs_ and are used for local flag evaluation. Anyone who copies a phc_ token can send events to your project and evaluate your flags for any user ID, so a flag is not access control. Checked against PostHog's docs on 2026-10-27.
Use this from your agent
- Claude Code: 4 read-only tools; cannot see your repo.
claude mcp add --transport http viberaven https://viberaven.dev/mcp - Codex: same server, in ~/.codex/config.toml.
[mcp_servers.viberaven] url = "https://viberaven.dev/mcp" - In your repo: writes Vercel + Supabase check rules for your agent (what it writes).
npx -y viberaven init
Same question for Supabase? See what the Supabase anon key can and cannot do.
Which PostHog key is which
PostHog's API has public POST endpoints for capture and flags, which take the project token, and private endpoints that require a personal API key and give the same access as being logged in.
phc_ project token (project API key) capture events, evaluate flags can be public
phx_ personal API key private API, your account's access server only
phs_ project secret API key, or the local flag evaluation in server server only
legacy feature flags secure key SDKs, server-side remote configWhat someone can do with your phc_ token
Send events to your project that your app did not send, and ask the flags endpoint what any distinct ID would get. PostHog's API docs say the public endpoints are not rate limited. Keep secrets out of flag payloads, and check permissions on the server, not with a flag value.
A personal API key in NEXT_PUBLIC_ or VITE_
Next.js and Vite copy every NEXT_PUBLIC_ and VITE_ value into the browser bundle at build time, so a phx_ key under one of those names is readable by every visitor. Move it to a server-only name, call the private API from a server route, and roll the key in PostHog. PostHog says it rolls a phx_ key automatically when GitHub secret scanning finds it in a public repository, which does not cover a key that only shipped in your bundle. See what NEXT_PUBLIC_ exposes.
Local evaluation needs a secret key
PostHog's local evaluation docs say server SDKs need a project secret API key, recommended with the feature_flag:read scope, or the legacy feature flags secure API key, and that it must not be used in the frontend or exposed to users.
Checklist
Check which PostHog keys your app ships
- 01Search the code and the built bundle for personal and secret keys:
grep -rnE "phx_|phs_" src app lib .next/static dist 2>/dev/null - 02Confirm that every NEXT_PUBLIC_ or VITE_ PostHog variable holds a phc_ value.
- 03Move any phx_ or phs_ key to a server-only variable, roll it in PostHog, and redeploy.
- 04Check that no flag payload carries a secret and no permission depends on a flag value alone.
Related
Related guides
Sources
Official docs behind this checklist
Browse all launch guides · Read resources · How to make and check your next change
FAQ
FAQ for builders before launch
Do I need to hide the phc_ token behind a proxy?
Not to keep it secret: PostHog says it can be public. A reverse proxy is a separate choice, made so ad blockers do not stop the events.
What happens if a phx_ key is pushed to a public GitHub repo?
PostHog's API docs say GitHub secret scanning reports it, and PostHog rolls the key and emails you. Update the server variable with the new key afterwards.