All guidesMonitoring and analytics
On this page

PostHog keys

PostHog

Is the PostHog project API key safe to expose in the browser?

By Ohad Krispin, founder of VibeRaven · LinkedIn

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

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 config

What 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

  1. 01
    Search the code and the built bundle for personal and secret keys:
    grep -rnE "phx_|phs_" src app lib .next/static dist 2>/dev/null
  2. 02Confirm that every NEXT_PUBLIC_ or VITE_ PostHog variable holds a phc_ value.
  3. 03Move any phx_ or phs_ key to a server-only variable, roll it in PostHog, and redeploy.
  4. 04Check that no flag payload carries a secret and no permission depends on a flag value alone.

Related

Sources

Official docs behind this checklist

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.