← Back to Blog

Which URL is the real one? Off-domain canonicals and sitemaps with two homepages

· 14 min read Which URL is the real one? Off-domain canonicals and sitemaps with two homepages

Two rows in the Mega Analyzer Crawl Health section (on the SEO tab) ask the same question from opposite ends: which URL is the real one? Canonical on same origin reads the page's <link rel="canonical"> and checks that the URL it names lives on your host, because a canonical is an instruction: index that URL instead of this one, and credit it with this page's signals. Duplicate home-page aliases in sitemap (N) and its sibling Multiple home-page aliases with no canonical / declared read the sitemap and check that you asked for exactly one homepage. When either row fails, your own markup is telling Google that some other URL deserves the ranking.

What the check actually tests

Detector one: the canonical host. The analyzer takes the first <link rel="canonical"> in the fetched HTML, resolves its href into a URL, and compares that URL's hostname with the hostname of the page it fetched. The two may differ by a leading www. and nothing else. www.example.com and example.com count as the same site, because WordPress, Apache and nginx setups commonly canonicalize one form to the other and that is not a defect. Anything else fails: staging.example.com, old-brand.example, yourstore.myshopify.com, a syndication partner's domain, and also shop.example.com, since a subdomain other than www is a different hostname to this check.

The row is rated warn. When a same-host canonical exists, the pass detail is empty. When the page has no canonical tag at all, the row still passes, with the detail "No canonical tag" and the advice "consider adding one." The fail detail names the host, "Canonical points to staging.example.com", and adds "consolidates authority off this domain." If the href does not parse as a URL, the detail reads "Canonical is not a valid URL:" followed by the raw value.

What does not trip it: protocol, port and path are all ignored. A canonical from http:// to https:// on the same host passes. A canonical from /pricing/ to /plans/ on the same host passes this row too, because the row is about where authority leaves the site, not whether two of your pages collide; the Canonical Cluster Map covers that. A second canonical tag lower in the head is never read; only the first one counts.

One behavior to know before you argue with the row: the analyzer resolves the href the way a browser resolves a link inside its own page, so a relative canonical such as href="/about/" is reported as pointing at a host that is not yours. Google's guidance is to "Use absolute paths rather than relative paths" in the canonical element, so the fix is the same either way. Emit the full https:// URL.

Detector two: homepage aliases in the sitemap. This one runs only when the analyzer managed to fetch a sitemap (it tries /sitemap.xml and the usual fallbacks, then any Sitemap: line in robots.txt). It pulls every <loc> and tests the path against a list of homepage leftovers: /home; /home followed by a hyphen or underscore and one run of letters or digits, which covers /home-1, /home-3, /home_copy and /home-new; /welcome; /index and /index-old; /landing and /landing-old; /start-here-old and /start-here-copy. The match is anchored to the end of the URL and accepts a trailing slash or none, so /blog/welcome/ counts and /homeowners/ does not. A bare /start-here/ was removed from the list on purpose: "new here? start here" is a real page archetype on blogs, not a CMS draft.

Separately it looks for the root. The root counts as declared only when a <loc> has the pathname / and ends with a slash: https://example.com/ qualifies, https://example.com does not.

Then two conditions. Root present plus at least one alias produces Duplicate home-page aliases in sitemap (N), listing up to five alias paths, with the detail that "Each alias is a separate URL Google has to canonicalize against the root, splitting link equity," and the fix: delete the alias pages in the CMS or set them to do not index, add 301 redirects from each alias to /, then resubmit the sitemap in Search Console. Two or more aliases and no root produces Multiple home-page aliases with no canonical / declared, with the detail that the sitemap lists N candidate home pages "but no plain / root. Pick one as canonical, 301 the others to it, and ensure / is in the sitemap." Both are warn. One alias with no root produces nothing, and a clean sitemap produces nothing: there is no pass row for this detector, so its absence is the pass.

The gap to remember is the sitemap index. When the first sitemap file is an index (Yoast's sitemap_index.xml and WordPress core's wp-sitemap.xml both are), the <loc> entries the analyzer sees are child sitemap URLs like /page-sitemap.xml, none of which look like /home-2/, so the detector is silent whatever the children contain. Open the child sitemap (page-sitemap.xml under Yoast, wp-sitemap-posts-page-1.xml under core) and search its <loc> lines for /home, /welcome and the rest yourself, or run the step 4 script's alias pattern against it, before you call a sitemap-index site clean.

Why it matters

