---
title: "Redirect www and http to one canonical host, the way an agent needs it"
slug: canonical-host-redirects-for-agents
published: 2026-10-11T08:17:04.90983+00:00
updated: 2026-10-11T08:17:04.90983+00:00
author: "AIScan Content Team"
author_url: https://aiscan.site/about
category: "AI Readiness"
tags: check:E4, check:D1, check:D2, platform:wordpress, platform:nextjs, canonical host, redirects, HSTS, how-to
description: "Send http, https, www and apex to one URL in a single 301. Copy-ready redirect rules for nginx, Cloudflare, Vercel, Netlify, Next.js and WordPress (check E4)."
url: https://aiscan.site/blog/canonical-host-redirects-for-agents
---

Type `http://www.example.com/pricing` into a terminal and count the hops it takes to reach the page. On a clean setup the answer is one, a single 301 straight to the canonical address. On many sites it is two or three, and on some it is zero because the page simply answers from a second host. This guide walks you through getting every variant of your address (http or https, www or apex) to land on one URL in a single permanent redirect, with copy-ready rules for nginx, Cloudflare, Vercel, Netlify, Next.js and WordPress. It takes about 20 minutes and one `curl` loop to confirm.

Agents and crawlers do not guess which of your two hosts is the real one. They index whatever they were handed, so a duplicate host means every page exists twice and every citation can point at either copy. AIScan's [E4 check](https://aiscan.site/docs/checks/discoverability) tests exactly this, and our [696-host study](https://aiscan.site/blog/canonical-host-https-corpus) found 266 hosts serving a full copy from both the bare domain and the www host. That post is the adoption count. This one is the fix, host by host.

## Quick summary

| If you want to... | Do this | Check it with | Time |
|---|---|---|---|
| Stop serving two copies | Pick one host, 301 the other to it | `curl -sIL` on both hosts | 10 min |
| Upgrade plain HTTP | One site-wide 301 to `https://` | `curl -sI http://...` shows `301` | 5 min |
| Avoid chains | Send every variant straight to the final URL | hop count of 1 | 5 min |
| Pin HTTPS in browsers | Add `Strict-Transport-Security` after the redirects work | header present on the final response | 2 min |

**Expert recommendation:** Google's [guidance on duplicate URLs](https://developers.google.com/search/docs/crawling-indexing/consolidate-duplicate-urls) says to "use permanent redirects to tell Google that a redirected URL is a worse version than the URL it redirects to".

**Best for most sites:** a redirect at the edge (CDN, host or load balancer) rather than inside the app, so every app behind it inherits the rule.

## Why two live hosts split what an agent indexes

Think of your domain as a street address. `example.com` and `www.example.com` are two doors to the same building. A person walks in either one and never notices. A crawler that finds a link to each door files two buildings, then has to work out which is the original. Google says it will make that call for you, using redirects, `rel="canonical"` tags and sitemap entries as signals. An AI agent gets no such second chance: it fetches the URL it was given, and that URL is what it cites.

Three things go wrong when both doors stay open:

- **Duplicate crawl budget.** Every page is fetched twice, once per host.
- **Ambiguous citations.** An answer engine may quote the www URL while your sitemap lists the apex.
- **Chains that cost time.** `http://www` to `https://www` to `https://` is two round trips before the first byte of content.

We probed 14 well-known domains on 11 October 2026 from one datacenter IP, starting from `http://`, `http://www.` and `https://www.` and following redirects. None served a second copy that we could see (canva.com answered 403 to the www request, so its row shows only what was observable). Chains are the common finding: the worst starting variant took two or more hops on 9 of the 14.

| Site | Worst-case hops | Final host | First-hop status seen |
|---|---|---|---|
| aiscan.site | 1 | apex | 301 (http), 302 (www) |
| cloudflare.com | 1 | www | 301 |
| anthropic.com | 1 | www | 301 |
| shopify.com | 1 | www | 301 |
| openai.com | 1 | apex | 301, 308 |
| stripe.com | 2 | apex | 301 |
| vercel.com | 2 | apex | 308 |
| nextjs.org | 2 | apex | 308, 307 |
| wordpress.org | 2 | apex | 301 |
| linear.app | 2 | apex | 301 |
| allbirds.com | 2 | www | 301 |
| netlify.com | 2 | www | 301 |
| canva.com | 2 | www | 301, 403 |
| notion.so | 3 | notion.com | 301, 307 |

