Guides / Vercel preview deployments
Are your Vercel preview deployments public? How to check and lock them down
Every branch you push to Vercel gets its own URL, like my-app-git-new-checkout-yourname.vercel.app. Those previews run your unfinished code, often against the same database and API keys as production, and the URLs end up in pull requests, chat threads and screenshots. Whether a stranger can open one comes down to one project setting. Here's how to check it in a minute and turn it on.
The short answer
A preview deployment is only private if Deployment Protection is on for the project. New Vercel projects start with Vercel Authentication at Standard Protection, which puts a Vercel login in front of every deployment except your production domains. Older projects, projects where someone switched it off, and projects in a team whose default was set to None can have fully public previews. To check and fix it:
- Open a preview URL in a private window, or hit it with
curl. If your app loads without a Vercel login, that preview is public. - Turn on Vercel Authentication in Settings → Deployment Protection with Standard Protection. It's free on every plan, Hobby included.
- Give Preview its own keys, so a preview never runs unfinished code against live payments or real user data, even when someone does get in.
"noindex" isn't protection. Vercel adds an X-Robots-Tag: noindex header to preview deployments so search engines skip them. That only asks crawlers not to list the page. Anyone who has the URL can still open it.
Why a public preview matters
A preview is a real, running copy of your app built from a branch that isn't finished. Vercel applies the environment variables you marked for Preview to every non-production branch, and in a lot of AI-built projects those are the same live Supabase, Stripe and OpenAI keys production uses. So a public preview can mean:
- a half-built admin page, debug route or test endpoint, reachable by anyone, talking to your real database,
- a branch where auth checks were commented out "for now",
- features you haven't announced, visible to whoever finds a URL in a public pull request.
Production gets your attention before launch. Previews usually don't.
How to check
1. Find your preview URLs
Every deployment is listed on the project's Deployments page. With the Vercel CLI, from your linked project folder:
vercel ls
Pick a recent preview URL, plus the generated URL of your current production deployment (the one ending in a random string, like my-app-abc123xyz.vercel.app, not your custom domain).
2. Ask for it the way a stranger would
This sends no cookies and prints only the status code and where it redirects, if anywhere:
curl -s -o /dev/null -w '%{http_code} %{redirect_url}\n' \
"https://my-app-git-new-checkout-yourname.vercel.app/"
A 200 with no redirect means your app served the page to an anonymous visitor, so the preview is public. A 401, or a redirect to vercel.com, means a login is in the way. A redirect to your own app's sign-in page doesn't count: that's your app's auth, not Vercel's, and your API routes are still reachable. Run the same check on the generated production URL.
Also see whether the noindex header is there, since a missing one tells you the preview is served on a custom domain (more on that below):
curl -sI "https://my-app-git-new-checkout-yourname.vercel.app/" | grep -i '^x-robots-tag'
3. Read the setting from the API
If you have a Vercel access token in VERCEL_TOKEN, this prints only the protection settings for the project, not your environment variables or the token. Add ?teamId=... if the project belongs to a team:
curl -s -H "Authorization: Bearer $VERCEL_TOKEN" \
"https://api.vercel.com/v9/projects/my-app" \
| jq '{ssoProtection, passwordProtection, trustedIps: (.trustedIps.deploymentType // null)}'
"ssoProtection": null means Vercel Authentication is off. A deploymentType of prod_deployment_urls_and_all_previews is Standard Protection, all covers production too, and preview protects previews only.
4. See which keys your previews get
This lists variable names and the environments they apply to. It doesn't print values:
vercel env ls preview
Look for live payment keys, your production database URL, and secret keys you'd never want an unfinished branch to use.
How to fix it
Turn on Vercel Authentication
In the dashboard, open the project, go to Settings → Deployment Protection, switch on Vercel Authentication, choose Standard Protection and save. It applies to existing and future deployments in that scope. Visitors who aren't signed in to Vercel with access to the project get a login page instead of your app.
Or set it with the API, using the same token:
curl -s -X PATCH -H "Authorization: Bearer $VERCEL_TOKEN" \
-H "Content-Type: application/json" \
"https://api.vercel.com/v9/projects/my-app" \
-d '{"ssoProtection":{"deploymentType":"prod_deployment_urls_and_all_previews"}}' \
| jq '.ssoProtection'
If you run a team with several projects, also set the team default for new projects in your team settings, so the next project doesn't start out public.
Check your VERCEL_URL fetches. With Standard Protection, the generated production deployment URL needs a login too. If your app calls itself through VERCEL_URL or VERCEL_BRANCH_URL (in Next.js, NEXT_PUBLIC_VERCEL_URL), those calls will start failing. Vercel's fix is to call relative paths like fetch('/api/thing') from the browser, and from the server to use the origin of the incoming request.
Give Preview its own keys
Protection decides who can open a preview. Separate keys decide what a preview can damage. In Settings → Environment Variables, set each sensitive variable's Preview value to a test or staging one: Stripe test-mode keys, a separate Supabase project or branch, and a separate, spend-capped key for any AI API. Vercel lets you override a Preview variable for one specific branch, so you only have to change the values that differ. Changes apply to new deployments only, so redeploy the previews you care about.
Clean up who already has a way in
- Shareable Links. Anyone with one of these can open that deployment without logging in. Review them under Deployment Protection → Access → All Access → Shareable Links, and revoke one by switching its Share setting back to Only people with access.
- The automation bypass secret. Tools that send the
x-vercel-protection-bypassheader or query parameter skip protection entirely. Keep the secret in an environment variable rather than pasted into a URL, since it works on every deployment in the project until you revoke it. If it was ever shared or put in a public place, regenerate it, then redeploy. - Access you granted. People you approved through access requests can keep viewing that branch. Remove anyone who no longer needs it from the Access section.
Custom domains on preview branches
If you've put a domain like staging.example.com on a branch, Vercel stops adding the noindex header there, so search engines can list it. Run the curl check above on that domain too, and if it loads without a login, protect it before it gets indexed.
Want production private as well?
Choose All Deployments instead of Standard Protection. It's available on every plan and covers your production domain, which suits an internal tool or a beta you aren't ready to show. Password Protection is a different method: it isn't available on Hobby, and on Pro it's a paid add-on per protected project, so Vercel Authentication is the free route.
Confirm it worked
Re-run the curl check on the preview and the generated production URL from a logged-out terminal. You should no longer get a 200 from your app. Then open your real production domain and make sure it still loads for everyone, unless you chose All Deployments.
next step
Check your live app for free
Our free Leak Checker looks at your deployed app the way any visitor's browser does and flags exposed secret keys, public source maps and missing security headers. Point it at your production domain and at a preview URL you've just checked, and compare what each one gives away.
If you want the deploy settings, keys and database checked together, the $99 Scan + Report covers your repo and live app, including deploy settings, leaked keys and database access rules.
Sources
Every product step above was checked against these official pages. Last checked Oct 2026. Products change; if a setting moved, the docs below are the source of truth.
- Vercel: Deployment Protection (scopes, Standard Protection, VERCEL_URL migration, Password Protection pricing)
- Vercel: Vercel Authentication (who can access, API ssoProtection values)
- Vercel changelog: team-wide defaults for Deployment Protection
- Vercel: Shareable Links
- Vercel: Protection Bypass for Automation
- Vercel: Environment variables (Preview and branch-specific values)
- Vercel: Are Preview Deployments indexed by search engines?
- Vercel REST API: Find a project (ssoProtection, passwordProtection)