URL Parser
Split a URL into scheme, host, port, path segments, query parameters and fragment, exactly as browsers parse it. Parsed in your browser.
Where your data goes
| Using this page | Using the API, MCP or A2A | |
|---|---|---|
| Where it runs |
In your browser. The URL is parsed by your browser's built-in WHATWG URL parser in this page; nothing is sent, and the host is neither resolved nor contacted. | In a Cloudflare Pages Function at the Cloudflare data centre nearest the caller. |
| What leaves your device | Nothing you enter. After the page and its scripts load, no request
carries your input. The browser enforces this: the page's Content-Security-Policy
sets connect-src 'none' and form-action 'none', which
block fetch, XHR, WebSocket, EventSource, beacons and form posts.
| The server receives the URL (and base), parses it in memory, and returns its parts. Your input is not stored or logged; only the per-call metadata row (operation, time, status, sizes) is recorded. Passwords in the URL are never echoed back: they are replaced by |
| Stored | Nothing leaves the page. No cookies, analytics or third-party scripts; the browser keeps only your View → Inline config choice. | Your inputs and results: never. What is stored is your client record (client ID, a SHA-256 hash of your secret, expiry, and the profile you registered with) and one metadata row per call: operation, time, transport, status, error code, duration, request and response sizes, and country. |
| Logged | Nothing (no requests are made). | Only the per-call metadata above, attributed to your client ID. Never parameters, bodies, results, or credentials. Cloudflare, as the host, also processes request metadata (IP address, full URL including the query string, headers) under its own policies, so put inputs in POST bodies. |
| Access | Open to anyone. | Requires a client ID and secret (how to get one). HTTPS only; TLS terminates at Cloudflare. |
Details and how to verify this yourself: Security & privacy.
User guide
The tool sits in a window that works like a desktop app: menus on the top row and the full-screen icon at its right (Esc leaves full screen). The set-up options described below are in Settings → Options…, an overlay, and the Settings menu also lists the common choices directly. To keep the options in view instead, choose View → Inline config; the page remembers that choice. Help → Keyboard shortcuts… lists the keys.
- Paste a URL. Leading and trailing spaces are tolerated, as browsers tolerate them.
- To resolve a relative reference such as
../img/a.pngor?page=2, also enter the base URL it appears on. - Read the cards:
- Overview: the normalized URL, scheme, host, port and origin.
- Path segments, percent-decoded.
- Query parameters, in order, with repeated names kept.
- Notes: anything the parser silently changed or that deserves attention.
Why use a parser at all? URLs have many edge cases that regular expressions and by-eye reading get wrong:
- Host names are case-insensitive, and default ports disappear (
https://Example.COM:443/ishttps://example.com/). http://0x7f.1/is127.0.0.1.- Backslashes count as slashes in
http:URLs. +means a space in a query string but not in a path.
This tool shows you what a browser, Node.js or a Cloudflare Worker will actually see.
Passwords are never shown. If the URL contains user:password@, the password is replaced by *** in the output and reported only as present. Credentials in URLs end up in logs, browser history and Referer headers. Remove them.
Specification
Parser. The WHATWG URL Standard, via the runtime’s URL class. The API runs it in Cloudflare Workers (V8) and the page runs it in your browser. Results match whenever both implement the current standard.
Normalization performed by the parser (reported in warnings when it changes the input):
- Stripping: leading and trailing C0 control characters and spaces are removed, and so are tab and newline characters anywhere.
- Special schemes (
http,https,ws,wss,ftp,file): the scheme and host are lowercased, a default port is dropped,\is treated as/, and.and..path segments are resolved. - IPv4: hosts written in hex, octal or shorthand (
0x7f.1,2130706433) become dotted decimal. - IDN: internationalized host names become Punycode (
münchen.de→xn--mnchen-3ya.de), per UTS #46. - Percent-encoding: characters outside the allowed sets are percent-encoded. Existing escapes are kept as written, even invalid ones such as
%zz.
Components.
| Field | Meaning |
|---|---|
href | Normalized URL; a password is replaced by *** and hrefRedacted is true |
username | raw (as serialized) and decoded (percent-decoded UTF-8, or null if invalid) |
hasPassword | Whether a non-empty password was present. The password itself is never returned |
hostname / hostnameUnicode | ASCII form, and the same with xn— labels decoded |
hostType | domain, ipv4, ipv6, opaque (host of a non-special scheme), empty (file:///…) or none (mailto:, data:) |
port, defaultPort, effectivePort | port is null when absent or equal to the default; effectivePort is port ?? defaultPort |
origin | scheme://host[:port], or null for opaque origins |
pathSegments | The path split on / after the leading slash; raw and decoded per segment. Empty for opaque paths such as mailto:a@b |
query | Ordered {name, value, rawName, rawValue}; see below |
fragment | The part after #, raw and decoded |
Query parameters are parsed as application/x-www-form-urlencoded (WHATWG URL §5.1), the same rules as URLSearchParams:
- Splitting: on
&; empty pieces are skipped, and the first=separates name and value. - Decoding:
+becomes a space, and%XXescapes are decoded as UTF-8. Invalid UTF-8 becomes U+FFFD, and a%not followed by two hex digits is kept literally. - Order and duplicates: order is preserved and duplicate names are kept.
- No
=:valueis the empty string andrawValueis null.
Host classification. IP hosts are matched against the IANA special-purpose address registries:
| Range | IPv4 | IPv6 |
|---|---|---|
loopback | 127.0.0.0/8 | ::1 |
private / unique-local | 10/8, 172.16/12, 192.168/16 | fc00::/7 |
shared (CGNAT) | 100.64.0.0/10 | |
link-local | 169.254.0.0/16 (includes cloud metadata 169.254.169.254) | fe80::/10 |
unspecified | 0.0.0.0/8 | :: |
documentation | 192.0.2/24, 198.51.100/24, 203.0.113/24 | 2001:db8::/32 |
benchmarking | 198.18.0.0/15 | |
multicast | 224.0.0.0/4 | ff00::/8 |
broadcast / reserved | 255.255.255.255; 240/4, 192.0.0/24 | other non-global space |
ipv4-mapped, nat64 | ::ffff:0:0/96, 64:ff9b::/96 (the embedded IPv4 is classified too) | |
site-local | fec0::/10 (deprecated) | |
public | everything else | 2000::/3 outside the ranges above |
Flags.
isLocalhost:localhostor*.localhost(RFC 6761), or any loopback address.isPrivate: RFC 1918, shared (100.64/10), unique-local or site-local, including IPv4-mapped forms.isPublic: true only for a public IP, false for special-purpose IPs and localhost, and null for domain names, which are not resolved.
Not an SSRF filter on its own. A domain name can resolve to a private address, and DNS answers can change between check and use. Validate the resolved address at connection time.
Relative references. With base, the input is resolved against it (RFC 3986 §5 as refined by WHATWG). resolvedAgainstBase is false when the input was already absolute, in which case base is ignored.
Errors. An invalid URL is reported with a likely cause: a missing scheme, a forbidden host character, a bad port, or a malformed IPv6 literal. The input is not echoed back, so a password in a malformed URL is not repeated either.
Limits. API input and base: at most 16,384 characters each.
API & MCP
The same logic is available over HTTP and as MCP tools. Unlike this page, these run on the server: see where your data goes.