The canonical link relation is defined in RFC 6596 as a way to "designate an Internationalized Resource Identifier (IRI) as preferred over resources with duplicative content," and the RFC says plainly that the target may "Exist on a different hostname or domain." Google's canonicalization documentation lists rel="canonical" among the factors it weighs, next to HTTPS, redirects and sitemap presence, and says that "indicating a canonical preference is a hint, not a rule." Put those together and a leftover canonical is a real request that Google may well grant. Its troubleshooting page lists an injected "cross-domain rel="canonical" link annotation" as a known attack on websites; nobody attacks with a signal that is ignored.

Neither of Google's two responses is good. If it honors the canonical, Search Console files your page as "Alternate page with proper canonical tag," a status the report describes as a page that "correctly points to the canonical page, which is indexed, so there is nothing you need to do." The report has no way to know the target is a staging box or the domain you left two years ago. Your page is no longer the one served, the signals go to a URL you may not control, and the tooling tells you everything is fine. If Google overrides you instead, the page lands under "Duplicate, Google chose different canonical than user," and you are ranking on Google's guess rather than your instruction.

The causes are dull and repeatable. A site URL hard-coded into the base template before a domain change. A staging or preview hostname baked into the canonical at build time. A Shopify store whose theme emitted the myshopify.com host before the primary domain was set. A template copied from another site with the other site's URL still in it. Google's site-move guidance is explicit that "Once the redirects are active, ensure that the rel="canonical" link annotations on the new site are using the new URLs," and that "Each new URL should have a self-referencing rel="canonical" link tag." The analyzer row is that sentence, checked.

Homepage aliases are the same defect on the sitemap side. /, /home, /home-1 and /welcome are four URLs. When several return 200 and all of them sit in the sitemap, inbound links and menu items split among them, and Google's own guidance says to "link to the canonical URL rather than a duplicate URL." Google picks the canonical by its own factors, nothing guarantees it picks the plain root, and the one it picks is the one searchers see. The mechanism is ordinary: a page builder duplicates the homepage during a rebuild, the copy is named /home-1 because /home is taken, and the original is never deleted; on WordPress a leftover "Home" page stays published at /home/ when a different page becomes the static front page and nobody trashes the old one. Every alias renders the same page, so nothing looks wrong in a browser, and the sitemap is the only place the duplication is written down. Beyond ranking, a sitemap with three homepages is an unmaintained-site tell to anyone who reads the file.

How to fix it

Step 1: read the canonical yourself. View source on the failing page and find the tag. The three fails below come from the same class of template bug:

<link rel="canonical" href="https://staging.example.com/pricing/">
<link rel="canonical" href="https://old-brand.example/pricing/">
<link rel="canonical" href="https://example-store.myshopify.com/pages/pricing">

If the host is yours under another name (old domain, staging, preview), fix the site URL setting at its source rather than editing the tag. WordPress: Settings, General, the "Site Address (URL)" field, and check that no plugin overrides it. Shopify: Settings, Domains, set the primary domain; the theme's canonical_url object follows it. Static generators: the url field in _data/metadata.json, site.url in a Jekyll or Hugo config, or the equivalent, with the layout building the canonical from that value plus the page path. The page should emit an absolute self-reference:

<link rel="canonical" href="https://example.com/pricing/">

If the canonical points at an unrelated domain, remove it and emit the self-canonical. If it is intentional syndication, first confirm the page you are looking at is the copy, not the original; the analyzer cannot tell which one you are. Google's current advice is that the canonical element "is not recommended for those who want to avoid duplication by syndication partners, because the pages are often very different," and that "The most effective solution is for partners to block indexing of your content." If you are the partner hosting a copy, a noindex on the copy is the stronger fix, with the canonical as a fallback, and a visible "Originally published on" line either way. Paste the failing URL into the Code-Diff Patch Generator to get the template change as a unified diff, deploy, then request indexing in Search Console.

Step 2: make / the only homepage. Delete or unpublish the aliases in the CMS. Squarespace: Pages, find the duplicate (often in the Not Linked section), delete it, and confirm the real homepage carries the home icon. Wix: Pages, delete the duplicates. WordPress: once Settings, Reading points at your static front page, trash the old "Home" page that is still published under /home/. Then add a 301 from every alias to the root, forced, so it wins even while the alias file still exists:

# Netlify _redirects
/home      /   301!
/home-1    /   301!
/home-3    /   301!
/welcome   /   301!