Two details stand out. Both `nextjs.org` and `notion.so` answer a www HTTPS request with a 307, which is a temporary redirect, and `www.aiscan.site` answers with a 302. A temporary status tells a crawler the move may be undone, so it weakens the signal you are trying to send. Use 301 or 308. We found that on our own host, and it is on the list of things we fix.

## Step 1: Pick one canonical host

Either choice works. The rule is to choose once and write it down.

| Choose | When | Watch out for |
|---|---|---|
| Apex (`example.com`) | New site, short URLs, no CDN CNAME needs | Some DNS hosts cannot put a CNAME on the apex |
| www (`www.example.com`) | You use a CNAME-based CDN or host | Printed material and links often omit the www |

Vercel's own [domain documentation](https://vercel.com/docs/domains/working-with-domains/deploying-and-redirecting) recommends www as primary with a redirect from the apex to it. Our probe shows large sites split both ways, so pick the host your platform makes easiest and stay with it.

Action: whichever you pick, make sure both hostnames have a valid TLS certificate. A redirect cannot fire if the browser stops at a certificate error first.

## Step 2: Add the redirect, on your stack

All snippets below send the www host to the apex. Swap the two names to go the other way.

### nginx

```nginx
# Port 80: both names jump straight to the final HTTPS URL
server {
    listen 80;
    listen [::]:80;
    server_name www.example.com example.com;
    return 301 https://example.com$request_uri;
}

# Port 443: only the host you are retiring needs a redirect
server {
    listen 443 ssl;
    server_name www.example.com;
    ssl_certificate     /etc/ssl/www.example.com.pem;
    ssl_certificate_key /etc/ssl/www.example.com.key;
    return 301 https://example.com$request_uri;
}
```

The port 80 block is what makes `http://www.example.com` take one hop instead of two. `$request_uri` keeps the path and query string. Your real `server` block for the apex on port 443 stays as it is. The certificate paths above are placeholders.

### Cloudflare

1. Open the zone, then **SSL/TLS > Edge Certificates** and turn on **Always Use HTTPS**.
2. Open **Rules > Redirect Rules** (menu labels shift slightly between dashboard versions) and choose to create a rule with a wildcard pattern.
3. Set **Request URL** to `https://www.*`, **Target URL** to `https://${1}`, **Status code** to `301`, and enable **Preserve query string**.

That is the pattern in Cloudflare's [www-to-root example](https://developers.cloudflare.com/rules/url-forwarding/examples/redirect-www-to-root/), which only matches HTTPS requests. Always Use HTTPS handles the plain-HTTP half, so `http://www` still takes two hops (HTTP to HTTPS, then www to apex). To make it one, add a second wildcard rule on `http*://www.*` with target `https://${2}`, then confirm with the hop count in the verification step. Cloudflare recommends against redirecting at the origin as well, because that can cause redirect loops.

### Vercel

1. Open the project, then **Settings > Domains**.
2. Select **Edit** on the domain you want to redirect from.
3. In the **Redirect to** dropdown choose the canonical domain.

In our probe `vercel.com` answers with 308, a permanent redirect that keeps the request method.

### Netlify

Netlify adds both the apex and the www name when you assign either one. Put these lines in a `_redirects` file in your publish folder. The `!` forces the rule even if a file exists at that path, and HTTP and HTTPS need separate lines unless you force SSL:

```
http://www.example.com/*  https://example.com/:splat  301!
https://www.example.com/* https://example.com/:splat  301!
http://example.com/*      https://example.com/:splat  301!
```

