Skip to main content

url-normalize

tests Coveralls PyPI Python Versions License Ruff

A Python library for standardizing and normalizing URLs. Ideal for database deduplication, caching, web crawling, and anywhere you need to ensure that equivalent URLs resolve to the exact same string.

from url_normalize import url_normalize

# Fixes IDN, lowercases host/scheme, removes default ports, resolves path segments
url_normalize("HTTP://User:Pass@www.FOO.com:80///foo/../bar/./baz?q=1#frag")
# -> 'http://User:Pass@www.foo.com/bar/baz?q=1#frag'

Features

url-normalize provides a robust URI normalization function that handles IDN domains, scheme/host lowercasing, and RFC-compliant path normalization.

  • IDN Support: Full internationalized domain name handling (using IDNA2008 with UTS46).
  • Humanization: Convert normalized URLs to a readable display format while preserving round-trip normalization.
  • RFC Compliance:
    • Proper percent-encoding (minimal, uppercase hex).
    • Dot-segment removal in paths.
    • Default port and authority handling.
    • UTF-8 NFC normalization.
  • Configurable Defaults:
    • Customizable default scheme (https by default).
    • Configurable default domain for absolute paths.
  • Query Parameter Control:
    • Parameter filtering with allowlists.
    • Support for domain-specific parameter rules.
  • Versatile URL Handling: Handles empty strings, double-slash URLs (//domain.tld), and shebang (#!) URLs.
  • Developer Friendly:
    • Python 3.10+ compatibility.
    • 100% statement coverage, enforced by the test suite.
    • Modern type hints and string handling.

Inspired by Sam Ruby's urlnorm.py.

Installation

Install as a library:

pip install url-normalize

Or install as a standalone CLI tool using uv:

uv tool install url-normalize

Usage

Python API

Basic Normalization

from url_normalize import url_normalize

# Basic normalization (uses https by default)
print(url_normalize("www.foo.com:80/foo"))
# Output: https://www.foo.com:80/foo

# With custom default scheme
print(url_normalize("www.foo.com/foo", default_scheme="http"))
# Output: http://www.foo.com/foo

The charset argument remains for compatibility. Unicode characters use UTF-8 percent encoding, regardless of this argument.

Query Parameter Filtering

With filter_params=True, normalization retains only allowlisted query parameters. The built-in rules cover selected domains.

Other domains have an empty default allowlist. Without a custom allowlist, filtering removes all query parameters from those domains.

# With the built-in Google allowlist
print(url_normalize("www.google.com/search?q=test&utm_source=test", filter_params=True))
# Output: https://www.google.com/search?q=test

# With custom parameter allowlist as a list
print(url_normalize(
    "example.com?page=1&id=123&ref=test",
    filter_params=True,
    param_allowlist=["page", "id"]
))
# Output: https://example.com/?page=1&id=123

# With domain-specific parameter allowlists
print(url_normalize(
    "example.com?page=1&id=123&ref=test",
    filter_params=True,
    param_allowlist={"example.com": ["page", "id"]}
))
# Output: https://example.com/?page=1&id=123

Default Domain & Scheme

Useful for resolving relative URLs found on a specific page.

# With default domain for absolute paths
print(url_normalize("/images/logo.png", default_domain="example.com"))
# Output: https://example.com/images/logo.png

# With default domain and custom scheme
print(url_normalize("/images/logo.png", default_scheme="http", default_domain="example.com"))
# Output: http://example.com/images/logo.png

Humanizing URLs

Convert normalized URLs back into a user-friendly format for display, particularly useful for IDN domains and percent-encoded paths.

from url_normalize import url_humanize

# Human-readable display form that still normalizes back to the same URL
print(url_humanize("https://xn--e1afmkfd.xn--80akhbyknj4f/%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F"))
# Output: https://пример.испытание/Служебная

# Humanization accepts the same normalization options
print(url_humanize("/%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F", default_domain="xn--e1afmkfd.xn--80akhbyknj4f"))
# Output: https://пример.испытание/Служебная

Command-line Usage

You can also use url-normalize directly from the terminal to process URLs.

$ url-normalize "www.foo.com:80/foo"
# Output: https://www.foo.com:80/foo

# With custom default scheme
$ url-normalize -s http "www.foo.com/foo"
# Output: http://www.foo.com/foo

# With query parameter filtering
$ url-normalize -f "www.google.com/search?q=test&utm_source=test"
# Output: https://www.google.com/search?q=test

# With custom allowlist
$ url-normalize -f -p page,id "example.com?page=1&id=123&ref=test"
# Output: https://example.com/?page=1&id=123

# With default domain for absolute paths
$ url-normalize -d example.com "/images/logo.png"
# Output: https://example.com/images/logo.png

# With default domain and custom scheme
$ url-normalize -d example.com -s http "/images/logo.png"
# Output: http://example.com/images/logo.png

# Human-readable display form
$ url-normalize -H "https://xn--e1afmkfd.xn--80akhbyknj4f/%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F"
# Output: https://пример.испытание/Служебная

# Via uv tool/uvx
$ uvx url-normalize www.foo.com:80/foo
# Output: https://www.foo.com:80/foo

Documentation

For a complete history of changes, see CHANGELOG.md.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT License

Metadata

Release files for url-normalize 3.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for url-normalize 3.0.1
File Size Uploaded
url_normalize-3.0.1.tar.gz 28.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for url-normalize 3.0.1
File Interpreter ABI Platform
url_normalize-3.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 46.5 kB

Release files / url_normalize-3.0.1.tar.gz

Download URL url_normalize-3.0.1.tar.gz
Size 28.2 kB
Tags Source
SHA-256 checksum
How to use checksums
1655cd214159d9d47dc37aa6ce993c2149da44fa35cac6bafd90036a4eda3ac3
BLAKE2b-256 checksum
How to use checksums
3326b60cce0211e94bb130e88dbcba87583f61c6ddf386fa6adc10a167461f6a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / url_normalize-3.0.1-py3-none-any.whl

Download URL url_normalize-3.0.1-py3-none-any.whl
Size 18.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
97ea68fc543b1fc9f270f34c90cf164453e7d490da2ec653dcd8ebd4e3ac1faf
BLAKE2b-256 checksum
How to use checksums
9dbf98209a164859c81d9eec311ee2b35cd1e5b33c7be8d3665c08850557abe1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

3.0.1 This release

2 release files

3.0.0

2 release files

2.2.1

2 release files

2.2.0

2 release files

2.1.0

2 release files

2.0.1

2 release files

2.0.0

2 release files

1.4.3

2 release files

1.4.2

2 release files

1.4.1

2 release files

1.4.0

2 release files

1.3.3

2 release files

1.3.1

2 release files

1.2.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page