On Squarespace the same mapping goes under Settings, Advanced, URL Mappings, one line per alias: /home -> / 301. On Apache use a RedirectMatch anchored to the whole path, so /homeowners/ is left alone:

RedirectMatch 301 ^/(home|home-[0-9]+|welcome)/?$ /

The redirect is the signal Google is looking for. Its redirect documentation says "Googlebot follows the redirect, and the indexing pipeline uses the redirect as a signal that the redirect target should be canonical," and its site-move guidance is to keep redirects "for as long as possible, generally at least 1 year." The Broken Link Fix Generator turns an old-to-new URL map into the Netlify, Apache, nginx and Vercel versions of these rules in one pass, plus a sed patch for links still pointing at the alias; the Internal Link Auditor finds those links.

Step 3: fix the sitemap and the homepage template. Confirm the homepage emits <link rel="canonical" href="https://example.com/">. Regenerate the sitemap so the root appears once, with its trailing slash, and no alias remains:

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url><loc>https://example.com/</loc><lastmod>2026-09-21</lastmod></url>
  <url><loc>https://example.com/pricing/</loc><lastmod>2026-09-21</lastmod></url>
</urlset>

Resubmit it under Indexing, Sitemaps in Search Console. The protocol requires that "all URLs in a Sitemap must be from a single host," so a sitemap that mixes the old and new domains is broken twice over; fix the host at the source, as in step 1.

Step 4: gate it. Both detectors reduce to a few lines against the built output. This is the shape of a pre-deploy check that fails the deploy when a page has no canonical, a canonical leaves the host, or the sitemap lists the root more than once or any alias at all:

// scripts/check-canonical-targets.mjs (run before every deploy; exit 1 blocks it)
import fs from 'node:fs';
import path from 'node:path';

const SITE = new URL('https://example.com/');
const strip = h => h.replace(/^www\./i, '').toLowerCase();
const ALIAS_RE = /\/(home(?:[-_][0-9a-z]+)?|welcome|index(?:[-_]old)?|landing(?:[-_]old)?|start[-_]here[-_](?:old|copy)|home[-_](?:copy|old|new|test))\/?$/i;
const problems = [];

