Skip to content

URL Encoder / Decoder: Encode or Decode Any String Online

Free URL encoder/decoder with explicit component, full-URL and form modes — because encodeURIComponent and encodeURI aren't interchangeable.

Try it now: URL Encoder & Decoder Percent-encode and decode URLs and query strings, with explicit component, full-URL and form modes. Runs entirely in your browser.

What Percent-Encoding Actually Does

A URL is only allowed to contain a small, fixed set of characters: unreserved characters (letters, digits,-, _, ., ~) and a handful of reserved characters that are structurally meaningful — :, /, ?, #, &, =, and a few others. Percent encoding is the escape mechanism that lets a URL carry any other byte anyway: take a character outside that safe set, get its byte value (UTF-8, for anything non-ASCII), and write it as % followed by two hex digits. A space becomes %20, an ampersand becomes %26, the Euro sign becomes %E2%82%AC (three bytes, three%XXtriplets). The mechanism itself is simple. What trips people up isn't the encoding — it's that URL encode/decode isn't one operation with one correct output. There are three, and they disagree with each other on purpose.

Component Encoding vs. Full-URL Encoding: Two Different Jobs

The characters :, /, ?, &, and =mean two completely different things depending on where they sit. In a full URL, they're delimiters — the scheme is separated from the host by ://, the path from the query string by ?, and one query parameter from the next by &. Encode a full URL as if it were a single value and you destroy it: :// turns into %3A%2F%2F, the browser no longer sees a scheme separator, and the string stops being a URL at all. That's what encodeURI() is for — it escapes unsafe characters (spaces, non-ASCII) but deliberately leaves reserved delimiters alone, because a full URL still needs them to parse.

Now flip the context. If that same & or = appears as literal data inside one query parameter's value— a search term that happens to contain an ampersand, a redirect URL passed as a value to another URL — it is not a delimiter anymore, it's just a character in the data. Leave it unescaped there and the URL parser reads it as the start of a new parameter instead of as part of the value it actually belongs to. This is exactly what encodeURIComponent() is for: it escapes everything encodeURI()leaves alone, on the assumption that what you're handing it is a single component, not a structural whole.

encodeURI() vs encodeURIComponent() on the same string
const url = "https://example.com/search?q=cats & dogs";

encodeURI(url)
// "https://example.com/search?q=cats%20&%20dogs"
// scheme, host, path, ?, & and = are left alone — still a working URL

encodeURIComponent(url)
// "https%3A%2F%2Fexample.com%2Fsearch%3Fq%3Dcats%20%26%20dogs"
// : / ? & = are escaped too — this is no longer a URL,
// it's a value meant to be placed *inside* one

Neither output is wrong — they answer different questions. Run encodeURI() on a whole address bar value and you get something you can still navigate to. Run encodeURIComponent()on a search term before appending it to a query string and you get a value that can't be mistaken for extra delimiters, no matter what it contains. The bug shows up when someone reaches for the wrong one:encodeURI() a value that's going into a query parameter and any & or = inside it silently truncates or corrupts the parameter list; encodeURIComponent() a full URL before using it and you've turned an address into an unusable string.

Form Encoding's Space Quirk: %20 vs. +

There's a third variant, and it disagrees with the first two on one specific point. HTML forms submitted with application/x-www-form-urlencoded — the default for a plain <form>, and the format behind most GET query strings built by browsers — encode a literal space as +, not %20. Everything else about it matches standard percent encoding; only the space rule differs, because + was reserved for that purpose before %20 became the general convention.

the same space, two encodings
Input: "first name"

Standard percent-encoding (encodeURIComponent):
"first%20name"

Form encoding (application/x-www-form-urlencoded):
"first+name"

The asymmetry is what causes real bugs, and it runs in the decode direction as much as the encode direction. A + decoded as form data becomes a space. A + decoded under strict percent-encoding rules stays a literal +. So a value that genuinely contains a plus sign — C++, a phone number extension, a math expression — decodes correctly under one mode and silently turns into C (two spaces) under the other. There is no way to tell which rule applies just by looking at a raw +in a query string; you have to know which encoding produced it. This is the single most common reason a query string decoder gives someone the “right” decoded value in one tool and a subtly wrong one in another — they picked different default modes, not because either implementation is broken.

