URL parser: the anatomy of a URL
Long URLs with tracking tags, encoded characters and many parameters are hard to read. This URL parser uses the browser's standards-compliant URL implementation (the WHATWG URL Standard) to split an address into its parts, exactly as a browser would interpret it.
https://admin:secret@shop.example.com:8443/products/desk%20lamp?color=oak&tag=new&tag=sale#reviews
└─┬─┘ └────┬─────┘ └──────┬───────┘ └┬─┘└──────────┬─────────┘ └────────────┬────────────┘ └──┬──┘
scheme credentials host port path query fragment
Example output
URL https://admin:secret@shop.example.com:8443/products/desk%20lamp?color=oak&tag=new&tag=sale#reviews
Scheme https
Username admin
Password secret
Host shop.example.com
Port 8443
Path /products/desk%20lamp
Query string ?color=oak&tag=new&tag=sale
Fragment reviews
Query parameters:
color = oak
tag = new
tag = sale
What each part means
- Scheme – the protocol, such as
https,ftpormailto. - Username and password – rarely used today and a security risk in shared links, since credentials in URLs end up in logs and browser history.
- Host – the domain name or IP address. Internationalized domain names are shown in their Punycode form (
xn--…). - Port – shown when explicitly set; otherwise the default port for the scheme (80 for HTTP, 443 for HTTPS) is noted.
- Path – the resource on the server. The structured result also lists the decoded path segments, so
desk%20lampreads as "desk lamp". - Query – key/value parameters after
?. Values are percent-decoded, and repeated keys such astagare kept in order and grouped into an array. - Fragment – the part after
#. Browsers never send it to the server; it is used for in-page anchors and client-side routing.
Why parse URLs instead of reading them?
Encoded characters hide what a parameter really contains: %2F is a slash, %3D an equals sign and %26 an ampersand. A parser decodes each part in the correct context, so you can tell whether an ampersand separates two parameters or is part of a value.
Useful for
- Debugging OAuth redirects, payment callbacks and deep links with long parameter lists.
- Reviewing marketing links to check
utm_parameters before a campaign goes out. - Understanding API request URLs copied from browser developer tools.
- Checking a batch of URLs from a spreadsheet or log file: paste up to 100 at once.
Absolute, relative and special URLs
The parser expects absolute URLs. Relative references such as ../images/logo.png only make sense together with a base address, so paste the full URL instead. Special schemes work too: mailto:team@example.com?subject=Hi shows the address as the path and the subject as a query parameter, and file:///C:/docs/report.pdf shows a local file path.
Hostnames are also normalized: uppercase letters become lowercase and default ports are dropped from the canonical form, which is why the parsed URL can look slightly different from what you pasted while still pointing to the same resource.
Edge cases handled
If you paste an address without a scheme, such as example.com/path, it is parsed as http:// and a note says so. Invalid URLs produce a clear error. A + in the query is decoded as a space, following the form-encoding rules browsers use.
Related tools
Need to build or fix encoded values? Use the URL encoder and URL decoder. To strip redirect wrappers and tracking parameters from links, try the un-Google link tool. Parsing happens in your browser; URLs are not sent anywhere.
URL parser in Python
urllib.parse.urlsplit() breaks a URL into scheme, network location, path, query and fragment, and parse_qs() turns the query string into a dictionary. Three details trip people up. netloc still contains the credentials and the port, so read hostname and port instead. The path comes back as written, so call unquote() to turn %20 into a space. And a URL without a scheme, such as shop.example.com/products, is parsed as a path with an empty host; add https:// before parsing it.
from urllib.parse import urlsplit, parse_qs, unquote
url = "https://admin:secret@shop.example.com:8443/products/lamps/desk%20lamp?color=oak&size=m&tag=new&tag=sale#reviews"
parts = urlsplit(url)
print(parts.scheme) # https
print(parts.netloc) # admin:secret@shop.example.com:8443
print(parts.hostname, parts.port) # shop.example.com 8443
print(parts.username, parts.password) # admin secret
print(parts.path) # /products/lamps/desk%20lamp
print(unquote(parts.path)) # /products/lamps/desk lamp
print(parts.query) # color=oak&size=m&tag=new&tag=sale
print(parts.fragment) # reviews
params = parse_qs(parts.query) # every value is a list
print(params) # {'color': ['oak'], 'size': ['m'], 'tag': ['new', 'sale']}
print(params["color"][0]) # oak
Paste a URL above to see the same parts side by side and confirm what your code should return.