Skip to content
← Back to Blog
URL EncodingPercent-EncodingDeveloper ToolsString Tools

URL Encoding Explained: Percent-Encoding, Query Strings and Common Mistakes

Almost nobody looks up url encode for fun. They look it up because a link broke, a query parameter arrived mangled, or a URL that should have worked returned an error. This article explains percent-encoding through the bugs it causes, and it is worth saying up front: most URL problems are not about encoding being hard, they are about encoding happening at the wrong moment. You can encode and decode URLs in the browser, or read on for the rules that stop the breakage.

RMBG.PRO string tools for encoding and decoding URLs

Published on September 19, 2026

URL encoding — also called percent-encoding — is the system that lets a URL carry characters it was never designed to hold. A URL is, at heart, a strictly formatted string of ASCII characters. The moment you need to put a space, an accent, an emoji or an Arabic word inside it, you have a problem: those characters are not in the ASCII set, and several punctuation marks are already reserved for structure.

The solution is substitution. Any character that cannot appear literally is replaced by a percent sign followed by two hexadecimal digits, which represent that character’s byte value. A space is %20, a question mark is %3F, a hash is %23, and an ampersand is %26. Reading and writing these escapes is what an URL encoder does.

Three ideas explain almost every encoding bug you will meet. Encoding is context-sensitive — the rules differ between the path and the query string. Encoding is idempotent when done once — encoding an already-encoded value a second time creates a broken value. And encoding must respect structure — the characters that build a URL should never be encoded, because encoding them turns them into data.

The rest of this article works through which characters are safe, how the path and the query string differ, why + and %20 are not interchangeable, how UTF-8 handles non-Latin scripts, the double-encoding bug and its tell-tale signature, and when you should not encode at all. If you just need a conversion, the URL encoder and decoder handles it instantly in your browser.

Why Do URLs Need Encoding at All?

A URL is not a free-text field; it is a structured address with a grammar. The characters ?, &, =, #, / and % are reserved, which means they have structural jobs. The ? marks where the path ends and the query begins; & separates parameters; = separates a parameter from its value; # starts the fragment.

The moment one of those characters appears inside your data, the URL becomes ambiguous. A search for a&b would be read as two parameters, and a value containing # would truncate everything after it into a fragment that never reaches the server. Encoding them — a%26b — removes the ambiguity, because %26 can only mean “an ampersand character” and never “start a new parameter”.

The same applies to characters that are simply illegal. URLs are defined over a limited ASCII repertoire, so a space, a control character, or anything non-Latin cannot appear literally without being escaped. Percent-encoding is the single mechanism that handles both cases: reserved characters that would be misread, and characters that cannot be written at all.

Which Characters Are Safe to Leave Alone?

There is a small set of characters you never need to encode, known as the unreserved characters. Memorising it saves a lot of uncertainty, because anything in this set means exactly itself everywhere in a URL:

GroupCharactersEncode?
LettersA–Z and a–zNo
Digits0–9No
Four safe punctuation marks- _ . ~No
Reserved structural characters/ ? # & = : %Only when they are data, never as structure
Everything elsespaces, accents, non-Latin scripts, emoji, +, & in a valueYes

Notice the last row: the reserved characters are conditional. A / separating path segments must stay literal, but a / inside a filename should be encoded as %2F or it will be read as an extra directory level. That conditional rule — structure versus data — is the whole game.

Path Versus Query String: The Rules Differ

A URL has distinct zones, and encoding rules are not uniform across them. The part before the ? is the path; everything after is the query string. Browsers, servers and parsing libraries apply different conventions to each, which is a quiet source of bugs.

  • In the path, a space should be encoded as %20. A + in the path is a literal plus sign, not a space.
  • In the query string, both %20 and + can mean a space, but only because query strings traditionally follow the application/x-www-form-urlencoded convention from HTML form submissions.
  • Decoders disagree. JavaScript’s URLSearchParams turns + into a space, while decodeURIComponent leaves + as a literal plus. Mix them and the same URL yields two different values.

