URL Parser & Builder

Break any URL into its components, build URLs from parts, encode/decode, or batch-parse multiple URLs.

Last reviewed: April 2026

New to this tool? Click here for instructions

URL
Paste a URL above to parse it.

Paste any URL and instantly decompose it into the seven WHATWG-URL-spec components — scheme, userinfo, host, port, path, query, and fragment — with query parameters parsed into a key-value table and percent-encoding decoded on the fly. Every parse runs locally in your browser: no URL you enter is uploaded, logged, or transmitted to any server.

What This Tool Does

This URL Parser accepts any string that conforms to (or approximately conforms to) the WHATWG URL Living Standard and decomposes it into its constituent components. The output covers every part defined by the specification: the scheme (also called protocol — https, http, ftp, mailto, file, data, custom schemes), the userinfo section that historically carried username:password before the host, the host (a registered domain name, a Punycode IDN, an IPv4 dotted quad, or a bracketed IPv6 literal), the port (when explicitly present and non-default for the scheme), the path (one or more slash-separated segments), the search string (everything from the ? onward, also called the query string), and the fragment (everything from the # onward, also called the hash).

Beyond raw decomposition, the parser separates the query string into its individual key-value pairs using URLSearchParams, so repeated keys (tags=a&tags=b) are preserved as multiple entries rather than collapsed into a single value. Path segments are split and indexed so you can spot a missing slash or a stray segment immediately. Percent-encoded characters are decoded for display (so %20 renders as a space, and Latin-1 byte sequences become their Unicode characters) without modifying the underlying URL. The companion Build, Encode, and Batch modes invert the parse operation (assembling URLs from parts), handle percent-encoding both directions, and parse many URLs in one shot — useful when auditing redirect chains, link-checking a sitemap, or cleaning a list scraped from server logs. Every computation runs client-side via the native new URL() constructor and URLSearchParams interface, so no string you paste leaves the browser session.

How to Use It

Paste a URL into the input field at the top of the tool. The parser runs on every keystroke (debounced at 150 ms) and displays four output blocks beneath the input: the anatomy strip, a color-coded inline rendering that highlights each component in place; the component table, listing protocol, host, port, path, query string, hash, origin, and the full canonical URL with a copy button per row; the path segments list, splitting the path on forward slashes and numbering each segment from 1; and the query parameter table, listing each key=value pair with the value percent-decoded for readability.

If your input lacks a scheme — for example example.com/api — the parser first tries the raw string, then retries with https:// prepended as a fallback. This matches what browsers do when you type a bare hostname into the address bar. To switch modes, click the chips above the input: Parse (current mode), Build (assemble a URL from individual fields), Encode (apply or reverse percent-encoding on arbitrary text, using either encodeURI or encodeURIComponent semantics), or Batch (paste multiple URLs, one per line, and get a table summarizing scheme, host, path, parameter count, and validity for each).

The Try Example button in every mode pre-loads a realistic input — useful as a self-paced tutorial or as a quick way to verify the tool is working in your browser before you paste a sensitive production URL. Every output value has a one-click copy button, and the Batch table can be selected and pasted into a spreadsheet for further analysis. None of these operations touch the network.

Worked Example: https://user:pass@www.example.com:8443/api/v2/users?role=admin&active=true&tags=a,b#section-2

The example URL below exercises every component the specification defines — including the rarely-seen userinfo segment — and shows exactly how the parser decomposes each part. Click Try Example in Parse mode to load a similar URL into the input directly.

URL Anatomy Diagram A labeled diagram of the URL https://user:pass@www.example.com:8443/api/v2/users?role=admin&active=true&tags=a,b#section-2 with each component highlighted and annotated with its name and purpose. https:// user:pass@ www.example.com :8443 /api/v2/users ?role=admin&tags=a,b #section-2 URL Anatomy: Seven Components Defined by WHATWG URL Each colored block is one structural component; arrows label name and meaning SCHEME retrieval protocol (also: protocol) USERINFO username:password (deprecated, phishing risk) HOST domain, IPv4, or [IPv6] (also: hostname) PORT TCP port number (omitted if default) PATH resource location on host (also: pathname) QUERY key=value pairs, &-separated (starts with ?, sent to server) FRAGMENT client-side scroll target (starts with #, NEVER sent) Separator characters and their roles: :// ends scheme @ ends userinfo : precedes port / begins path ? begins query # begins fragment Source: WHATWG URL Living Standard, §4 — url.spec.whatwg.org

Figure 1: The seven structural components of a URL as defined by WHATWG. Each separator (://, @, :, /, ?, #) signals the end of one component and the start of the next. The fragment is the only component never transmitted to the origin server.

  1. Scheme: https. The scheme names the retrieval protocol; everything before the first : is the scheme. For HTTP-family URLs the scheme is followed by :// (which the WHATWG spec treats as part of the scheme block). HTTPS implies a default port of 443; HTTP implies 80; FTP implies 21. The scheme determines which port is "default" and therefore whether the port component will appear in the canonical serialization.
  2. Userinfo: user:pass. Everything between :// and the first @ is the userinfo. The colon-separated form username:password is the historical pattern from RFC 1738. Modern browsers strip userinfo from the address bar for HTTPS URLs and refuse to autofill credentials this way because it has been heavily abused in phishing campaigns — an attacker uses https://www.bank.com@evil.com/ to make the URL appear to point at www.bank.com when in fact it points at evil.com.
  3. Host: www.example.com. Between @ (or, when userinfo is absent, between ://) and the next : or / is the host. The host can be a registered DNS name (the usual case), an IPv4 literal in dotted-quad form (192.0.2.1), an IPv6 literal in bracketed form ([2001:db8::1]), or a Punycode-encoded internationalized domain name (xn--bcher-kva.example for bücher.example). The host is case-insensitive per DNS rules.
  4. Port: 8443. A literal colon followed by a decimal integer between 1 and 65535. The port is optional — if absent, the scheme's default applies. The WHATWG URL parser normalizes default-port URLs by stripping the port: https://example.com:443/ serializes back as https://example.com/, while https://example.com:8443/ retains the port because 8443 is non-default for HTTPS.
  5. Path: /api/v2/users. Everything from the first / after the authority up to the next ? or #. The path is typically interpreted by the server as a hierarchical resource identifier, but to the URL parser it is just an opaque slash-separated string. Empty paths are normalized to /. Path segments use a different reserved-character set than query strings: / is a structural separator in the path but a literal character in the query.
  6. Query: ?role=admin&active=true&tags=a,b. Everything from ? up to #, including the leading ?. By convention the query is a series of key=value pairs separated by & (or sometimes ;), but the URL specification does not require any internal structure — a server is free to interpret the query string however it likes. The URLSearchParams interface enforces the key=value&... convention and exposes it as an iterable of pairs. In this example tags=a,b shows a common pattern where a single value contains a comma-separated list rather than using repeated keys.
  7. Fragment: #section-2. Everything from # to the end of the string, including the leading #. The fragment is a client-side identifier — by RFC 1738 design it is never transmitted to the server. Browsers use it to scroll to a named anchor (id="section-2") or to drive single-page-application routing. Because the fragment never reaches the server, server logs never record it and server-side analytics never see it — a privacy property that single-page apps sometimes exploit deliberately.

Origin — the combination of scheme, host, and port — is https://www.example.com:8443 for this URL. Origin is the unit that browsers use for security boundaries (same-origin policy, CORS, cookie scoping). The userinfo, path, query, and fragment do not contribute to origin; two URLs with identical scheme+host+port share an origin regardless of their paths.

Common Use Cases

Debugging Redirect Chains

When a request goes through three or four redirects before reaching its final destination, each hop typically tweaks one component — a different host, a rewritten path, a stripped query parameter, or an injected tracking pair. Pasting each intermediate URL into the parser side by side makes the diff between hops trivial to spot: a missing path segment, a port that shouldn't be there, a query parameter that got URL-encoded twice. In Batch mode you can paste the entire redirect chain at once and read off the structural differences in a single table.

Extracting OAuth State and Authorization Codes

OAuth 2.0 callbacks return the authorization code and the anti-CSRF state parameter as query parameters on the redirect URI. When something goes wrong — the state doesn't match, the code is empty, the redirect URI doesn't match what was registered — the first step is decomposing the actual URL the browser landed on. Paste it into the parser, check the query parameters table, and confirm exactly which fields the authorization server returned. The OpenID Connect id_token flow returns the token in the fragment rather than the query (because fragments aren't sent to the server, which is the security property the spec relies on); the parser surfaces it identically either way.

Building URL Filters and Allow/Deny Lists

Network filters at the proxy or firewall layer often need to make decisions based on individual URL components — block all requests where the host matches a known tracker, allow requests where the path begins with /api/v2/public/, strip query parameters that match a denylist pattern. Decomposing sample URLs in the parser lets you write filter rules against the right component without false-positive matches against substrings that happen to appear elsewhere in the URL. A regex that matches tracker anywhere in the string will also match a path like /article-tracker-explained; matching only against the parsed host avoids the collision.

Checking Phishing-Suspicious URLs

Three URL patterns dominate modern phishing: a deceptive host using an IDN homograph (Cyrillic letters that visually mimic Latin), a deceptive userinfo segment that hides the real host (https://www.bank.com@evil.example/), and a deceptive subdomain that pushes the brand name to the left so the real registered domain trails off the screen (www.bank.com.login-secure.example.com). The parser surfaces all three patterns by isolating the host into a single field — once you see the host as a discrete component rather than as one segment in a long string, the deception becomes obvious. The Punycode form (xn--*) is shown when applicable, and the userinfo block (purple in the anatomy strip) makes any @-trick visible at a glance.

Validating User-Submitted URLs

Forms that accept user-supplied URLs — webhook configuration, profile links, "verify this domain by adding a meta tag" workflows — need to validate input on both client and server. The parser provides a fast client-side sanity check: paste the URL, confirm the scheme is one you accept, confirm the host is not localhost or a private-IP range, confirm there's no userinfo segment. For programmatic validation in your own code, use new URL(input) and inspect the same fields the tool surfaces; for visual debugging during development, paste into this tool to see what the browser's parser actually produced.

Parsing Webhook Payloads

Webhook URLs from third-party services often include sensitive tokens embedded in the path or query — Slack incoming webhooks use a slash-separated token in the path, Stripe signing secrets live in headers but the endpoint identifier is in the URL, GitHub webhook deliveries include the installation ID in the path. When the payload arrives and something doesn't match, decomposing the request URL into its components is the fastest way to verify which token, which installation, which endpoint variant the sender used. The path-segments list highlights structural changes between versions of the same webhook endpoint.

Edge Cases and Limitations

The WHATWG URL specification accommodates a number of edge cases that surprise people coming from a regex-and-split mental model. The list below covers the ones most likely to trip you up in production.

Percent-encoded characters require a two-step decode. A percent-encoded byte sequence like %E2%9C%93 represents the three-byte UTF-8 encoding of U+2713 (check mark). The parser decodes percent-escapes byte by byte, then interprets the resulting byte sequence as UTF-8. Older URLs occasionally use Latin-1 encoding instead of UTF-8, which yields garbled characters when interpreted as UTF-8; this is a quirk of the source URL, not a bug in the parser. %20 always means space, regardless of which URL component it appears in.

Unicode IDN domains use Punycode internally. Domain names with non-ASCII characters are stored in DNS as ASCII strings prefixed with xn--; for example, café.example resolves through DNS as xn--caf-dma.example. The browser's URL parser converts between the Unicode display form and the Punycode wire form depending on context. The parser tool surfaces the Punycode form in the host field when the browser determines that the Unicode form is potentially confusable (mixed-script names, names matching known homograph patterns).

file:// and data: URIs follow different rules. The file:// scheme has no host component on most systems — a path like file:///etc/hosts has an empty authority and an absolute path. Windows file URLs sometimes include the drive letter as part of the path (file:///C:/Users/...). The data: scheme is structurally different from network URLs: there is no host, no path in the usual sense, and the entire URL after the comma is the resource content (optionally base64-encoded). Both schemes parse with new URL() but the resulting object has empty host, port, and search fields.

URLs without a scheme need a base URL. The string example.com/path is not a valid URL on its own — it is a relative reference. To parse it as if it were absolute, supply a base via new URL('example.com/path', 'https://placeholder.com') or prepend a scheme manually (which this tool does as a fallback). True relative references like ../api/v2/users resolve against a base URL using a documented algorithm; without a base, they cannot be parsed.

Userinfo is deprecated in browser contexts. RFC 3986 still permits the userinfo@host form, but every modern browser strips userinfo from displayed URLs and refuses to use embedded credentials for HTTPS authentication. The component still parses correctly so that auditing tools can detect its presence, but you should never rely on it for legitimate authentication — use the Authorization header instead. Latin-look-alike phishing attacks frequently combine userinfo with IDN homographs to maximize visual deception.

Trailing slash significance for relative paths. https://example.com/api and https://example.com/api/ are different URLs, and any relative path resolved against them will yield different results. ../v2 resolved against the first becomes https://example.com/v2; resolved against the second it becomes https://example.com/api/v2. Static-site generators and reverse proxies sometimes normalize trailing slashes (or fail to), which produces broken relative links if you don't notice the redirect.

Fragments are never sent to the server. The HTTP request line is built from the path and query only — the fragment is stripped before the request goes on the wire. This is a feature, not a bug: it lets single-page applications use fragment-based routing (#/dashboard) without triggering server requests, and it lets OAuth implicit-flow callbacks return tokens in the fragment where they will not be logged by intermediate proxies. Server-side analytics never see the fragment; if you need analytics on hash-based routes, you have to instrument them on the client.

Multiple ? or # characters split on the first occurrence. A URL like https://example.com/path?q=hello?world#a#b has the first ? as the query separator (everything after is the query string, including the second ?) and the first # as the fragment separator (everything after is the fragment, including the second #). Literal ? and # characters inside path segments or query values must be percent-encoded.

Behind the Scenes: RFCs, Specifications, and How Browsers Actually Parse

RFC 2396 (1998) and the Original URI Generic Syntax

The first formal generic syntax for URIs appeared in RFC 2396 in August 1998, written by Tim Berners-Lee, Roy Fielding, and Larry Masinter. It introduced the now-familiar breakdown into scheme, authority, path, query, and fragment, defined the reserved and unreserved character sets, and codified percent-encoding as the mechanism for embedding reserved or non-ASCII characters as data. RFC 2396 explicitly distinguished URIs (the umbrella term) from URLs (URIs with a retrieval scheme) and URNs (URIs that name a resource without locating it).

RFC 3986 (2005) and the Modern Generic Syntax

RFC 3986 superseded RFC 2396 in January 2005 with several clarifications: the formal ABNF grammar was tightened, the authority component was decomposed explicitly into userinfo@host:port, percent-encoding rules were refined per-component (different reserved sets apply to the path vs. the query vs. the fragment), and the relative-reference resolution algorithm was specified in unambiguous pseudocode. RFC 3986 is still the IETF standard for URI generic syntax, but as a static document it cannot keep pace with the evolving needs of browser interoperability.

WHATWG URL Living Standard (Browser Reality)

Browser vendors found that strict RFC 3986 conformance broke too many real-world URLs and produced subtle interoperability differences between browsers. The WHATWG URL Living Standard (maintained at url.spec.whatwg.org) documents the "forgiving" parsing algorithm that all modern browsers actually implement. It normalizes backslashes to forward slashes, tolerates trailing dots in hostnames, applies the http scheme by default for certain ambiguous inputs, and specifies the percent-encode sets used by each URL component down to the byte. The WHATWG specification is a continuously updated living document, intentionally — interoperability requires the spec to track browser behavior in real time, not the other way around.

The URL Constructor and URLSearchParams

The browser-side API for working with URLs is the URL constructor and its associated URLSearchParams interface, both standardized by WHATWG and available in every browser since approximately 2016. new URL(input, [base]) returns an object with read-write properties for every component (protocol, username, password, host, hostname, port, pathname, search, searchParams, hash, href, origin). Mutating a property re-serializes the URL on read; the href property always returns the current canonical form. URLSearchParams handles query-string parsing and serialization with full support for repeated keys, percent-encoding, and the +-for-space convention used in application/x-www-form-urlencoded.

URL vs. URI vs. IRI

URI is the umbrella term for any string that identifies a resource. URL is a URI whose scheme names a retrieval mechanism (http, https, ftp, mailto, file, etc.). URN is a URI that identifies a resource by persistent name (urn:isbn:0-486-27557-4, urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6). IRI (Internationalized Resource Identifier, RFC 3987) extends URI to allow Unicode characters directly in the string; browsers accept IRIs and convert them to URIs internally by Punycode-encoding the host and percent-encoding the path/query/fragment. In casual usage "URL" and "URI" are interchangeable for HTTP URLs, but the distinction matters when working with non-network schemes or when reading specifications.

Percent-Encoding Per Component

A subtle but important point: the percent-encode set that applies to a character depends on which URL component the character appears in. The path uses the C0 controls set plus the characters ", <, >, `, ?, #, {, }. The query uses the same set plus '. The fragment uses a smaller set that omits ? and # (because both are valid inside a fragment). This is why encodeURI and encodeURIComponent behave differently in JavaScript: encodeURI uses the full-URL set (preserving /?#& as structural characters), while encodeURIComponent uses the per-component set that escapes those characters as data.

Comparison: This Tool vs. Browser URL vs. Python urlparse vs. Node node:url vs. PostgreSQL Regex

Multiple environments offer URL parsing, each with different conformance levels, return shapes, and edge-case behaviors. The table below summarizes when each option is the right choice.

URL Parsing Options Across Environments
Tool / API Specification Followed Output Shape Strengths When to Use
This tool (Parse mode) WHATWG URL via browser new URL() Visual breakdown + table + parsed params Zero-install, instant feedback, copy buttons per field, no upload Debugging a specific URL, learning the spec, auditing third-party links
Browser new URL() + URLSearchParams WHATWG URL Living Standard JS object with mutable properties Native, fast, handles edge cases the way the browser does, no dependency Client-side JS in production; any context where you need WHATWG semantics
Python urllib.parse.urlparse RFC 3986 generic syntax ParseResult namedtuple (6 fields) Stdlib, deterministic, follows the older spec strictly Server-side Python scripts; auditing URLs against strict RFC 3986
Python urllib.parse.urlsplit + parse_qs RFC 3986 + form-encoding SplitResult + dict of lists Splits without parsing params separately; parse_qs preserves repeated keys Python scripts where you handle the query string explicitly
Node node:url (legacy url.parse) WHATWG with RFC 3986 fallback Plain object with named properties Long-standing API, widely used in older Node code Legacy Node code; deprecated in favor of the WHATWG URL class
Node new URL() WHATWG URL Living Standard Same shape as browser URL Matches browser semantics exactly; works in server code New Node.js code; anywhere you need browser-compatible parsing server-side
PostgreSQL regexp_split_to_array None — regex-based, ad hoc Array of substrings Runs in-database; can index parsed components Last resort when you must parse URLs inside a query and cannot push to app code
PostgreSQL uri extension (third-party) RFC 3986 Custom uri type with component accessors Properly structured; supports indexing Heavy URL workloads in Postgres where you'd otherwise denormalize
Choose by environment first, then by specification strictness. WHATWG-conformant tools accept inputs that RFC 3986-strict tools reject, and vice versa for a small number of edge cases.

The key trade-off is conformance vs. permissiveness. WHATWG parsers (this tool, browser new URL(), Node new URL()) accept the messy URLs that exist on the real web — and silently normalize them — while RFC 3986 parsers (Python urlparse, the PostgreSQL uri extension) reject any URL that doesn't conform to the formal grammar. If you're processing URLs that came from a browser (form input, scraped HTML, copy-pasted links), use a WHATWG parser. If you're validating URLs against a strict allowlist or implementing a protocol that requires RFC 3986 conformance, use an RFC 3986 parser and reject inputs the WHATWG parser would silently fix.

Frequently Asked Questions

A URI (Uniform Resource Identifier) is the umbrella term for any string that identifies a resource. A URL (Uniform Resource Locator) is a URI that also tells you how to locate the resource — it carries a scheme like https:// that names a retrieval protocol. A URN (Uniform Resource Name) is a URI that identifies a resource by persistent name rather than location, such as urn:isbn:0-486-27557-4. An IRI (Internationalized Resource Identifier) extends URI to allow Unicode characters directly in the string — the same identifier without requiring percent-encoding for non-ASCII text. Modern browsers accept IRIs and convert them to URIs internally for transmission.
Browser URL parsing follows the WHATWG URL Living Standard, which intentionally accepts inputs that RFC 3986 would reject — backslashes get normalized to forward slashes, trailing dots in hostnames are tolerated, and a number of percent-encoded byte sequences are silently re-encoded into canonical form. The WHATWG specification calls this "forgiving" parsing because its primary goal is reproducing real-world browser behavior across the messy URLs that exist on the live web. If you need strict RFC 3986 conformance, validate with a separate library or apply regex checks after parsing rather than relying on the URL constructor alone.
The URL() constructor requires either an absolute URL or a relative reference paired with a base URL. To parse example.com/path as a complete URL, supply a base: new URL('example.com/path', 'https://placeholder.com') — this returns a URL object you can read components from. To parse a true relative reference like ../api/v2/users for resolution against a known location, pass that location as the second argument. Some tools accept scheme-less input and prepend https:// automatically; this tool does that as a fallback when the raw input fails to parse.
RFC 3986 defines two character sets: unreserved characters (A–Z, a–z, 0–9, and the four marks - . _ ~) never need encoding; reserved characters (: / ? # [ ] @ ! $ & ' ( ) * + , ; =) have structural meaning and must be encoded when used as data rather than syntax. The exact rules vary by URL component: the path allows / unencoded but the query string must encode it; the query allows = and & as separators but values must encode any literal = or & inside them. Spaces are encoded as %20 in paths and either %20 or + in query strings. Anything outside ASCII must be UTF-8 encoded first, then percent-escaped byte by byte.
The fragment identifier (the part after #) was designed in RFC 1738 as a client-side hint — it tells the browser which section of the retrieved resource to scroll to or which sub-state to activate. Because the fragment only makes sense after the resource has been fetched and rendered, browsers strip it from the HTTP request line. The query string, by contrast, is part of the resource identifier itself — different query strings represent different resources from the server's perspective, so the server needs to see them. This split is why single-page applications use hash-based routing (#/dashboard) when they need URL-driven state without triggering server requests.
There is no limit set by the URL specification itself, but practical limits come from the software in the chain. RFC 9110 says HTTP servers should support request lines of at least 8000 bytes. Internet Explorer historically capped at 2,083 characters and that figure still circulates as a de facto safe maximum. Modern Chrome and Firefox tolerate URLs above 64K characters in the address bar, but proxies, CDNs, log analyzers, and search engines often truncate well before that. A reasonable rule of thumb is to keep URLs under 2,000 characters for maximum compatibility; if a request needs more data, switch to a POST body instead of stuffing it into the query string.
The URLSearchParams interface handles this automatically and correctly across edge cases. new URLSearchParams('?a=1&b=2&a=3').getAll('a') returns ['1', '3'] — duplicated keys are preserved as arrays. Object.fromEntries(new URLSearchParams(queryString)) gives a plain object but loses duplicates because object keys must be unique. Avoid hand-rolled string splitting on & and =: it silently breaks on encoded ampersands inside values, on bare keys without =, and on the + character (which decodes to space in query strings but stays as + in path segments). URLSearchParams handles all of these correctly per the WHATWG URL specification.
Internationalized Domain Names (IDNs) allow Unicode characters in hostnames, which means an attacker can register a domain that visually resembles a legitimate one by substituting characters from another script. The Cyrillic "а" (U+0430) is visually identical to the Latin "a" (U+0061), so paypa1.com written entirely in Cyrillic looks like paypal.com to the eye but is a completely different domain. The DNS protocol stores these as Punycode (xn-- prefix), so xn--80ak6aa92e.com is the actual registered string for the all-Cyrillic example. Modern browsers display the Punycode form when a hostname mixes scripts or matches a known homograph pattern, but URLs in emails, chat messages, and PDFs render the Unicode form — making this attack still effective in phishing contexts.