Vercel reverse proxy

Before you start
  • If you use a self-hosted proxy, PostHog can't help troubleshoot. Use our managed reverse proxy if you want support.
  • Use domains matching your PostHog region: us.i.posthog.com for US, eu.i.posthog.com for EU.
  • Don't use obvious path names like /analytics, /tracking, /telemetry, or /posthog. Blockers will catch them. Use something unique to your app instead.

This guide shows you how to use Vercel rewrites as a reverse proxy for PostHog.

How it works

Vercel rewrites map incoming request paths to different destinations. When you add PostHog rewrites to vercel.json, Vercel fetches content from PostHog's servers and returns it under your domain.

Here's the request flow:

  1. User triggers an event in your app
  2. Request goes to your Vercel domain (e.g., yourdomain.com/ph)
  3. Vercel matches the request against your rewrite rules
  4. Vercel fetches the response from PostHog's servers
  5. Vercel returns PostHog's response under your domain

This works because the rewrite happens server-side, so the browser only sees requests to your domain. Ad blockers that filter by domain won't block these requests.

Using Next.js on Vercel?

If you're using Next.js, you can configure rewrites in either vercel.json or next.config.js. Both work identically on Vercel.

  • Use this guide (vercel.json) if you want all Vercel-specific settings in one file
  • Use Next.js rewrites if you prefer keeping config in next.config.js

Don't use both at the same time as they may conflict.

Prerequisites

This guide requires a project deployed on Vercel.

Setup

  1. Create vercel.json

    In your project root, create or update vercel.json:

    {
    "rewrites": [
    {
    "source": "/ph/static/:path(.*)",
    "destination": "https://us-assets.i.posthog.com/static/:path"
    },
    {
    "source": "/ph/:path(.*)",
    "destination": "https://us.i.posthog.com/:path"
    }
    ]
    }

    Here's what each part does:

    • The first rewrite routes /ph/static/* requests to PostHog's asset server. This serves the JavaScript SDK and other static files.
    • The second rewrite routes all other /ph/* requests to PostHog's main API. This handles event capture, feature flags, and session recordings.
    • The :path(.*) syntax captures everything after the matched prefix and passes it to the destination URL.

    The static rewrite must come first. Vercel evaluates rewrites in order, so if the catch-all rule came first, it would match /ph/static/* before the static-specific rule.

    See Vercel's rewrites documentation for more details.

  2. Update your PostHog SDK

    In your application code, update your PostHog initialization:

    posthog.init('<ph_project_api_key>', {
    api_host: '/ph',
    ui_host: 'https://us.posthog.com'
    })

    The api_host tells the SDK where to send events. Using a relative path ensures requests go to your domain. The ui_host must point to PostHog's actual domain so features like the toolbar link correctly.

  3. Deploy to Vercel

    Commit and push your changes. The rewrites become active once deployed.

    You can verify the configuration in your Vercel dashboard under Project SettingsFunctionsRewrites.

  4. Verify your setup

    Checkpoint

    Confirm events are flowing through your proxy:

    1. Open your browser's developer tools and go to the Network tab
    2. Navigate to your site or trigger an event
    3. Look for requests to your domain with your proxy path (e.g., yourdomain.com/ph)
    4. Verify the response status is 200 OK
    5. Check the PostHog app to confirm events appear in your activity feed

    If you see errors, check troubleshooting below.

Troubleshooting

Rewrites not working

If requests to your proxy path return 404:

  1. Verify vercel.json is in your project root (same level as package.json)
  2. Check the file is valid JSON with no syntax errors
  3. Ensure the rewrites are in the correct order: static assets first, then catch-all
  4. Check the Vercel dashboard to confirm the config was deployed

401 errors after deployment

If events work locally but return 401 errors on Vercel, this usually indicates a region mismatch. Verify your rewrite destinations match your PostHog project's region:

  • US region: us.i.posthog.com and us-assets.i.posthog.com
  • EU region: eu.i.posthog.com and eu-assets.i.posthog.com

Conflicts with Next.js rewrites

If you're using both vercel.json rewrites and Next.js next.config.js rewrites, they may conflict. Choose one method:

  • Use vercel.json for all Vercel-specific config
  • Or use next.config.js for framework-level config

Remove the PostHog rewrites from whichever file you're not using.

Rewrite pattern not matching

If your rewrites aren't matching correctly, ensure you're using Vercel's named parameter syntax:

{
"source": "/ph/:path(.*)",
"destination": "https://us.i.posthog.com/:path"
}

The :path(.*) captures the path and :path in the destination references it. Don't use (.*) without the named parameter.

Community questions

Was this page useful?

Questions about this page? or post a community question.