The practical takeaway is to know which zone you are encoding for, and to decode with the matching decoder. If a value is round-tripping wrong and the text looks right, check whether a stray + is being interpreted as a space in one place and a plus sign in another.

The + Versus %20 Trap

This deserves its own section because it is the single most common encoding bug, and it is invisible until it bites. Both + and %20 can represent a space — but only inside a query string, and only under the form-encoding convention.

The + convention comes from HTML form submission. When a form POSTs data as application/x-www-form-urlencoded, spaces in the field values are written as +. That convention carried over to query strings, which is why ?q=hello+world and ?q=hello%20world both arrive as “hello world” on most servers.

The failure mode is subtle. If you percent-encode the literal text 1+1 because you want the plus sign to survive, you get 1%2B1 — correct. If you naively substitute spaces with + in a path, or let a form-encoded decoder touch a value where + was meant literally, you get a silent corruption: “1 1” instead of “1+1”.

The safe habit is to use %20 for spaces everywhere, which is unambiguous in every zone, and to reserve + for the specific form-encoding case where you know the receiver expects it. When debugging, remember the asymmetry: URLSearchParams decodes + to a space, decodeURIComponent does not.

UTF-8, Accents and Non-Latin Scripts

Non-Latin text adds a wrinkle that surprises everyone the first time. A URL is ASCII, so an accented letter or an Arabic character must be converted to bytes first — in UTF-8 — and then each byte is percent-encoded individually.

The French word café encodes to caf%C3%A9: the ASCII letters pass through unchanged, while the é is two bytes in UTF-8, giving %C3 and %A9. An Arabic word expands further — each letter is multiple bytes, so a short word becomes a long run of percent groups like %D9%85%D8%B1....

  • One character can be several groups. Never assume one percent group equals one character; count bytes, not escapes.
  • Wrong charset scrambles the text. If the server decodes the bytes as a single-byte encoding instead of UTF-8, accents become mojibake. UTF-8 is the default for a reason — stick with it unless you have a specific legacy reason not to.
  • Modern browsers hide this. They display readable URLs and do the encoding on submission, so a pasted Arabic URL looks clean in the address bar even though the request on the wire is percent-encoded. That gap between display and wire format is exactly why an explicit encoder is sometimes needed.

This is also the case where a dedicated tool helps most, because hand-encoding non-Latin text is error-prone. The URL encoder converts text to its correct UTF-8 percent form and back.

The Double-Encoding Bug and Its Signature

Double encoding is the bug that keeps giving, because it produces a URL that looks encoded and still arrives wrong. It happens when a value that is already encoded gets encoded again — common when one function hands a value to another without knowing the first already escaped it.

Watch the arithmetic. A space becomes %20. Encode that output again and the percent sign itself is encoded, since % is a reserved character: %20 becomes %2520. One round of decoding now yields the literal string %20 instead of a space, because the value contained a real percent sign.

InputEncoded onceEncoded twice (bug)
a space%20%2520
an ampersand%26%2526
a slash%2F%252F

The tell-tale signature is a %25 where a % should be — %2520, %2526, %252F are all double-encoded values. If you see them, the value was encoded twice.

The fix is to decode exactly as many times as it was encoded, but the better fix is to prevent it: encode a raw value once, at the boundary where it enters the URL, and keep a single source of truth for whether a value is already encoded. Functions that “helpfully” re-encode their input are the usual culprit.

When Should You Not Encode?

Encoding is a tool, not a policy of “encode everything, just in case”. Applied blindly it breaks the very URLs it was meant to protect, because the structural characters are what make a URL parseable at all.

  • Never encode the structural skeleton. The :// after the scheme, the / between path segments, and the ? & = # of the query string must stay literal. Encode them and the address stops being an address.
  • Never encode an already-encoded value. That is the double-encoding bug from the previous section, and it is entirely self-inflicted.
  • Do not encode to “clean up” a URL you do not understand. If a URL is already failing, randomly encoding more of it rarely helps and often hides the real problem. Decode it fully first, see what the raw values actually are, then encode once.