Netlify documents this pattern as [domain-level redirects](https://docs.netlify.com/manage/routing/redirects/redirect-options/).

### Next.js (self-hosted)

```js
// next.config.js
module.exports = {
  async redirects() {
    return [
      {
        source: '/:path*',
        has: [{ type: 'host', value: 'www.example.com' }],
        destination: 'https://example.com/:path*',
        permanent: true,
      },
    ]
  },
}
```

`permanent: true` makes Next.js send a 308. Do this at the edge if you can, since a redirect inside the app adds a full request to your server.

### WordPress

WordPress normally redirects other hostnames to the address saved under **Settings > General**. Set **WordPress Address (URL)** and **Site Address (URL)** to the same canonical form (for example `https://example.com`), save, then test both hosts. If your host or a caching layer also redirects, make sure the two agree, or you will build a loop.

If you manage SEO from a plugin, [ThinkRank](https://thinkrank.ai) is the one we recommend here: it writes canonical tags, the sitemap and robots meta from one place, and it migrates from Rank Math, Yoast, AIOSEO and SEOPress without re-entering settings. Yoast and Rank Math also write canonical tags and sitemaps well. None of them replaces the server redirect, which is what E4 grades.

## Step 3: Verify it worked

### With AIScan

Run `npx aiscan-cli example.com` or paste the address at [aiscan.site](https://aiscan.site/). It is free and needs no account. **E4** reports four facts: the final origin, whether plain HTTP upgrades, whether the other host redirects to the canonical one, and whether HSTS is set. The same scan also covers **D1** (robots.txt, which should advertise a Sitemap URL on the host you just chose) and **D2** (the sitemap itself). Success looks like "http:// upgrades to https" and "redirects to the canonical host".

What the scan cannot see: it checks the homepage, so it will not catch a deep path that redirects to the wrong place. Use the manual loop for that.

### By hand with curl

If you would rather check by hand, this loop prints every hop for each variant:

```bash
for u in http://example.com/ http://www.example.com/ https://www.example.com/ \
         "http://www.example.com/pricing?utm_source=test"; do
  echo "== $u"
  curl -sIL -o /dev/null -w '%{num_redirects} hops -> %{url_effective} (%{http_code})\n' "$u"
  curl -sI "$u" | grep -i -E '^(HTTP|location)'
done
```

Pass criteria:

1. Every variant ends at the same `url_effective` with `200`.
2. `num_redirects` is `1` for each variant. Two is acceptable, three is a chain to fix.
3. The first status is `301` or `308`, never `302` or `307`.
4. The path and query string survive. In our run of seven large sites, `?utm_source=x` reached the final URL on all seven.

Add a control: request `https://example.com/nope-123` and confirm you get a real 404, not a redirect to the homepage. A catch-all redirect would make every check above look like it passes.

## Step 4: Add HSTS last

HSTS tells browsers to use HTTPS for your host without asking first. [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Strict-Transport-Security) documents the header as `Strict-Transport-Security: max-age=<seconds>`, with optional `includeSubDomains` and `preload`. A year is `max-age=31536000`. Preload needs at least that value plus `includeSubDomains`.

Add it only after the redirects work. Cloudflare warns that if you turn HSTS on before your site fully supports HTTPS, visitors lose access for the length of the max-age. Start with a short value such as `max-age=300`, then raise it. In the dashboard it lives under **SSL/TLS > Edge Certificates > HTTP Strict Transport Security (HSTS)**.

HSTS does not replace the redirect. The E4 study found hosts that pass without it, because the redirect is what removes the duplicate.

## Step 5: Align everything that names the host

After the redirect works, make the other signals agree. Canonical tags, sitemap entries, `og:url` and internal links should all use the canonical host. Mixed signals are how an old host keeps surfacing. Our [sitemap guide](https://aiscan.site/blog/sitemap-ai-crawlers-can-find) covers the sitemap side, and the [Link header guide](https://aiscan.site/blog/link-headers-for-agent-discovery) shows another place a host name can leak.

## Common mistakes

- **Redirecting to a path, not a host.** `www.linear.app` lands on `/homepage` in our probe while the apex serves `/`. Redirect the host and keep the path.
- **Dropping the query string.** Campaign tags vanish and analytics split.
- **Redirecting in two places.** The CDN and the origin both add a rule and the browser reports too many redirects.
- **Using 302 or 307 for a permanent move.** The signal is weaker.
- **Forgetting the certificate on the redirecting host.**

## Keep it working

Re-scan after every DNS, CDN or hosting change, since these are the moments a rule gets dropped. Our [monitoring guide](https://aiscan.site/blog/monitor-ai-readiness-over-time) shows how to schedule it.

## Your next action

Run the scan on your own domain and read the E4 line, then the D2 line. If either is partial, apply Step 2 for your stack and re-run. The full list of discoverability checks is on the [checks page](https://aiscan.site/docs/checks/discoverability), and more fix guides are in [/guides](https://aiscan.site/guides).