function walk(dir) {
  for (const f of fs.readdirSync(dir, { withFileTypes: true })) {
    const p = path.join(dir, f.name);
    if (f.isDirectory()) { walk(p); continue; }
    if (!f.name.endsWith('.html')) continue;
    const html = fs.readFileSync(p, 'utf8');
    const tag = (html.match(/<link\b[^>]*\brel=["']canonical["'][^>]*>/i) || [])[0];
    if (!tag) { problems.push(p + ': no canonical'); continue; }
    const href = (tag.match(/\bhref=["']([^"']+)["']/i) || [])[1] || '';
    let target;
    try { target = new URL(href); } catch { problems.push(p + ': relative or invalid canonical ' + href); continue; }
    if (strip(target.hostname) !== strip(SITE.hostname)) problems.push(p + ': canonical points to ' + target.hostname);
  }
}
walk('_site');

const sitemap = fs.readFileSync('_site/sitemap.xml', 'utf8');
const locs = [...sitemap.matchAll(/<loc>([^<]+)<\/loc>/g)].map(m => m[1].trim());
const roots = locs.filter(u => new URL(u).pathname === '/');
if (roots.length !== 1) problems.push('sitemap lists the root ' + roots.length + ' times');
for (const u of locs) if (ALIAS_RE.test(u)) problems.push('sitemap lists a homepage alias: ' + u);

if (problems.length) { console.error(problems.join('\n')); process.exit(1); }
console.log('canonical targets: clean');

Step 5: verify. Run the sitemap through the Canonical Cluster Map. It fetches each listed URL (up to 100 per run), reads the canonical, and groups pages by canonical target, so every page whose canonical points at a foreign host shows up under that foreign URL as a cluster heading, with its members flagged "canonicalized," across the whole site instead of the one page the analyzer fetched. The copied fix prompt counts those external targets on their own line. Then re-run the Mega Analyzer: Canonical on same origin should pass with an empty detail, and the alias row should be gone.

When to leave it alone

The www case is already handled, so a canonical from the apex to www or back never appears here. A canonical from a real subdomain to the main site is a judgment call. If blog.example.com republishes each post on example.com/blog/ on purpose and the copy on the subdomain is the one that should not rank, the canonical is doing its job and the warn is noise; leave it, and write down why. If the subdomain is the only place the content lives, the canonical is wrong.

A genuine syndication copy on your own site, pointing at the original on the publisher's domain, is the one cross-domain canonical Google's documentation contemplates, and the row will flag it every time. Keep it if you are the copy. Consider noindex instead, per the guidance quoted above, and never put that canonical on the original.

For the alias detector, read the paths in the detail line before acting. /home-inspection/ on an inspector's site, /home-services/ on a contractor's, /welcome/ for a real new-patient page and /landing/ for a real campaign page all match the pattern and are all legitimate URLs with their own content. There is no allowlist in the analyzer. The row is right that these are separate URLs and wrong that they are homepages; if they hold distinct content, they belong in the sitemap and the row stays. What you should never leave alone is an alias that renders the same page as /. That one is a duplicate whatever it is called, and the 301 is the answer.

Fact-check notes and sources

  • Source: https://www.rfc-editor.org/rfc/rfc6596 establishes that the canonical link relation exists to "designate an Internationalized Resource Identifier (IRI) as preferred over resources with duplicative content," that the target may "Exist on a different hostname or domain," and that it may "Be self-referential."
  • Source: https://developers.google.com/search/docs/crawling-indexing/canonicalization establishes the factors Google weighs ("whether the page is served over HTTP or HTTPS, redirects, presence of the URL in a sitemap, and rel="canonical" link annotations") and that "indicating a canonical preference is a hint, not a rule."
  • Source: https://developers.google.com/search/docs/crawling-indexing/consolidate-duplicate-urls establishes the definition of the canonical element as indicating "that another page is representative of the content on the page," the guideline to "Use absolute paths rather than relative paths," and the guideline to "link to the canonical URL rather than a duplicate URL."
  • Source: https://developers.google.com/search/docs/crawling-indexing/canonicalization-troubleshooting establishes that the canonical element "is not recommended for those who want to avoid duplication by syndication partners," that "The most effective solution is for partners to block indexing of your content," that an injected "cross-domain rel="canonical" link annotation" is a known attack, and that "Google might choose a different canonical for various reasons."
  • Source: https://support.google.com/webmasters/answer/7440203 establishes the Page indexing statuses "Alternate page with proper canonical tag" (a page that "correctly points to the canonical page, which is indexed, so there is nothing you need to do") and "Duplicate, Google chose different canonical than user."
  • Source: https://developers.google.com/search/docs/crawling-indexing/301-redirects establishes that "Googlebot follows the redirect, and the indexing pipeline uses the redirect as a signal that the redirect target should be canonical," and to "Use permanent redirects when you're sure that the redirect won't be reverted."
  • Source: https://developers.google.com/search/docs/crawling-indexing/site-move-with-url-changes establishes that "Each new URL should have a self-referencing rel="canonical" link tag," that the new site's canonicals must use the new URLs once redirects are active, and to keep redirects "generally at least 1 year."
  • Source: https://www.sitemaps.org/protocol.html establishes that <loc> is the "URL of the page," must "begin with the protocol" and "end with a trailing slash, if your web server requires it," and that "all URLs in a Sitemap must be from a single host."
  • The www-only tolerance, the first-tag-only read, the alias pattern list, the trailing-slash rule for the root, and the two alias conditions come from the Mega Analyzer source at https://jwatte.com/tools/mega-analyzer/ (view source; search for canonical_same_origin and duplicate_home_aliases).

Related reading

The staging-host canonical is the classic handoff defect: the site looks perfect on the preview URL and quietly credits that URL after launch. The $20 Dollar Agency treats the pre-launch canonical and sitemap check as part of the delivery, not the retainer, for exactly this reason.

← Back to Blog

Accessibility Options

Text Size
High Contrast
Reduce Motion
Reading Guide
Link Highlighting
Accessibility Statement

J.A. Watte is committed to ensuring digital accessibility for people with disabilities. This site conforms to WCAG 2.1 and 2.2 Level AA guidelines.

Measures Taken

  • Semantic HTML with proper heading hierarchy
  • ARIA labels and roles for interactive components
  • Color contrast ratios meeting WCAG AA (4.5:1)
  • Full keyboard navigation support
  • Skip navigation link
  • Visible focus indicators (3:1 contrast)
  • 44px minimum touch/click targets
  • Dark/light theme with system preference detection
  • Responsive design for all devices
  • Reduced motion support (CSS + toggle)
  • Text size customization (14px–20px)
  • Print stylesheet

Feedback

Contact: jwatte.com/contact

Full Accessibility StatementPrivacy Policy

Last updated: April 2026