You search Google for your branded content and the result shows your-app.vercel.app or your-site.web.app instead of yourdomain.com. Click through and it’s the same page. The platform hostname got indexed before you attached a custom domain, and Google never migrated on its own.
Fastest fix (as of June 2026): make the platform URL 301-redirect to your custom domain so the two stop competing. On Vercel that’s one setting: Project Settings -> Domains -> Edit the *.vercel.app domain -> set Redirect to your custom domain. Emit a <link rel="canonical"> to the custom domain on every page as a backstop, then re-inspect a sample URL in Search Console. A custom domain never “wins” automatically — Google needs an explicit signal (301, canonical, or noindex) to drop the old host.
Why this happens (and which bucket you’re in)
A custom domain and the platform hostname serve byte-identical pages. To Google that’s two URLs for one document, so it picks one “Google-selected canonical.” If the platform URL had a head start (links, crawl history, a shorter path), Google often keeps it. Ordered by how often each cause is the real one:
| # | Cause | One-line check | Result that confirms it |
|---|---|---|---|
| 1 | Launched on the platform URL, added the domain later | site:your-app.vercel.app in Google | Indexed pages show up |
| 2 | No canonical, or canonical points at the platform URL | curl -s https://your-app.vercel.app/article | grep canonical | Canonical href contains vercel.app |
| 3 | Platform URL not redirected | curl -sI https://your-app.vercel.app/ | First line is 200, not 301 |
| 4 | A non-production custom domain leaks (preview branch) | curl -sI https://staging-branch-domain/ | grep -i robots | No X-Robots-Tag: noindex |
| 5 | Firebase web.app / firebaseapp.com can’t be turned off | site:web.app yoursite | Results appear |
| 6 | External backlinks still point at the platform URL | Ahrefs / Search Console “Links” report | Many referring pages cite the platform host |
One detail that surprises people: Vercel already sets X-Robots-Tag: noindex automatically on preview and generated deployment URLs (the *-git-branch-*.vercel.app and hash URLs), as of June 2026. What is not auto-protected is your stable production alias your-project.vercel.app, and any custom domain you attach to a non-production branch. So if a vercel.app URL is in the index, it’s almost always the production alias from cause #1 — not a stray preview.
Shortest path to fix
Step 1 — Emit a canonical to the custom domain on every page
Every page’s <head> needs the canonical pointing at the custom domain, even when the request arrived on the platform host:
<link rel="canonical" href="https://yourdomain.com/article-path/" />
In Astro, build it from site so the host is always your domain regardless of which alias served the request:
---
// In your layout
const canonicalUrl = new URL(Astro.url.pathname, 'https://yourdomain.com').toString();
---
<link rel="canonical" href={canonicalUrl} />
Canonical is a hint, not a command — Google can override it (you’ll see this in URL Inspection as a “Google-selected canonical” that differs from yours). That’s why Step 2 matters: a 301 is an instruction, not a hint.
Step 2 — Redirect the platform URL to the custom domain (the real fix)
Vercel. Adding a custom domain does not remove or redirect the vercel.app alias; both keep serving 200. Fix it in the dashboard: Project Settings -> Domains, click Edit on the *.vercel.app domain, and use the Redirect to dropdown to point it at your custom domain (Vercel issues a 308 permanent redirect, which Google treats like a 301). This is Vercel’s own recommended way to avoid duplicate-content competition between the two hosts.
If you’d rather keep it in code, a host-matched rule in vercel.json does the same thing:
{
"redirects": [
{
"source": "/:path*",
"has": [{ "type": "host", "value": "your-app.vercel.app" }],
"destination": "https://yourdomain.com/:path*",
"permanent": true
}
]
}
Keep site set so canonical and sitemap URLs stay correct:
// astro.config.mjs
export default defineConfig({
site: 'https://yourdomain.com',
});
Netlify. Set the custom domain as primary under Domain management; Netlify then 301-redirects the *.netlify.app subdomain to it automatically. Confirm with curl -sI.
Firebase Hosting. This is the awkward one. Firebase serves both *.web.app and *.firebaseapp.com by design, and a firebase.json headers block applies to all connected domains — there is no host-matching in the config, so you can’t noindex only the web.app host from firebase.json. Two options that actually work:
- Decide at runtime and emit
noindexonly when the request host is a Firebase default domain:
{(Astro.url.hostname.endsWith('.web.app') || Astro.url.hostname.endsWith('.firebaseapp.com')) && (
<meta name="robots" content="noindex" />
)}
- Or front Firebase with a redirect on the default host via a Cloud Function / rewrite so
web.apprequests 301 to your domain.
Either way, your canonical tag (Step 1) is doing the heavy lifting on Firebase.
Step 3 — Confirm previews are already noindexed (don’t over-engineer this)
On Vercel, preview and old production deployment URLs already carry X-Robots-Tag: noindex automatically (June 2026), so a manual rule is usually redundant. The one gap is a custom domain attached to a non-production branch — Vercel does not noindex that. If you have a staging.yourdomain.com on a preview branch, add the header yourself, gated on environment so production is never touched:
// vercel.json — only for the non-production alias
{
"headers": [
{
"source": "/(.*)",
"has": [{ "type": "host", "value": "staging.yourdomain.com" }],
"headers": [{ "key": "X-Robots-Tag", "value": "noindex" }]
}
]
}
Verify with curl -sI https://staging.yourdomain.com/ | grep -i robots.
Step 4 — Re-inspect, don’t mass-request
In Search Console, run URL Inspection on a few of your custom-domain URLs and read the Google-selected canonical field. If it now reads yourdomain.com, consolidation is working and you mostly just wait. If it still reads the platform host, your 301/canonical isn’t reaching Google yet — recheck Step 2 with curl.
You can click Request Indexing on the custom-domain URLs, but it’s capped at roughly 10-12 URLs/day per property (Google doesn’t publish the exact number, and it varies by site, as of June 2026), so spend it on your most important pages and let the rest reconsolidate from the 301. Do not add the platform URL as its own property and request indexing on it — that tells Google to keep tracking it as a separate site.
Step 5 — Remove the platform URL’s old GSC property (if you made one)
If you verified https://your-app.vercel.app/ as a Search Console property at launch, remove it from the property list. Export any data you want first; the goal is to stop feeding it as an independent site.
Step 6 — Wait for consolidation
Once the 301 and canonical are live, Google drops the platform URL gradually as it re-crawls. site:your-app.vercel.app counts typically fall over 2-8 weeks; head pages move first because they’re crawled most often.
How to confirm it’s fixed
curl -sI https://your-app.vercel.app/returns301or308with alocation:of your domain.curl -s https://your-app.vercel.app/article | grep canonicalshows the canonical pointing atyourdomain.com.- In Search Console URL Inspection, Google-selected canonical on a custom-domain URL reads
yourdomain.com. - Over the following weeks,
site:your-app.vercel.appreturns fewer results, and the branded SERP starts showing your domain.
Easy to misdiagnose as
People assume the custom domain takes over the moment it’s added. It doesn’t — both hosts stay live and Google keeps whichever it already trusts. The cure is always an explicit signal: a 301 from the platform host, a canonical to the custom domain, or noindex on the platform host. Adding the domain alone changes nothing.
When this is not on you
Firebase makes it impossible to fully retire web.app / firebaseapp.com — they’re load-bearing defaults. The noindex-by-host workaround is the cleanest option available, but it’s a meta-tag signal, not a hard 301, so consolidation can be slower than on Vercel or Netlify where you control the redirect directly.
Prevention
- Day one of any project: set the custom domain as primary and redirect the platform host to it before you publish or share links.
- Build the canonical tag from your domain in every template, regardless of which host served the request.
- Never verify a platform URL in Search Console as a separate property.
- For any non-production custom domain (staging/preview), add
X-Robots-Tag: noindexyourself — Vercel only auto-protects the default preview hostnames. - Audit
site:platform-urlonce a quarter to catch newly indexed pages early.
FAQ
- Can I disable the platform URL entirely? Depends on the host. Vercel and Netlify let you 301 the platform subdomain to your custom domain, which effectively retires it for users and crawlers. Firebase’s
web.appandfirebaseapp.comstay accessible by design — you can onlynoindexthem, not remove them. - Will Google figure it out on its own? Eventually, and unreliably. With no 301 or canonical, the platform URL can linger for months. Explicit signals cut that to weeks.
- My canonical points at the right domain but Google still shows the platform URL — why? Canonical is a hint Google can override, usually because the platform URL has more links or crawl history. Add the 301 (Step 2); a redirect is an instruction, not a suggestion.
- Does the 301 hurt my rankings or lose link equity? No. A permanent redirect passes ranking signals to the target, which is exactly what you want — it consolidates the platform URL’s authority onto your domain.
- How long until the old URL disappears from search? Typically 2-8 weeks after the 301 and canonical go live, fastest for frequently crawled head pages. You can nudge top pages with Request Indexing, but the redirect does the bulk of the work on its own.