Practical Use Cases

  • Building a query string with dynamic values.Encode each value with component encoding before it goes into the query string — never the reverse order, and never the whole assembled URL at once, or you'll re-encode the ? and & you just relied on.
  • Debugging an incoming request log. A raw access log or webhook payload often shows a query string exactly as it arrived, percent-encoded — a query string decoder turns %7B%22id%22%3A42%7D back into something you can actually read.
  • Sharing a link with special characters in it. A path segment or query value containing spaces, accented characters, or symbols needs component encoding to survive being pasted into chat, email, or a spreadsheet without silently breaking at the first unsafe character.
  • Reading a form-submitted GET request. Recognizing that + means space in that specific context — and only that context — is what keeps a form-encoded query string from being misread.

Choosing the Right Mode

The rule that actually resolves all of this: encode at the narrowest scope you have. If you're encoding one value that's about to be inserted into a query string or path segment, use component encoding — it's the safe default, because it never leaves a structural character behind for a parser to misread. Reach for full-URL encoding only when the input genuinely is a complete URL you want to make safe to transmit without touching its structure. Reach for form encoding only when you know the other end expects application/x-www-form-urlencoded specifically — a space-as-plus is a feature there, not elsewhere.

GenKitLab's URL Encoder / Decoder keeps these three modes explicit instead of picking one silently — component, full-URL, and form — so the output matches what you actually meant to encode, and it runs entirely in your browser: nothing you paste in is uploaded anywhere. If you're working with JWTs, note that the token's header and payload use a related but distinct scheme — Base64URL — which swaps a couple of characters specifically so the result never needs percent-encoding in a URL at all; that's covered in the Base64 encode/decode guide, alongside GenKitLab's Base64 tool.

Frequently asked questions

What's the difference between URL encoding and percent encoding?

They're the same mechanism — percent encoding is the technical name for the %XX escape format, and URL encoding is the common name for using that mechanism inside a URL. The confusion is really about which mode: encoding a full URL, a single component, or a form-submitted value each escape a different set of characters.

When should I use encodeURIComponent() instead of encodeURI()?

Use encodeURIComponent() whenever you're encoding a single value — a query parameter, a path segment — before inserting it into a larger URL. It escapes structural characters like &, =, and / because, at that point, they're just data. Use encodeURI() only when the input is already a complete URL you want to make safe without altering its structure.

Why does a + in a query string sometimes decode as a space and sometimes stay a +?

Because two different encoding rules exist. application/x-www-form-urlencoded (the format HTML forms use) treats + as an encoded space. Strict percent-encoding does not — a + there is a literal plus sign. The same raw character decodes differently depending on which rule the sender used, which is why a query string decoder needs to know the context, not just the string.

Why does encoding a whole URL with encodeURIComponent() break it?

Because encodeURIComponent() escapes reserved delimiters like :, /, ?, and & on the assumption it's given a single value, not a structure. Run it on a full URL and the scheme separator, path slashes, and query delimiters all get percent-escaped, leaving a string that's no longer a navigable URL — it becomes a value meant to be embedded inside another URL instead.

Is it safe to percent-encode data before it's uploaded anywhere?

With GenKitLab's URL Encoder/Decoder, yes — encoding and decoding happen entirely in your browser using the same JavaScript APIs described here (encodeURIComponent, encodeURI, and form encoding), and nothing you type or paste is sent to a server.

What characters are safe in a URL without any encoding?

Unreserved characters — uppercase and lowercase letters, digits, and the four symbols -, _, ., ~ — never need encoding anywhere in a URL. Reserved characters like :, /, ?, #, &, and = are safe only when they're acting as delimiters; the same characters need escaping the moment they appear as literal data inside a component.

Last updated