The mental model worth keeping: encode the value, never the structure. Build the URL from parts you trust, encode each data value exactly once as it goes in, and let the delimiters do their job.

Where This Shows Up in Practice

These are the situations where an encoding bug actually costs time, and where knowing the rules pays off.

  • Search parameters. A search box containing & or = will split into extra parameters unless the value is encoded. Query-string builders in frameworks usually handle this; string concatenation does not.
  • Tracking links. UTM parameters carry titles and campaign names that routinely contain spaces and accents. One unencoded space in an email link and the whole URL breaks for every recipient who clicks it.
  • API requests. APIs receive values as URL parameters, and an unencoded # silently truncates the request, while a literal + becomes a space. Encoding is not optional here — it is part of the contract.
  • Redirects and forwarded URLs. When one URL is passed inside another, it must be encoded as a single value or the outer URL misreads the inner one’s delimiters.

Each of these is the same bug in different clothing: a value was not encoded where the grammar required it, or was encoded twice by code that did not trust the last step.

Encode or Decode a URL Without the Guesswork

Whatever the URL problem, the conversion itself should take seconds:

  • A free URL encoder and decoder that handles percent-encoding in both directions.
  • Correct UTF-8 handling for accents, Arabic and other non-Latin scripts.
  • Runs entirely in your browser — nothing you paste is uploaded.
  • Part of the wider string tools set: word counter, character counter, case converter, and Base64 encoder.

Try the URL Encoder

Paste text, get a valid URL. Paste an encoded URL, get the text back. It runs in your browser.

Encode / Decode a URL

Frequently Asked Questions

What does it mean to encode a URL?▾

Encoding a URL means replacing characters that are not allowed, or that have a special structural meaning, with a percent sign followed by two hexadecimal digits — for example a space becomes %20 and an ampersand becomes %26. This keeps the URL valid and unambiguous while it travels through browsers, servers and APIs, and it is what allows values to contain punctuation or non-Latin scripts without breaking the request.

What is the difference between %20 and + in a URL?▾

Both represent a space, but only in the right context. %20 is the standard percent-encoding of a space and is valid anywhere in a URL. The + convention comes from the application/x-www-form-urlencoded format used for HTML form submissions, where it means a space inside the query string only. A + in the path is a literal plus sign. Decoders also differ: URLSearchParams turns + into a space, while decodeURIComponent leaves it as a literal plus — so mixing the two produces wrong values.

How do I know if a URL is double-encoded?▾

Look for sequences where the percent sign itself has been encoded, which shows up as %25 followed by two hex digits — the classic sign is %2520 where %20 was intended, or %252F instead of %2F. The value literally contains a percent sign after one round of decoding. It happens when an already-encoded value is encoded a second time, and the fix is to decode the exact number of times it was encoded, or better, to stop double-encoding by only encoding raw values once.

Why do French accents and Arabic characters appear as %C3%A9 and %D9%85 in a URL?▾

URLs are defined over ASCII, so any character outside it is first encoded to bytes in UTF-8, and each byte is then percent-encoded individually. The accented é is two bytes in UTF-8, giving %C3%A9. An Arabic letter is also multiple bytes, producing longer runs such as %D9%85. This is why a single character can occupy several percent groups, and why decoding with the wrong character set scrambles the text.

Which characters can I leave unencoded in a URL?▾

The unreserved set is always safe: the upper- and lower-case letters A–Z and a–z, the digits 0–9, and the four punctuation marks - _ . ~ (hyphen, underscore, full stop, tilde). Everything else — spaces, accents, non-Latin scripts, and the reserved characters like ? & = # % — must be encoded when it appears as data rather than as URL structure.

When should I not encode a URL?▾

Do not encode the structural characters that give a URL its shape — the scheme separator ://, the path slashes, and the ? & = # that delimit the query string — because encoding them turns them into data and breaks the address. Also avoid encoding an already-encoded value, which creates a double-encoding bug. The rule is to encode the raw value once, at the boundary where it enters the URL, and leave the surrounding structure alone.

Similar articles

View all