URL Parser
Break a URL into scheme, host, port, path segments, query parameters and fragment, with percent-decoded values and repeated parameters flagged. All processing happens locally in your browser.
Split a URL into its parts and decode its query string
Parsing uses the browser's own URL and URLSearchParams, so the results match exactly what your JavaScript, and the browser's address bar, will do with the same string.
| Property | Value | |
|---|---|---|
| href | https://api.example.com/v1/tools/search?q=json%20schema&limit=20&sort=popular#results | |
| protocol | https: | |
| origin | https://api.example.com | |
| host (with port) | api.example.com | |
| hostname | api.example.com | |
| port | Default for https (443) | |
| pathname | /v1/tools/search | |
| search | ?q=json%20schema&limit=20&sort=popular | |
| hash | #results | |
| username | Empty | |
| password | Empty |
| Name | Raw value | Decoded value |
|---|---|---|
q | json%20schema | json schema |
limit | 20 | 20 |
sort | popular | popular |
| # | Raw segment | Decoded |
|---|---|---|
| 1 | v1 | v1 |
| 2 | tools | tools |
| 3 | search | search |
Origin is https://api.example.com. Anything sharing that exact scheme, host and port is same-origin; anything else is cross-origin.
{
"protocol": "https:",
"hostname": "api.example.com",
"port": null,
"pathname": "/v1/tools/search",
"segments": [
"v1",
"tools",
"search"
],
"query": {
"q": "json schema",
"limit": "20",
"sort": "popular"
},
"hash": "#results"
}What is a URL made of?
A URL is a structured address. Each part is delimited by a specific character, and knowing which delimiter starts which section is most of the knowledge you need:
https://user:pass@api.example.com:8443/v1/tools?q=json&limit=20#results
└─┬─┘ └───┬───┘ └──────┬───────┘ └┬─┘└───┬───┘└──────┬──────┘└──┬──┘
scheme userinfo hostname port path query fragment
└──────────── host ─────┘
└───────────────── origin ───────────────┘
| Part | Starts after | In the example |
|---|---|---|
| Scheme | Start of string, ends at : |
https: |
| Userinfo | //, ends at @ |
user:pass |
| Hostname | @ or // |
api.example.com |
| Port | : after the host |
8443 |
| Path | First / after the host |
/v1/tools |
| Query | ? |
q=json&limit=20 |
| Fragment | # |
results |
Two derived values matter more in practice than any single part.
origin is scheme + host + port. It is the unit the same-origin policy works on, so https://example.com and https://api.example.com are different origins, and so are http://example.com and https://example.com. Every CORS decision comes down to comparing origins.
host versus hostname trips people up constantly: host includes the port, hostname does not. For api.example.com:8443, host is api.example.com:8443 and hostname is api.example.com.
How to parse a URL here
-
Paste a full URL
It needs a scheme. Without one,
example.com/pageis ambiguous — the standard reads it as a relative path, not a hostname. -
Or paste a relative URL and add a base
A path such as
/docs?lang=enhas no host of its own. Supply a base URL and it is resolved exactly as a browser resolves a link on a page. - Read the components table Every property the URL API exposes, each with its own copy button. Any embedded password is reported as present with its length rather than displayed.
- Compare raw and decoded query values The query table shows both, side by side. That is where percent-encoding problems become visible.
Query parameters: raw versus decoded
Showing both forms is deliberate, because the difference is where most URL bugs live.
| Query string | Raw value | Decoded value |
|---|---|---|
?q=json%20schema |
json%20schema |
json schema |
?q=coffee+tea |
coffee+tea |
coffee tea |
?q=a%2Bb |
a%2Bb |
a+b |
?next=%2Fdash%3Ftab%3D2 |
%2Fdash%3Ftab%3D2 |
/dash?tab=2 |
?q=100%25 |
100%25 |
100% |
Look at rows two and three. In a query string, + means a space, inherited from HTML form encoding — but a literal plus sign must be written %2B. So ?q=1+1 searches for "1 1", not "1+1". URLSearchParams applies this rule correctly; naive decodeURIComponent() on the whole query string does not, which is a common source of mangled search terms.
Row four shows a nested URL. When a whole URL is a parameter value, its own ?, & and / must be percent-encoded, otherwise the outer query string absorbs them. If a redirect after login drops everything after the first &, this is almost always why. The URL Encoder & Decoder handles the encoding side.
Repeated parameters have no single standard
?tag=react&tag=nextjs&tag=css is perfectly legal, and it is the usual way to express a list. What no specification settles is how a server should interpret it, and frameworks genuinely disagree:
| Framework or language | Result for ?tag=a&tag=b |
|---|---|
JavaScript searchParams.get('tag') |
"a" — the first value |
JavaScript searchParams.getAll('tag') |
["a", "b"] |
PHP $_GET['tag'] |
"b" — the last value wins |
| Express, Rails, ASP.NET | An array of both values |
PHP with tag[]=a&tag[]=b |
An array, using the bracket convention |
This page flags repeated names so you notice them, because a filter that silently keeps only one of three selected tags is a bug that is very easy to miss in testing.
Examples of edge cases worth knowing
The fragment never leaves the browser
Everything after # is processed by the client only. It is not sent in the HTTP request, does not appear in server access logs, and cannot be read by your backend. That is why single-page app routers historically used it, and why a fragment is a poor place to put anything you need server-side.
A default port disappears
Parse https://example.com:443/x and the port property comes back empty. The URL API normalises away the default port for the scheme, so 443 for HTTPS and 80 for HTTP are dropped. The port is shown here as "default for https (443)" rather than blank, so the value is not mistaken for missing information.
Credentials in a URL are a liability
https://user:pass@example.com is syntactically valid and practically a mistake. The credentials travel in browser history, referrer headers, server logs and analytics. Chrome strips them from fetch() requests, and browsers have progressively restricted them because of phishing patterns such as https://your-bank.com@attacker.example, which points at attacker.example. Use an Authorization header instead. This page masks the password rather than displaying it.
Punycode hostnames
A hostname containing non-ASCII characters is stored as Punycode with an xn-- prefix. bücher.example becomes xn--bcher-kva.example. Browsers display the readable form but resolve and transmit the encoded one — which is also the mechanism behind homograph attacks, where Cyrillic characters that look like Latin ones produce a visually identical domain name.
Path segments are individually encoded
Each segment between slashes is encoded separately, so a slash inside a segment value must be written %2F. This page decodes each segment individually, which is the correct way to read them.
Use cases
- Debugging a broken redirect. Parsing the URL shows immediately whether a nested
return_tovalue was encoded properly or was truncated at an&. - Auditing campaign links. Confirm that every UTM parameter is present, correctly spelled and correctly encoded before a send goes out.
- Diagnosing a CORS failure. Comparing the origins of two URLs makes it obvious whether a mismatch is the scheme, the subdomain or the port.
- Reading a URL from a log line. Long encoded URLs are unreadable inline; the decoded parameter table makes them legible.
- Checking a webhook or callback URL. Verify the path, port and query before registering it with a third-party service.
- Understanding a routing bug. The numbered path segments correspond directly to route parameters in most frameworks.
To go the other way and build a safely encoded URL, use the URL Encoder & Decoder. To turn a captured request into code, the cURL to Fetch Converter handles the whole command.
Privacy and security handling
Parsing uses the browser's built-in URL and URLSearchParams. No request is made to the URL you paste — it is read as text, never fetched — and nothing is uploaded.
Credential handling: an embedded password is never displayed. It is reported as present with a character count so you know it is there without it appearing in a screenshot or screen share. Usage analytics record only that a parse happened, never the URL.
Frequently Asked Questions
What is the difference between host and hostname?
host includes the port; hostname does not. For https://api.example.com:8443 the host is api.example.com:8443 and the hostname is api.example.com. Getting these mixed up is a frequent cause of failed origin comparisons in CORS and cookie code.
Why is the port empty for an https URL?
Because 443 is the default for HTTPS and the URL API normalises it away, just as it drops 80 for HTTP. The page shows "Default for https (443)" instead of leaving the row blank, so it is clear the port is implied rather than missing.
Why does my search for "1+1" return results for "1 1"?
In a query string, + means a space — a convention inherited from HTML form encoding. A literal plus must be written %2B. URLSearchParams applies this rule; calling decodeURIComponent() on a whole query string does not, which is why the raw and decoded values are shown side by side here.
Can the server see the part after the #?
No. The fragment is stripped before the request is sent, so it never reaches your backend and never appears in access logs. It is available to JavaScript via location.hash, which is why client-side routers used it, but it is unusable for anything server-side.
How do I parse a relative URL like /docs?lang=en
Add a base URL in the field provided. A relative URL has no host of its own, so it has to be resolved against something — exactly as a browser resolves a link relative to the current page. Without a base, the URL constructor throws.
Is it safe to paste a URL containing a token?
The URL is only parsed as text in your browser and is never fetched or uploaded, and embedded passwords are masked on screen. Even so, a token that has appeared in a URL should be treated as exposed regardless of this tool, since URLs are logged in many places along the way.
What does the xn-- prefix in a hostname mean?
It marks a Punycode label, meaning the domain contains non-ASCII characters encoded into ASCII for DNS. bücher.example becomes xn--bcher-kva.example. Browsers show the readable form, which is worth knowing because visually similar characters from other scripts can be used to imitate a familiar domain.