Scrapeless Wiki

What Is URL Normalization? – Definition and How It Works

Informational P3 what is url normalization

Learn which URL transformations are safe, which change meaning, and why normalization decides how much of a crawl is wasted.

URL normalization converts URLs to a canonical form so that different strings pointing at the same resource are recognised as one. Without it, a crawler fetches the same page many times.

1. Why It Decides Crawl Efficiency

These are usually one resource:

http://Example.com/Page/
https://example.com/page
https://example.com/page?utm_source=x
https://example.com/page#section
https://www.example.com/page/index.html

Five distinct strings. A crawler without normalization fetches five pages, stores five copies, and follows five sets of links β€” and the multiplication compounds at every level of depth.

2. Safe Transformations

These never change which resource is addressed:

Transformation Example
Lowercase scheme and host HTTP://Example.COM β†’ http://example.com
Remove default port https://example.com:443/ β†’ https://example.com/
Add empty path https://example.com β†’ https://example.com/
Resolve dot segments /a/./b/../c β†’ /a/c
Decode unreserved percent-escapes %7Euser β†’ ~user
Uppercase remaining escapes %3a β†’ %3A
Drop the fragment /page#top β†’ /page

The fragment is a client-side pointer and is never sent to the server, so dropping it for fetching and deduplication is always correct.

3. Transformations That Are Not Safe

Transformation Why it can be wrong
Lowercase the path Paths are case-sensitive on most servers
Strip or add a trailing slash /page and /page/ can be different resources
Drop index.html May not be the directory default
Remove www. Can be a genuinely different host
Sort query parameters Order can be significant to the application
Remove all query parameters Destroys the resource identity

Every one of these is applied routinely and works on most sites β€” which is exactly why it is dangerous. It fails on the minority, silently, by merging two distinct pages into one.

4. Tracking Parameters Are the Exception

Removing known tracking parameters is safe in practice, because they are consumed by analytics and never affect the response:

from urllib.parse import urlsplit, urlunsplit, parse_qsl, urlencode

TRACKING_PREFIXES = ("utm_",)
TRACKING_EXACT = {"gclid", "fbclid", "msclkid", "mc_cid", "mc_eid", "ref", "_ga"}

def normalize(url):
    parts = urlsplit(url)
    scheme = parts.scheme.lower()
    host = parts.hostname or ""
    port = "" if parts.port in (None, 80, 443) else f":{parts.port}"
    path = parts.path or "/"
    query = [(k, v) for k, v in parse_qsl(parts.query, keep_blank_values=True)
             if not k.lower().startswith(TRACKING_PREFIXES) and k.lower() not in TRACKING_EXACT]
    return urlunsplit((scheme, host + port, path, urlencode(query), ""))

Note the empty fifth element β€” the fragment is dropped.

5. Two Normalization Levels

The distinction that avoids most of the trouble:

Fetch URL β€” conservative normalization only. This is what you request, and it must address exactly what the link addressed.

Dedup key β€” aggressive normalization: sorted parameters, trailing-slash unification, whatever the site's observed behaviour justifies. Used only to decide whether to fetch, never as the request.

Keeping them separate means an over-aggressive rule costs a skipped fetch rather than a wrong request.

6. Use the Site's Own Answer

Where a page declares <link rel="canonical">, that is the site telling you which URL it considers primary. Recording it lets you collapse variants correctly rather than by guesswork.

It is a claim, not a guarantee β€” canonical tags are sometimes wrong or self-referential across genuinely distinct pages β€” so treat it as strong evidence rather than proof.

7. Practical Rules

  1. Always: lowercase scheme and host, drop the fragment, resolve dot segments, remove default ports.
  2. Always: strip known tracking parameters.
  3. Never: lowercase the path, or assume trailing-slash equivalence, without checking the site.
  4. Keep the fetch URL and the dedup key separate.
  5. Record canonical URLs when pages declare them.
  6. Normalise before the seen-set check, or the set does not work.

8. Summary

URL normalization canonicalises URLs so one resource is not fetched many times, using transformations that are provably safe β€” case of scheme and host, default ports, dot segments, fragments, tracking parameters β€” and avoiding those that merely usually work, such as path casing and trailing slashes.

Maintain a conservative fetch URL and a separate aggressive dedup key, and prefer a page's declared canonical URL over inference.