URL Parsing and Query Editing, Explained
After reading this you will know exactly how a URL splits into its six parts, how percent-encoding turns unsafe characters into %XX bytes, and how to edit query parameters without corrupting the request.
What a URL actually is
A URL is a single string with a strict internal structure. Take this one:
https://user:[email protected]:8443/catalog/shoes?color=blue&size=42#reviews
That string is not one blob. It is six named components stitched together by delimiter characters. The parser reads the delimiters (://, @, :, /, ?, #) and hands you each part separately. Once split, you can see that the port is 8443, the path is /catalog/shoes, and the fragment is reviews, without squinting at punctuation.
The authoritative grammar lives in RFC 3986, section 3. It defines the generic syntax as scheme://authority/path?query#fragment, where the authority itself splits into optional userinfo, host and optional port. Every browser, every HTTP library and this tool follow that same grammar.
The six components and their delimiters
Here is the anatomy of the example above, part by part.
- Scheme
- Everything before
://. Here it ishttps. It is case-insensitive and must start with a letter. RFC 3986 section 3.1. - Authority
- Between
://and the next/,?or#. Contains optional userinfo (user:pass@), the host (shop.example.com) and an optional port (:8443). - Path
- From the first
/up to?or#. Here/catalog/shoes. This is what the server routes on. - Query
- After
?, up to#. A set of key-value pairs joined by&:color=blue&size=42. - Fragment
- After
#. Herereviews. The browser keeps it; it is never sent in the HTTP request.
The default port depends on the scheme. http defaults to 80, https to 443. A URL like https://example.com:443/ and https://example.com/ point to the same place, so the explicit :443 is redundant.
Percent-encoding: the math of %XX
Only a limited set of characters may appear literally in a URL. RFC 3986 section 2.3 calls these the "unreserved" characters: the ASCII letters A-Z a-z, the digits 0-9, and the four marks - . _ ~. Everything else, if it needs to carry meaning as data rather than as a delimiter, is percent-encoded.
The rule is mechanical. Take the character, look up its byte value in UTF-8, then write a % followed by that byte in two uppercase hexadecimal digits.
Here byte is one of the UTF-8 bytes of the character, and hex_2 writes it as two hex digits with a leading zero if needed. A space is byte 0x20, so it becomes %20. An ampersand is 0x26, so it becomes %26. Characters outside ASCII use more than one byte: the euro sign € is UTF-8 bytes E2 82 AC, so it encodes as %E2%82%AC, three percent-groups for one character.
To decode, you reverse the steps: read each %XX as one byte, collect the byte sequence, then interpret it as UTF-8. This tool decodes every part on display and re-encodes on rebuild.
A worked example you can reproduce
Encoding a query value with a space and an ampersand
Suppose you want the parameter q to carry the literal value tea & coffee (with a space on each side of the ampersand). If you paste that raw into a query, the & looks like a delimiter and the value gets truncated to tea . Encoding fixes it.
- Start with the value
tea & coffee, which is 13 characters. - Encode each byte that is not unreserved. The letters stay. The two spaces become
%20each. The ampersand (byte0x26) becomes%26. - The result is
tea%20%26%20coffee. - Assembled into a query:
?q=tea%20%26%20coffee.
Count the length: the value grew from 13 characters to 18, because three single characters (two spaces, one ampersand) each became three characters. When the server decodes it, it gets back exactly tea & coffee.
Inside a query string, a space is often written as + instead of %20. That comes from the application/x-www-form-urlencoded format, not from RFC 3986. Both decode to a space in query context, but in the path only %20 means a space; a + in a path is a literal plus sign.
Reading the query as a table
The query string color=blue&size=42&color=red is not a map. It is an ordered list of pairs, and keys may repeat. Splitting on & then on the first = gives you three rows:
| # | Key | Value (decoded) |
|---|---|---|
| 1 | color | blue |
| 2 | size | 42 |
| 3 | color | red |
How a server treats the two color rows is not defined by any single spec. PHP keeps the last value unless you name the key color[]. Node's URLSearchParams.getAll("color") returns both ["blue", "red"]. Because behavior varies, a table view that preserves order and duplicates tells you the truth about what was sent, rather than silently collapsing it.
When to use this, and when not to
Use a parser whenever you need to see or change one part of a URL without disturbing the rest: adding a tracking parameter, stripping a session token before sharing a link, or checking whether a redirect target smuggled an unexpected host. Editing in a table beats hand-editing the string because you cannot accidentally break the encoding of a neighboring value.
Do not use URL parsing to validate that a resource exists or that a host is safe to trust. Parsing tells you the structure, not the reality. A perfectly well-formed URL can point at a server that returns an HTTP error status, or at a host that does not resolve at all. Structure and reachability are separate questions.
Common mistakes
Three errors show up again and again.
- Double-encoding. If a value is already
%20and you encode it again, the%(byte0x25) becomes%25, giving%2520. The server then decodes it back to the literal text%20, not a space. Encode exactly once. - Trusting the fragment on the server. The part after
#never leaves the browser (RFC 3986 section 3.5). If your backend depends on a value, put it in the query or the path, not the fragment. - Assuming keys are unique. As shown above,
color=blue&color=redis legal. Code that reads only the first match may drop data the sender intended.
Watch the host boundary in redirect URLs. The string https://[email protected]/ has host evil.test, because everything before the @ is userinfo. A quick glance reads "trusted.example.com" and misses the trap. Always confirm the host the parser reports, not the text your eye lands on first.
Related tools
Once you have a clean URL, other references help with the surrounding work. The MIME type lookup maps a file extension in a path to its content type. The User-Agent parser decodes the client string that travels alongside a request. For raw character handling, the HTML entity reference covers the named escapes you meet in HTML attributes, which are a different escaping scheme from percent-encoding. And the Keycode inspector is handy when you are debugging the form that builds a query in the first place.
Frequently asked questions
Why does my space turn into %20 sometimes and + other times?
Both mean a space inside a query string. %20 is the RFC 3986 form and works in any component. + comes from HTML form submission (application/x-www-form-urlencoded) and only means a space in the query. In a path, + is a literal plus sign, so this tool always emits %20 on rebuild for safety.
Is the port always shown?
Only when it differs from the scheme default or was written explicitly. https://example.com/ has an implied port of 443 but no port component in the string. If you type :443, the parser will show it; whether to keep it is your choice.
Does editing a value in the table change the encoding of other values?
No. Each value is decoded and re-encoded independently on rebuild. Changing color=blue to color=café produces color=caf%C3%A9 and leaves size=42 untouched.
Can a URL contain a non-ASCII host like café.com?
The host uses a separate scheme called Punycode (RFC 3492). café.com is transmitted as xn--caf-dma.com. That is not percent-encoding; it is a distinct algorithm for the domain label only. Query and path use percent-encoding, the host does not.
Is anything I paste sent anywhere?
No. The parsing and rebuilding run entirely in your browser. Nothing you paste leaves your device.