URL Case Sensitivity
Why /Apple and /apple are two different URLs to Google — the Linux vs Windows/IIS filesystem mechanism behind it, the robots.txt case trap, server-level fixes for Apache, Nginx, and IIS, and how to find case duplicates in the wild.
1 evidence signal on this page
- Related live toolHTTP Status & Redirect Checker
URL paths, filenames, and query parameters are case-sensitive to Google (the hostname isn't) — so /Apple and /apple are two different URLs that can spawn duplicate content, and a robots.txt Disallow for /Private/ won't block /private/. The mechanism is your filesystem: Linux/Unix (and Apache/Nginx on it) treat paths as case-sensitive byte strings; Windows/IIS is case-insensitive by default, so the same request can 404 on one host and 200 on another. The fix is picking one case (lowercase is the convention) and enforcing it with a server-level redirect, or rel=canonical as a fallback.
Evidence for this claim URI schemes and hosts are case-insensitive, while path and query components may be case-sensitive depending on the server and application. Scope: Generic URI comparison rules. Confidence: high · Verified: IETF RFC 3986: Syntax-based normalization Evidence for this claim Google recommends consistent URL casing and treats URLs that differ by path case as potentially distinct crawlable URLs. Scope: Current Google URL consistency guidance. Confidence: high · Verified: Google Search Central: URL structure best practicesTL;DR —
/Appleand/appleare distinct URL strings, even when a server returns the same page for both. Hostnames are case-insensitive, while path and query handling depends on the server and application. Mixed variants can create duplicate crawl paths and mismatchedrobots.txtrules, so choose a casing convention and enforce it consistently.
Are URLs case-sensitive?
Yes — the part after your domain is. Google says it plainly in its own documentation: “Be aware that URLs are case sensitive.” So these two addresses are treated as two separate URLs:
https://example.com/Apple
https://example.com/appleEven if both load the exact same page, a search engine sees two different URLs with their own content. That’s the whole issue in one sentence.
The one exception is your domain name (the hostname). Example.com and
example.com are the same site — capitals in the domain never matter. It’s only
the path, the filename, and the query string — everything after the
domain — where case matters.
Why this causes problems
Two things go wrong:
- Duplicate content. If people (or your own site) link to both
/Appleand/apple, you’ve got the same page living at two addresses. Google may sort that out on its own — but it also may not, and now your rankings and links are split across two versions instead of pooled into one. - Broken
robots.txtrules. If yourrobots.txtsaysDisallow: /Private/(capital P), it does not block/private/(lowercase p). The rule only matches the exact casing you wrote.
How to fix it
- Pick lowercase. It’s the near-universal convention and what most website platforms already use.
- Make your server enforce it — set up a rule that redirects any uppercase URL to its lowercase version. (The Advanced and Scripts tabs have the actual code for Apache, Nginx, and IIS.)
- Keep your own links lowercase — in your menus, your content, and your sitemap, always link to the lowercase version.
The thing most people get wrong
“Google is smart enough that this doesn’t matter.” It’s usually smart enough to merge identical case-variant pages — but “usually” isn’t “always,” and John Mueller has said outright that “hope should not be a part of an SEO strategy.” Don’t leave it up to Google to guess.
Want the why behind all this — how your server’s operating system decides whether
/Apple works or 404s, the full robots.txt trap, and copy-paste server fixes?
Switch to the Advanced tab.
Evidence for this claim URI schemes and hosts are case-insensitive, while path and query components may be case-sensitive depending on the server and application. Scope: Generic URI comparison rules. Confidence: high · Verified: IETF RFC 3986: Syntax-based normalization Evidence for this claim Google recommends consistent URL casing and treats URLs that differ by path case as potentially distinct crawlable URLs. Scope: Current Google URL consistency guidance. Confidence: high · Verified: Google Search Central: URL structure best practicesTL;DR — Hostnames are case-insensitive; path and query comparison may be case-sensitive and ultimately depends on server and application routing. Filesystem defaults often influence behavior, but do not define URL semantics by themselves. Google can crawl differently cased paths as distinct URLs; it can canonicalize them together when content matches, but “usually… not always ideal” is not a strategy.
robots.txtvalues are case-sensitive too, so aDisallowfor one casing silently misses the others — a distinct access problem, not just a duplicate-content one. Fix priority: prevent variants at the source, then a server-level 301 to lowercase (ApacheRewriteMap tolower, Nginxmap, IIS URL Rewrite), withrel=canonicalas a fallback when you can’t touch the server.
What is (and isn’t) case-sensitive
Start with the exact boundary, because casual phrasing (“URLs are case-sensitive”) gets it wrong half the time. John Mueller drew the line cleanly: “URL path, filename, and query parameters are case-sensitive, the hostname / domain name aren’t. Case-sensitivity matters for canonicalization, so it’s a good idea to be consistent there.”
So:
| URL part | Case-sensitive? | Why |
|---|---|---|
Scheme (https://) | No | Fixed protocol tokens |
Hostname (example.com) | No | DNS resolution is case-insensitive at the protocol level |
Path (/Products/Shoes) | Yes | Resolved against a filesystem/router that compares casing |
Filename (/Logo.png) | Yes | Same — it’s part of the path |
Query string (?Color=Red) | Yes | Parameter keys and values are compared as-is |
EXAMPLE.com/page and example.com/page are the same URL. example.com/Page and
example.com/page are not. This is the same class of “one page, many URLs” problem
that trailing slashes, www vs non-www, and query parameters create — the URL
structure and canonicalization deep dives cover those variants, and I won’t
re-derive them here; casing is one more axis in the same duplicate-URL grid.
That table is the URL-handling default engines like Google follow, per the spec — not
a promise about what your specific origin server, CDN, or application will actually
return. Treat it as where to start testing, not as a substitute for testing: request
the path in both casings and read the real response (the Scripts tab has a copy-paste
curl check) before you assume the rule applies to your stack.
One more edge case worth flagging rather than glossing over: Unicode slugs. Two
visually identical characters — a Latin “a” and a Cyrillic “а,” for example — can be
different code points that survive ASCII-style lowercasing completely untouched,
because lowercasing operates on the characters you have, not the ones a reader
perceives. If you generate slugs from non-English titles, decide your encoding and
normalization policy up front rather than assuming a .toLowerCase() call catches
everything international.
Why this happens: it’s your filesystem
Most write-ups state “URLs are case-sensitive” as received wisdom and move on. The useful part is why, because it explains the single most confusing symptom — the same URL working on one server and 404-ing on another.
Linux/Unix filesystems are case-sensitive. On the ext4, XFS, and similar
filesystems that run the overwhelming majority of the web, Apple and apple are
literally different directory entries — different inodes. When Apache or Nginx maps
an incoming request path to a file or a route, it compares the casing byte-for-byte.
Ask for /Apple when only /apple exists and you get a genuine 404.
Windows/NTFS is case-insensitive by default — but case-preserving. It stores
Apple with its capital A intact (so it displays “correctly”), yet when it looks
the name up, it ignores case. IIS, Microsoft’s web server, inherits that
behavior: request /Apple or /APPLE or /apple and IIS serves the same file. It
doesn’t fix the SEO problem — Google still sees distinct URLs — but the server
itself will happily 200 all of them.
The consequence is the classic dev-to-prod bug: a developer on Windows/IIS types a
path with the wrong case, it works fine locally because Windows doesn’t care, then
the same request 404s the moment it hits a Linux/Apache/Nginx production server
that does. Nothing in your CMS or SEO plugin caused it — the two machines’ operating
systems just disagree about whether case matters. (Microsoft documents this behavior
directly in its
Windows case-sensitivity guidance.)
This is worth knowing during any platform migration: move a site between a case-insensitive host and a case-sensitive one and mixed-case URLs that “always worked” can suddenly start breaking or duplicating.
The filesystem is the bottom of the stack, not the whole stack. Everything above it — a reverse proxy, a CDN edge, a load balancer, or the application’s own router — gets a chance to normalize, rewrite, or short-circuit a request’s casing before it ever reaches the filesystem the origin server sits on. A Linux origin doesn’t guarantee case-sensitive behavior at the URL you actually request if something in front of it is already folding cases together, and an application router can just as easily impose its own case rules independent of the OS underneath it. “Linux + Apache/Nginx = case-sensitive” is the right default assumption, not a substitute for checking the actual response on your stack.
How Google actually treats case-different URLs
Google isn’t inventing case sensitivity — it’s following the URL spec that every
compliant HTTP client follows. From the docs: “Like any other HTTP client following
IETF STD 66, Google Search’s URL handling is case sensitive (for example, Google
treats both /APPLE and /apple as distinct URLs with their own content).” That
STD 66 grounding matters: this is standards behavior, not a Google quirk.
Google’s own advice is to normalize: “If upper and lower case text in a URL is treated the same by your web server, convert all text to the same case so it’s easier for Google to determine that URLs reference the same page.” Note the “if” — that’s aimed squarely at case-insensitive servers (IIS) that serve every casing, which is exactly where the duplicate risk lives.
Can Google merge case-duplicates on its own? Often, yes — through canonicalization, casing is one of the common duplicate-URL patterns it groups. Mueller: “If a website still shows the same content in these cases, search engines will try to figure it out on their own and usually that works out well. But it’s not always ideal.” And in a separate exchange about mismatched canonicals on uppercase URLs, he was sharper: “If it serves the same content, it’ll probably be seen as a duplicate and folded together, but ‘hope’ should not be a part of an SEO strategy.”
That’s the honest framing. This isn’t a five-alarm fire — but relying on Google to guess right is a choice you don’t have to make when the fix is a redirect rule.
There’s also a crawl-efficiency cost. Mueller: “Search engines will try to crawl all variations of the URL that they find. This can make it a bit slower for them to find other useful content on your website.” If your site is spraying case-variant URLs into the link graph, bots waste fetches re-crawling the same content in different casings instead of discovering your real pages — the same crawl-waste dynamic the parameters and crawl-budget topics describe, just with casing as the multiplier.
How Bing treats case-different URLs
Bing behaves differently, and honesty about sourcing matters here: there is no dedicated Bing documentation page on URL case sensitivity comparable to Google’s STD 66 callout, so this is based on webmaster reports and Microsoft community threads, not a formal spec.
What those reports consistently describe: Bingbot tends to normalize toward lowercase — crawling and indexing the lowercase version of a URL it discovers, and Bing Webmaster Tools has been observed auto-lowercasing URLs submitted in sitemaps. Webmasters have raised both behaviors on the Microsoft Community Hub. So Bing appears to do more of the case-collapsing for you than Google’s strict distinct-URL treatment does.
Caveat: this is Bing’s practical behavior per webmaster reports and community threads, not an official policy statement. I’m not going to invent a Bing spokesperson quote — none exists for this specific topic. Treat it as “behaves differently, less formally documented,” and verify against your own Bing Webmaster Tools data if it matters to you.Either way, the fix is the same. Standardizing on lowercase satisfies Google’s distinct-URL model and aligns with whatever Bing is normalizing toward — you don’t optimize for one engine’s behavior at the expense of the other.
The robots.txt case trap
This deserves its own section because it’s a different kind of failure from
duplicate content. Duplicate content splits signals; a broken robots.txt rule is
an access-control failure — a path you meant to keep bots out of gets crawled
anyway.
The rule, straight from Google’s robots.txt spec: the directive name is
case-insensitive, but its value is case-sensitive. “The field name (disallow)
is case-insensitive, but its value is case-sensitive.” And: “The path value must
start with / to designate the root and the value is case-sensitive.” Google’s own
example spells it out — a rule for /fish “Matches any path that starts with
/fish. Note that the matching is case-sensitive.”
So Disallow, disallow, and DISALLOW all work identically — the directive name
casing is irrelevant. But the path value is matched exactly. Mueller confirmed
the practical implication directly: “The robots.txt file also uses exact URLs, so if
you have entries there which refer to one version of a URL they would not apply to
other versions.”
Two concrete ways this bites — the second is the more dangerous:
Example 1 — the classic. Your robots.txt has:
User-agent: *
Disallow: /Private/That blocks /Private/. It does nothing for /private/. If anything on your
site links to the lowercase version, it’s fully crawlable despite your rule.
Example 2 — the post-migration mismatch. You replatform, and the new CMS
generates cart and admin paths in lowercase. Your old robots.txt, copied over
verbatim, still says:
Disallow: /Checkout/
Disallow: /Admin/The live URLs are now /checkout/ and /admin/. The disallows silently miss them,
and thin, no-value (or sensitive) paths get crawled and can end up indexed. This is
exactly the scenario migration teams walk into, because robots.txt almost never
gets audited against the actual casing of the new URLs.
(To be clear, this rarely causes catastrophic problems in practice — Mueller has said case mismatches in robots.txt are rare to see cause real issues. But “rare and silent” is precisely the kind of bug that sits unnoticed for months, so it’s worth a five-minute check.)
The fix for the trap is the same discipline as everywhere else: write your
robots.txt rules in the casing your URLs actually use, and enforce a single casing
so there’s only one version to block.
Fixing case-duplicate URLs
Standard technical-SEO remediation hierarchy, most to least preferred:
1. Prevent variants at the source
The best fix is never generating mixed-case URLs in the first place — this is a CMS/URL-generation-layer concern, and it varies by platform (verify current behavior on your own stack rather than trusting a blanket claim):
- Shopify lowercases product and collection handles automatically, so native URLs are largely safe — but app-generated or legacy-imported URLs can still introduce case variants.
- WordPress permalinks are lowercase by convention, but custom post types, tags, and manually entered slugs can introduce mixed case; Yoast and RankMath don’t natively force-lowercase URLs.
- Enterprise, custom, and Java/.NET-backed platforms are the most exposed — casing often falls out of the routing framework and hosting OS with no deliberate policy, especially on Windows/IIS stacks where nothing forces the issue locally.
2. Server-level lowercase redirect (the definitive fix)
A 301 to the canonical lowercase URL is the hard fix — it consolidates signals and sends users/bots to one address. The implementation differs by server (full copy-paste config is in the Scripts tab):
- Apache has a native lowercasing tool —
RewriteMapwithint:tolower— so you can convert an entire path to lowercase in a rewrite rule. - Nginx has no built-in string-lowercasing function, so it’s genuinely more
involved than Apache’s one-liner: you either use the
njs/Lua module to lowercase the URI, or build an explicitmaplookup that catches uppercase characters. Don’t let anyone tell you it’s a like-for-likemapone-liner — it isn’t. - IIS uses the URL Rewrite module with a rule condition and the
{ToLower:...}function. Since IIS serves every casing by default, this is where enforcement matters most.
Don’t ship a blanket sitewide rule blind. Lowercase is the right convention for new paths, but a mixed-case-to-lowercase redirect is not automatically safe on an existing site — inventory your actual case variants first (crawl export, access logs, sitemap, internal links), and specifically check for paths where the case is legitimate and load-bearing: uploaded filenames, generated tokens, anything a CMS or app produced with intentional mixed case. Confirm each route actually returns equivalent content in both casings before you fold it into the rule, roll the redirect out in a bounded way rather than flipping every path at once, and watch error rates and the GSC Page indexing report afterward — there’s no guarantee a lowercase cleanup recovers lost rankings or crawl coverage, only that it stops the signal-splitting going forward.
3. rel=canonical as a fallback
When you can’t touch server config — shared hosting, a platform that won’t let you
add rewrite rules, or a case where legitimate case-variant URLs must stay live — a
rel=canonical pointing every variant at the lowercase version is the safety net.
It’s a hint, not a directive, and weaker than a 301 — but far better than
nothing. Mueller’s recommendation: “Using internal linking to link to a consistent
version makes your preference clear. Adding a link rel=“canonical” element also
helps to confirm that.”
That said, canonical only works once you’ve confirmed the variants actually serve
duplicate content. If a case variant returns genuinely different content, or an
error, a rel=canonical element can’t merge it — a hint can’t consolidate two
different resources into one. Verify the response before you point a canonical at
it, not after.
4. Keep internal links and sitemaps consistent
Whatever casing you choose, your own links have to agree with it. Every internal link,
navigation entry, and sitemap URL should use the canonical (lowercase) version. A
perfect redirect rule undermined by menus that still link to /Products/ just makes
bots follow redirect hops they didn’t need to.
How to find case-duplicate URLs on your site
Three complementary methods — GSC shows what Google actually did; crawlers let you catch variants before they become an indexing problem:
- Google Search Console → Page indexing report. Look for “Duplicate without user-selected canonical” and “Duplicate, Google chose different canonical than user” statuses, then eyeball the flagged URL pairs for case differences. GSC won’t label the cause as “casing” — it reports every duplicate cause the same way — so you have to spot the case-only pairs yourself.
- Ahrefs Site Audit. A crawl surfaces near-duplicate URLs; casing differences show up as separate crawled URLs with identical or near-identical content, worth cross-checking under the duplicate-content reporting.
- Screaming Frog. Export the full crawl, lowercase the URL column, and sort/filter
to spot pairs that differ only in case. You can also test specific known paths in
both casings to confirm server behavior — does
/Applereturn200,301, or404? That single test tells you whether your server is case-insensitive (IIS-style200), already enforcing lowercase (301), or case-sensitive with no variant (404).
Where this sits
Case sensitivity is one axis in the broader duplicate-URL problem this cluster keeps
circling — it compounds with trailing slashes, www vs non-www, and query
parameters, and it’s one of the roughly 40 signals that feed canonicalization. The
URL structure hub, the trailing slash and URL parameters deep dives, and the
canonicalization article each cover their own axis; the discipline is identical
across all of them — pick one clean version and enforce it with redirects,
canonicals, consistent internal links, and matching sitemaps.
AI summary
A condensed take on the Advanced version:
- What’s case-sensitive: the path, filename, and query string — not the
hostname.
/Apple≠/apple;Example.com=example.com. Google follows IETF STD 66, so it treats casings as distinct URLs with their own content. Treat the rule as a default to verify, not a guarantee — request both casings and read the real response for your own stack. Non-ASCII slugs are a separate risk: visually identical Unicode characters can be different code points that survive lowercasing untouched, so international slugs need an explicit encoding/normalization policy. - Why it happens — the filesystem: Linux/Unix (and Apache/Nginx on it) are
case-sensitive —
Appleandappleare different files. Windows/NTFS and IIS are case-insensitive by default (case-preserving). So the same request can200on IIS and404on Linux — the classic dev-to-prod / migration bug. But the filesystem is the bottom of the stack, not the whole stack: a proxy, CDN, load balancer, or application router in front of it can override that default before a request ever reaches the filesystem. - Google can merge case-duplicates via canonicalization, but “usually… not always ideal” — and “hope should not be a part of an SEO strategy.” There’s also a crawl-efficiency cost: bots waste fetches crawling every casing.
- Bing appears to normalize toward lowercase (crawls/indexes the lowercase version, auto-lowercases sitemap URLs) — per webmaster reports, not an official spec.
- The robots.txt trap (an access failure, not a duplicate one): the directive
name is case-insensitive but the path value is case-sensitive.
Disallow: /Private/does not block/private/. Watch for post-migration mismatches (/Checkout/rule vs. lowercase live paths). - Fix priority: (1) prevent variants at the CMS/source; (2) server-level 301 to
lowercase — Apache
RewriteMap int:tolower, Nginx vianjs/Lua or amaptable (no native lowercasing — and make sure the redirect preserves the query string with$is_args$args, since the njs function only lowercases the path), IIS URL Rewrite{ToLower:...}; (3)rel=canonicalas a fallback, only once you’ve confirmed the variant actually serves duplicate content; (4) keep internal links and sitemaps consistent. Before a sitewide redirect, inventory legitimately case-sensitive paths (uploaded files, tokens) and roll it out bounded — there’s no ranking or crawl recovery guarantee, only that it stops future signal-splitting. - Detect it: GSC Page indexing report (duplicate statuses → eyeball case pairs),
Ahrefs Site Audit, Screaming Frog (lowercase-and-sort the export; test
/Applefor200/301/404). - Compounds with trailing slash, www/non-www, and parameters — same fix: pick one version, enforce it.
Official documentation
Primary-source documentation on case handling.
- URL structure best practices — “Be aware that URLs are case sensitive”; the IETF STD 66
/APPLEvs/appleframing; the convert-to-same-case recommendation. - How Google interprets the robots.txt specification — the directive name is case-insensitive but the path value is case-sensitive; the
/fishcase-sensitive-matching example. - Canonicalization — casing listed among the common duplicate-URL scenarios (alongside HTTP/HTTPS, www, trailing slash, and parameters).
- Page indexing report — Search Console Help — the “Duplicate without user-selected canonical” and “Duplicate, Google chose different canonical than user” statuses that surface case-duplicates.
Bing / Microsoft
- Bing changing URLs from upper to lower case — Microsoft Community Hub — webmaster reports of Bing’s lowercase normalization (community evidence, not an official spec page).
- Adjust case sensitivity — Microsoft Learn — Windows/NTFS case-insensitive-but-case-preserving behavior, the mechanism behind the IIS-vs-Linux difference.
Quotes from the source
On-the-record statements from Google’s documentation and John Mueller. Where the source is documentation, the link deep-links to the passage.
Google Search Central docs — URLs are case-sensitive
- “Be aware that URLs are case sensitive.” Jump to quote
- “Like any other HTTP client following IETF STD 66, Google Search’s URL handling is case sensitive (for example, Google treats both /APPLE and /apple as distinct URLs with their own content).” Jump to quote
- “If upper and lower case text in a URL is treated the same by your web server, convert all text to the same case so it’s easier for Google to determine that URLs reference the same page.” Jump to quote
Google Search Central docs — robots.txt is case-sensitive
- “The field name (disallow) is case-insensitive, but its value is case-sensitive.” Jump to quote
- “The path value must start with / to designate the root and the value is case-sensitive.” Jump to quote
- “Matches any path that starts with /fish. Note that the matching is case-sensitive.” Jump to quote
John Mueller, Google — what is (and isn’t) case-sensitive
- “URL path, filename, and query parameters are case-sensitive, the hostname / domain name aren’t. Case-sensitivity matters for canonicalization, so it’s a good idea to be consistent there.” Coverage (Search Engine Journal)
John Mueller, Google — don’t rely on Google figuring it out
- “If it serves the same content, it’ll probably be seen as a duplicate and folded together, but ‘hope’ should not be a part of an SEO strategy.” Coverage (Search Engine Journal)
- “If a website still shows the same content in these cases, search engines will try to figure it out on their own and usually that works out well. But it’s not always ideal.” Coverage (Search Engine Journal)
John Mueller, Google — robots.txt and crawl efficiency
- “The robots.txt file also uses exact URLs, so if you have entries there which refer to one version of a URL they would not apply to other versions.” Coverage (Search Engine Journal)
- “Search engines will try to crawl all variations of the URL that they find. This can make it a bit slower for them to find other useful content on your website.” Coverage (Search Engine Journal)
- “Using internal linking to link to a consistent version makes your preference clear. Adding a link rel=“canonical” element also helps to confirm that.” Coverage (Search Engine Journal)
URL case-sensitivity checklist
A quick pass to catch and close case-duplicate risk:
- Decide on a single casing convention — lowercase unless you have a hard reason not to.
- Test a known path in both casings (
/Appleand/apple): does the uppercase version301to lowercase, or200/404? Anything but a301is a gap. - Know your host OS/server: Linux + Apache/Nginx = case-sensitive (mixed-case
links can
404); Windows + IIS = case-insensitive (every casing200s → duplicate risk). - Before deploying a blanket lowercase redirect, inventoried existing paths where case is legitimate (uploaded filenames, tokens, generated slugs) and confirmed they’re excluded or tested for equivalence — not just assumed safe.
- Server-level lowercase redirect rule is in place (Apache
RewriteMap, Nginxmap/njs, or IIS URL Rewrite) and, if Nginx, redirects preserve the original query string ($is_args$args) rather than dropping it. - Every
robots.txtDisallow/Allowvalue matches the actual casing of your live URLs — no/Private/rules guarding/private/paths. - Internal links, navigation, and menus all use the canonical (lowercase) casing.
- XML sitemap lists only the canonical-cased URLs.
-
rel=canonicalpoints every reachable case-variant at the lowercase version (as a backstop, especially where you can’t add a redirect). - GSC Page indexing report checked for duplicate statuses; flagged pairs eyeballed for case-only differences.
- Post-migration:
robots.txt, canonicals, and internal links re-audited against the new platform’s URL casing.
URL case sensitivity — cheat sheet
What’s case-sensitive
| URL part | Case-sensitive? | Example |
|---|---|---|
| Scheme | No | HTTPS:// = https:// |
| Hostname / domain | No | Example.com = example.com |
| Path | Yes | /Shop ≠ /shop |
| Filename | Yes | /Logo.png ≠ /logo.png |
| Query string | Yes | ?Color=Red ≠ ?color=red |
Server behavior by platform
| Host / server | Filesystem | Default behavior | SEO implication |
|---|---|---|---|
| Linux + Apache/Nginx | Case-sensitive | /Apple 404s if only /apple exists | Mixed-case links break |
| Windows + IIS | Case-insensitive (case-preserving) | /Apple, /APPLE, /apple all 200 | Every casing served → duplicate URLs |
These are OS/server defaults, not guarantees — a reverse proxy, CDN, or application router in front of the origin can override them. Test the real response for your stack.
The robots.txt trap
| You wrote | It blocks | It does NOT block |
|---|---|---|
Disallow: /Private/ | /Private/ | /private/, /PRIVATE/ |
Disallow: /Checkout/ | /Checkout/ | /checkout/ |
Directive name casing (Disallow / disallow) doesn’t matter — the path value
casing does.
Fix priority
- Prevent variants at the CMS/source.
- Server-level 301 → lowercase (definitive).
rel=canonical→ lowercase (fallback, it’s a hint).- Consistent internal links + sitemap.
One-line diagnosis: request /Apple — a 301 to /apple means you’re covered;
a 200 (IIS) or 404 (Linux with no variant) means you’re not.
Enforce lowercase URLs — server config
Copy-paste-ready starting points for each server. Test against your own stack before
shipping — mod_rewrite availability, module installs, and rule ordering vary by
host, and an over-broad rule can loop or lowercase things you didn’t mean to (like
case-sensitive query values).
Apache (.htaccess / vhost) — the native tolower approach
Apache has a built-in lowercasing map. Define it once in your main server config
(RewriteMap can’t live in .htaccess), then use it in a rule:
# In httpd.conf / vhost config (NOT .htaccess):
RewriteMap lc int:tolower
# In .htaccess or vhost:
RewriteEngine On
# Only act when the path actually contains an uppercase letter
RewriteCond %{REQUEST_URI} [A-Z]
# Redirect the whole path to its lowercase form
RewriteRule (.*) ${lc:$1} [R=301,L]int:tolower is Apache’s internal function that lowercases the captured path. The
RewriteCond %{REQUEST_URI} [A-Z] guard means the rule only fires when there’s an
uppercase letter to fix, avoiding a redirect on already-lowercase URLs.
Nginx — no native lowercasing (be honest about this)
Nginx’s core map directive cannot lowercase a string on its own, so there’s no
Apache-style one-liner. Two real options:
Option A — njs (or Lua), the clean way. With the njs module, lowercase the
URI in JavaScript and redirect:
# Load the njs module and a small JS file that lowercases the URI path
js_import lower from conf.d/lower.js;
js_set $lower_uri lower.uri;
server {
# ...
# Test $uri (path only), NOT $request_uri (path + query) — the njs
# function below only lowercases the path, so the query string is
# intentionally left untouched. Testing $request_uri would fire on an
# uppercase-containing query even when the path is already lowercase.
if ($uri ~ [A-Z]) {
# $is_args$args re-attaches the original query string. Without it,
# the redirect drops any query string entirely, since $lower_uri
# (built from r.uri, which excludes the query) never contains one.
return 301 $scheme://$host$lower_uri$is_args$args;
}
}// conf.d/lower.js
function uri(r) { return r.uri.toLowerCase(); }
export default { uri };Two details that are easy to get wrong here and will silently break the fix:
matching on $request_uri instead of $uri makes the rule fire on an
uppercase query string even when the path is already lowercase, and
forgetting $is_args$args on the redirect target drops the entire query
string — tokens, filter parameters, everything — on every single redirect,
since the njs function only ever sees and lowercases the path. Test a path
that has a mixed-case query string attached before you ship this.
Option B — an explicit map lookup table, if you can’t add a module. You build a
map that only catches the uppercase-containing URIs you care about — verbose and
partial, which is exactly why Option A is preferred:
map $request_uri $has_upper {
default 0;
"~[A-Z]" 1; # flag URIs containing any uppercase letter
}
# You still need njs/Lua or per-path rewrites to do the actual lowercasing —
# map alone flags, it doesn't transform. Don't ship this as a complete fix.The takeaway: on Nginx, plan for the njs/Lua route. Anyone claiming a plain map
one-liner lowercases URLs is skipping the part where map can’t transform strings.
IIS (Windows) — URL Rewrite module
Because IIS serves every casing by default, this is where enforcement matters most.
The URL Rewrite module has a {ToLower:...} function:
<!-- web.config -->
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Lowercase URLs" stopProcessing="true">
<match url="[A-Z]" ignoreCase="false" />
<conditions>
<add input="{URL}" pattern="[A-Z]" ignoreCase="false" />
</conditions>
<action type="Redirect" url="{ToLower:{R:0}}" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>ignoreCase="false" on the match is what lets the rule see uppercase letters at
all; {ToLower:{R:0}} rewrites the matched path to lowercase; redirectType="Permanent"
issues the 301.
Verify it worked
After deploying, confirm the redirect with a single request (macOS/Linux):
# Should show: HTTP/… 301 and a Location header pointing to the lowercase path
curl -sI https://example.com/Apple | grep -Ei "^HTTP|^location"Windows (PowerShell):
# -MaximumRedirection 0 stops the redirect so you can read the 301 + Location
try { Invoke-WebRequest "https://example.com/Apple" -MaximumRedirection 0 } catch {
$_.Exception.Response.StatusCode.value__
$_.Exception.Response.Headers["Location"]
}A 301 to the lowercase URL means enforcement is live. A 200 means the server is
still serving the uppercase version; a 404 means that casing has no page (and you
likely have case-sensitive hosting with no redirect layer).
Case-sensitivity anti-patterns
The mistakes that turn a trivial config detail into a real duplicate-content or crawl problem:
1. Assuming Google will always merge case-duplicates. It often does — but “usually” isn’t “always,” and Mueller’s own “hope should not be a part of an SEO strategy” is the counter. Leaving it to canonicalization splits signals when Google guesses wrong.
2. Writing robots.txt rules in a different casing than your live URLs.
Disallow: /Private/ guarding a /private/ path is a silent no-op. The directive
name’s casing is irrelevant; the path value’s casing is exact. This is an
access-control bug, not a ranking one.
3. Copying robots.txt verbatim after a migration.
The new platform generates /checkout/ and /admin/; the old robots.txt still
disallows /Checkout/ and /Admin/. Everything you meant to block is now crawlable.
Re-audit robots.txt against the new URL casing every migration.
4. Fixing the redirect but not the internal links.
A perfect lowercase-enforcement rule undermined by menus and content still linking to
/Products/ just makes bots (and users) take an extra redirect hop every time. The
redirect is the backstop; consistent links are the actual fix.
5. Treating a rel=canonical as equivalent to a 301.
Canonical is a hint; a 301 is a directive. Use canonical only when you genuinely
can’t add a redirect — don’t reach for it first because it’s easier.
6. Believing “modern platform, so it’s handled.” Shopify lowercases native handles, sure — but imported, legacy, and app-generated URLs, plus anything on a Windows/IIS stack, still carry real risk. “Buy a modern CMS and forget about it” is not a policy.
7. Thinking lowercase is a ranking preference. Google has never said lowercase ranks better. The issue is duplicate-content consolidation and crawl efficiency — not a case-based ranking signal. Lowercase is a convention (and what most CMSs default to), not a ranking factor. Same class of myth as “shorter URLs rank better.”
8. Over-broad rewrite rules that lowercase query values. Blindly lowercasing the entire request URI can mangle case-sensitive query parameter values (tokens, base64, signatures). Scope your redirect to the path, and leave query strings alone unless you know they’re safe to fold.
Common URL-case failures
Mixed-case and lowercase URLs both return 200
Symptom: /Products/Blue-Shoe and /products/blue-shoe load the same page.
Likely cause: The application or host resolves paths case-insensitively without a
normalization redirect. Fix: Choose the established format, normally lowercase,
redirect alternates in one hop, and align internal links, canonicals, and sitemaps.
A URL works on staging but returns 404 in production
Symptom: A mixed-case path succeeds on one environment and fails on another. Likely cause: The hosts use different case-sensitivity rules, commonly across Windows and Linux-based systems. Fix: Correct the source link to the exact route case and add deployment tests that request the production path verbatim.
A robots rule does not block the expected path
Symptom: A crawler can fetch /private/ even though robots.txt disallows
/Private/. Likely cause: Robots path matching is case-sensitive. Fix: Match
the exact URL case or normalize paths before relying on a single rule, then retest
the real bot and URL combination.
Review mixed-case URL pairs
Paste a crawl export with URL, status, final URL, canonical, inlinks, sitemap source, and organic signals into this prompt:
Group URLs that differ only by path or query-string case. For each group, identify
the strongest candidate preferred URL using only the supplied evidence. Flag
conflicting redirects, canonicals, internal links, sitemap entries, and robots rules.
Return an implementation table with preferred URL, alternate URL, redirect action,
source links to update, and unresolved evidence. Do not assume lowercase wins when
the data shows an established mixed-case canonical. Patrick's relevant free tools
- SEO Incident Simulator — Practice thirty deterministic technical SEO incident investigations — indexability, crawl controls, redirects, sitemaps, markup, caching, DNS, bot verification, rendering, hreflang, and faceted navigation — with clearly labeled fixture evidence and Find → Fix → Verify handoffs.
Tools for case normalization
- Redirect Chain Mapper — compare case variants and see whether they resolve directly to one preferred form or accumulate extra hops.
- Canonicalization Checker — identify conflicts between the response, canonical element, and final destination for a variant URL.
- robots.txt Tester — test the exact uppercase and lowercase paths against the relevant bot because path matching is case-sensitive.
- A full-site crawler — use case-insensitive grouping to find variants, then use inlink reports to correct the templates and content that keep generating them.
Verify the preferred-case redirect
Test to run: Request the preferred URL and several case variants with the Redirect Chain Mapper. Expected result: The preferred URL returns a successful response and every alternate permanently redirects to it in one hop. Failure interpretation: The rule is incomplete, ordered incorrectly, or incompatible with the application route. Monitoring window: Immediate after deployment. Rollback trigger: Valid routes begin to loop, redirect to the wrong page, or return errors.
Verify emitted URLs and crawl controls
Test to run: Crawl internal links and sitemaps, then test representative paths in the robots.txt Tester. Expected result: Templates, canonicals, and sitemaps emit only the preferred case, and robots rules behave the same for the exact URLs the site exposes. Failure interpretation: A source system still generates variants or a robots rule has the wrong case. Monitoring window: After a complete post-release crawl. Rollback trigger: Important preferred URLs become blocked or a large new variant set appears.
Test yourself: URL Case Sensitivity
Five quick questions on how case sensitivity actually works and how to fix it. Pick an answer for each, then check.
Resources worth your time
My related writing
- Google Uses ~40 Canonicalization Signals — my breakdown of how Google picks a representative URL; it lists case-variant URLs (
/page/vs/Page/) as one of the duplicate-URL example patterns, which is exactly the problem this article fixes. - Trailing Slash: To Use or Not to Use? — a sibling canonicalization axis: same “pick one version and enforce it” discipline, applied to the slash instead of casing.
- URL Parameters: A Complete Guide for SEOs — the other big duplicate-URL multiplier, and why passive parameters waste crawl budget the same way stray casings do.
- Redirects for SEO: A Simple (But Complete) Guide — the 301 mechanics behind the server-level lowercase-enforcement fix.
- The Beginner’s Guide to Technical SEO — where URL hygiene sits in the bigger picture.
My speaking
- Troubleshooting Technical SEO Problems (SlideShare, Raleigh SEO Meetup) — duplicate-URL and canonicalization issues in context. (Standing disclaimer applies: this is my understanding of these systems, not an official spec.)
From around the industry
- URL structure best practices (Google Search Central) — the “URLs are case sensitive” / IETF STD 66 source.
- How Google interprets the robots.txt specification (Google Search Central) — the “value is case-sensitive” robots.txt rule.
- Google: URLs Are Case Sensitive (Search Engine Journal) — the anchor source for Mueller’s case-sensitivity, robots.txt, crawl-slowdown, and canonical-recommendation quotes.
- Google’s Advice On Canonicals: They’re Case Sensitive (Search Engine Journal) — the “hope should not be a part of an SEO strategy” exchange.
- URL Case Sensitivity and SEO (Practical Ecommerce) — the closest direct competitor; good on the ecommerce 404 symptom.
- Adjust case sensitivity (Microsoft Learn) — the Windows/NTFS case-insensitive-but-case-preserving behavior behind the IIS-vs-Linux difference.
- Bing changing URLs from upper to lower case (Microsoft Community Hub) — webmaster reports of Bing’s lowercase normalization (community evidence, not a formal spec).
URL Case Sensitivity
URL case sensitivity is the rule that uppercase and lowercase letters in the path, filename, and query string are treated as different characters — so /Apple and /apple are two distinct URLs — while the hostname is not case-sensitive.
Related: URL Structure, Canonicalization, Trailing Slash, 301 redirect
URL Case Sensitivity
URL case sensitivity refers to whether a web server and search engine treat uppercase and lowercase letters in a URL as different characters. They do — for everything after the hostname. example.com/Apple and example.com/apple are two separate, distinct URLs, even when they render identical content. This follows the URL standard (RFC 3986 / IETF STD 66), and Google’s crawler follows that standard exactly.
The one part that is never case-sensitive is the hostname. DNS doesn’t distinguish Example.com from example.com, so the domain resolves the same regardless of casing. Only the path, filename, and query string carry case-sensitivity risk.
The practical problem is duplicate content: when the same page is reachable under multiple casings, you can split signals across near-identical URLs. There’s also a sharper trap in robots.txt, where the directive value is case-sensitive — a Disallow: /Private/ rule does not block /private/ at all. The standard fix is to pick one case (lowercase is the convention), enforce it with a server-level redirect, and fall back to rel=canonical where a hard redirect isn’t feasible.
Related: URL Structure, Canonicalization, Trailing Slash, 301 redirect
Build-time retrieval analysis plus live signals for this exact article. The automatic chunk report includes a deterministic readiness score and is ready without a model download.
Search Console
sampleGA4 traffic (28d)
sampleCloudflare traffic (7d)
sampledCrUX field data (28d, phone)
sampleGoogle NLP entities
localChangelog
Updated Jul 18, 2026.
Editorial summary and recorded change details.Summary
Fixed a real bug in the Nginx njs redirect snippet (Scripts lens) that silently dropped the query string on every redirect and could over-trigger on case-insensitive-path/uppercase-query URLs; added caveats grounded in the structured research pass — filesystem defaults can be overridden by proxies/CDNs/routers, blanket lowercase redirects need a pre-flight inventory of legitimately case-sensitive paths, rel=canonical can't merge content that isn't actually a duplicate, and Unicode slugs need an explicit normalization policy.
Change details
- Before
return 301 $scheme://$host$lower_uri; (triggered on $request_uri, dropped the query string on every redirect)AfterNginx njs snippet now tests $uri (path only) and redirects to $scheme://$host$lower_uri$is_args$args, preserving the original query string instead of silently discarding it. -
Added a caveat to the filesystem-mechanism section noting that reverse proxies, CDNs, load balancers, and application routers can override OS-level case defaults before a request reaches the origin filesystem.
-
Added a pre-flight caution to the server-level lowercase redirect fix: inventory legitimately case-sensitive paths (uploaded filenames, tokens) and roll out bounded, with no ranking/crawl-recovery guarantee.
-
Added a note that rel=canonical only works once you've confirmed a case variant actually serves duplicate content — it can't merge two genuinely different resources.
-
Added a short Unicode/IDN slug caveat: visually identical characters can be different code points that survive ASCII-style lowercasing untouched.
Full comparison unavailable — no prior snapshot was archived for this revision.