Developer10 min readUpdated 2026-08-07

How to URL Encode and Decode a URL

You paste a link into a chat app and it arrives broken. You add a customer name to a query string and the page returns the wrong result. You share a search URL and everything after the first space disappears.

The cause is almost always the same: a URL can only legally contain a small set of characters, and something in your link isn't one of them. URL encoding — properly called percent-encoding — is the fix. It swaps unsafe characters for a % followed by two hexadecimal digits, so blue shoes becomes blue%20shoes and survives the trip intact.

This guide covers what percent-encoding actually does to your text, the one decision that trips up most people (encode the whole URL or just one piece of it?), the traps that silently corrupt data instead of throwing an error, and a full reference table. You can encode or decode anything as you read using FileNaut's free URL Encoder/Decoder — it runs entirely in your browser, so nothing you paste is uploaded anywhere.

---

What URL encoding actually does

A URL is allowed to contain letters, digits, and a handful of punctuation marks. Everything else has to be represented indirectly.

Percent-encoding works in two steps:

  1. The character is converted to its bytes using UTF-8.
  2. Each byte is written as % plus that byte's two-digit hex value.

A space is byte 0x20, so it becomes %20. An ampersand is 0x26, so it becomes %26. That's the entire mechanism — there's no compression, no encryption, and no secret. Anyone can read a percent-encoded string straight back.

This is also why non-English characters expand. é is two bytes in UTF-8, so it encodes to %C3%A9. Chinese characters are three bytes (%E4%B8%AD), and emoji are four (👍%F0%9F%91%8D). A name in Japanese can triple in length once encoded — worth knowing if you're near a URL length limit.

> Encoding is not security. Percent-encoding is a transport format, not a protection layer. If you need to obscure or transport binary data, that's a different job — see Base64 Encode/Decode — and neither one is encryption.

---

Which characters get encoded

Only these characters are ever left untouched: A–Z, a–z, 0–9, and - _ . ~ ! * ' ( ).

Everything else in the table below is transformed. The two columns matter because they correspond to the two different jobs described in Section 5.

CharacterNameAs a URL partIn a whole URL
(space)space%20%20
"double quote%22%22
#hash / fragment%23# (kept)
$dollar%24$ (kept)
%percent%25%25
&ampersand%26& (kept)
+plus%2B+ (kept)
,comma%2C, (kept)
/slash%2F/ (kept)
:colon%3A: (kept)
;semicolon%3B; (kept)
<less than%3C%3C
=equals%3D= (kept)
>greater than%3E%3E
?question mark%3F? (kept)
@at sign%40@ (kept)
[open bracket%5B%5B
\backslash%5C%5C
]close bracket%5D%5D
^caret%5E%5E
` ``backtick%60%60
{open brace%7B%7B
`\`pipe%7C%7C
}close brace%7D%7D
~tilde~ (kept)~ (kept)

The middle column is what FileNaut's encoder produces. Look at the rows where the columns disagree — #, &, /, :, ?, =, @ — because those are the characters that build a URL. That difference is the whole of Section 5.

---

How to URL encode online (step by step)

  1. Open the URL Encoder/Decoder.
  2. Make sure the Encode tab is selected — it's the default.
  3. Paste your text into the Input URL box on the left. Paste the value you want to make safe (a search term, a name, a redirect target), not necessarily the whole address — Section 5 explains which one you need.
  4. Click Encode URL.
  5. The percent-encoded result appears on the right. Click Copy to put it on your clipboard.

Decoding is the same flow in reverse: click the Decode tab, paste the encoded string, click Decode URL. The tool processes everything locally in your browser — the text never leaves your device, which matters when the URL contains a session token, an internal hostname, or a customer's email address.

To go the other way on a value you don't recognise at all, check whether it's percent-encoded (lots of % pairs) or Base64 (long, ends in =) before picking a tool.

---

The one decision that matters: whole URL or one part?

This is where most broken links come from.

Encoding a single part (a query value, a path segment, a search term) has to escape &, =, ?, / and #, because if it doesn't, those characters will be mistaken for URL structure.

Encoding a whole URL must not escape them — those characters are the structure.

Watch what happens to the same address:

Original:
https://example.com/my page?q=blue shoes&x=a+b#sec 1

Encoded as a whole URL (correct — structure preserved):
https://example.com/my%20page?q=blue%20shoes&x=a+b#sec%201

Encoded as a single part (structure destroyed):
https%3A%2F%2Fexample.com%2Fmy%20page%3Fq%3Dblue%20shoes%26x%3Da%2Bb%23sec%201

That second result isn't a URL any more. Paste it into a browser and you'll get a search, not a page.

FileNaut's encoder does part-encoding (the middle column of the table above). That's the right default, because part-encoding is what you need 90% of the time — and because it's the only one of the two that is ever required. So:

  • Encoding a search term, a name, an email, a redirect target, a filename? Paste just that value. The tool does exactly what you want.
  • Trying to fix a whole URL that has spaces in it? Don't paste the whole thing. Paste only the broken piece — the path segment or the parameter value — encode it, and put it back into the URL by hand.

Here's the correct workflow for building a link. Say you want to search for blue shoes & socks:

  1. Encode only the search term → blue%20shoes%20%26%20socks
  2. Assemble the URL yourself → https://example.com/search?q=blue%20shoes%20%26%20socks

If you had encoded the whole URL as one part, the ? and = would have become %3F and %3D, and the server would have seen one long nonsense path instead of a search.

---

Decoding, and the `+` trap

Decoding reverses the process: blue%20shoes becomes blue shoes, caf%C3%A9 becomes café.

But there's a catch that catches almost everyone. A plus sign in a query string usually means a space — and standard URL decoding won't convert it.

Input:  blue+shoes
Output: blue+shoes     ← unchanged

This is not a bug in the tool; it's a genuine ambiguity in how the web evolved. HTML forms submit data as application/x-www-form-urlencoded, a format that encodes spaces as +. Percent-encoding — the standard used everywhere else — encodes spaces as %20. Both are legitimate, and a decoder cannot tell which one produced the string it's given.

How to handle it: if you're decoding something that came out of a form submission or a search box (it'll look like q=blue+shoes&cat=men), replace every + with %20 before pasting it into the decoder. If you're decoding an API response, an OAuth value, a Base64 payload, or an email address, leave + alone — there it's a real plus sign, and converting it would corrupt the value. user+tag@example.com is a valid address, and turning that + into a space breaks it.

---

The five traps that silently corrupt data

These are ranked by how often they cause real damage. What makes them dangerous is that four of the five produce no error at all — just a wrong answer.

**1. Double encoding — %2520**

Encoding an already-encoded string encodes the % itself:

Original:        blue shoes
Encoded once:    blue%20shoes
Encoded twice:   blue%2520shoes

%25 is a literal %, so %2520 decodes back to %20 — the text %20, not a space. Your user sees "blue%20shoes" printed on the page. If you ever see %25 in a live URL, something has been encoded one time too many. Decode it once and check.

2. Encoding the whole URL as a part — covered in Section 5. Symptom: https%3A%2F%2F at the start. The link becomes unclickable and search engines treat it as a broken destination.

**3. A literal % breaks decoding entirely**

% is the escape character, so a raw one is invalid input:

Input:  100% cotton
Output: Error: Invalid input for decoding.

This is the one trap that does announce itself. If you need a literal percent sign in a URL, it must be encoded as %25 first. Note that the error text appears in the result box, so don't copy it into your link by accident.

**4. !, ', (, ) and * are left unencoded**

Standard URL encoding treats these five as safe, but RFC 3986 lists them as reserved sub-delimiters. Nearly always harmless — but if you're generating an OAuth 1.0 signature, building an AWS Signature V4 request, or hitting a strict API, the signature will fail because the server encoded them and you didn't. Those specs require you to percent-encode all five manually: !%21, '%27, (%28, )%29, *%2A.

5. Encoding after concatenating instead of before

The order is not optional. Build your value, encode the value, then join it into the URL. If you assemble the full string first and encode afterwards, you get trap #2. If a user's input contains an & and you never encode it at all, they can inject an extra parameter into your URL — a real security issue, not just a display bug.

---

Where this actually bites you

  • Query parameters — any search term, filter, or user-supplied value with a space, &, or # in it.
  • UTM tracking links — campaign names like spring sale 2026 must be spring%20sale%202026, or your analytics tool splits the campaign into two.
  • Redirect parameters?next=https://example.com/dashboard needs the target URL encoded as a part, precisely because it contains :// and ?. This is the one case where you deliberately want https%3A%2F%2F.
  • **mailto: links** — subject lines and bodies need encoding; %0A gives you a line break.
  • API requests — a filter like name=O'Brien & Sons breaks the request unless the value is encoded.
  • Filenames in URLsQ3 report (final).pdf becomes Q3%20report%20(final).pdf. This is common enough that many teams just avoid spaces in filenames entirely.
  • Non-Latin content — Cyrillic, Arabic, Chinese and emoji all work fine in modern browsers, which display them decoded while sending them encoded.

---

Doing it in code

Every language ships this. The trap is that most offer two functions, and picking the wrong one causes Section 5's problem.

// JavaScript — encodeURIComponent for a PART, encodeURI for a WHOLE URL
encodeURIComponent('blue shoes & socks');  // 'blue%20shoes%20%26%20socks'
encodeURI('https://example.com/my page');  // 'https://example.com/my%20page'
decodeURIComponent('blue%20shoes');        // 'blue shoes'

// Safest: let the URL API assemble it for you
const u = new URL('https://example.com/search');
u.searchParams.set('q', 'blue shoes & socks');
u.toString();  // encoding handled automatically
# Python — quote() keeps '/' by default; quote_plus() uses + for spaces
from urllib.parse import quote, quote_plus, unquote, urlencode
quote('blue shoes & socks', safe='')   # 'blue%20shoes%20%26%20socks'
quote_plus('blue shoes')               # 'blue+shoes'   (form style)
unquote('blue%20shoes')                # 'blue shoes'
urlencode({'q': 'blue shoes'})         # 'q=blue+shoes'
// PHP — rawurlencode is RFC 3986 (%20); urlencode is form style (+)
rawurlencode('blue shoes');  // 'blue%20shoes'
urlencode('blue shoes');     // 'blue+shoes'
rawurldecode('blue%20shoes');
# Command line
curl --data-urlencode "q=blue shoes & socks" https://example.com/search
jq -rn --arg v 'blue shoes' '$v|@uri'      # blue%20shoes

Rule of thumb across all of them: the function whose name mentions component, raw, or safe='' is the part-encoder — that's usually the one you want. The one that produces + for a space is the form-encoder, and it belongs only in a form body.

---

Tips

  1. Encode values, assemble URLs. Never encode a URL you've already assembled.
  2. Use your language's URL builder (new URL(), urlencode(), a request library's params argument) instead of string concatenation. It removes the whole class of bug.
  3. **If you see %25, suspect double encoding** — decode once and look again.
  4. **If you see https%3A%2F%2F in a browser bar, something over-encoded a whole URL** — the exception is a deliberate redirect parameter.
  5. **Convert + to %20 before decoding form data**, and leave + alone in emails, tokens and Base64.
  6. **Encode ! ' ( ) * by hand for OAuth and AWS signatures.** Standard encoders skip them.
  7. Test the round trip. Encode, decode, and confirm you get your original string back exactly. Anything lost or changed means you've hit one of the Section 7 traps.

---

FAQs

What does %20 mean in a URL?

It's a space. URLs can't contain literal spaces, so a space is replaced by a percent sign followed by 20 — the hexadecimal value of the space character's byte. Paste any URL containing %20 into the URL Decoder and you'll get the readable version back.

What's the difference between %20 and + for a space?

Both can mean a space, in different contexts. %20 is standard percent-encoding and works anywhere in a URL. The plus sign means a space only in form-submitted data (application/x-www-form-urlencoded), which is why search box URLs often look like q=blue+shoes. %20 is always safe; + is only safe in a query string. A standard decoder will not convert + to a space, so replace + with %20 yourself before decoding form data.

Should I encode the whole URL or just part of it?

Almost always just the part. Encoding a whole URL as a single value turns the :// and ? and & into %3A%2F%2F, %3F and %26, which destroys the structure and makes the link unusable. Encode the individual value — the search term, the name, the redirect target — then place it into the URL yourself. The one deliberate exception is a redirect parameter, where the whole target URL is genuinely a value and does need full encoding.

Why does my decoded URL show %2520?

Because it was encoded twice. %25 is the code for a literal percent sign, so %2520 is an encoded version of the text "%20" rather than a space. Decode it one more time to get the real value, then fix the code path that is encoding an already-encoded string — usually a value that gets encoded once when it's built and again when the URL is assembled.

Why do I get "Invalid input for decoding"?

Your text contains a percent sign that isn't part of a valid escape sequence — for example "100% cotton", or a truncated sequence like %C3 with its second byte missing. Because % starts every escape, a raw one is invalid. If you want a literal percent sign in a URL it must be written as %25.

Is URL encoding the same as encryption?

No. Percent-encoding is a public, fully reversible transport format with no key and no secret — anyone can decode it instantly. It offers zero confidentiality. The same is true of Base64. Never use either to hide passwords, tokens or personal data.

Why does one accented letter become six characters?

Encoding works on bytes, not letters, and non-ASCII characters take several bytes in UTF-8. The letter é is two bytes, so it becomes %C3%A9. Chinese characters are three bytes (中 becomes %E4%B8%AD) and emoji are four (👍 becomes %F0%9F%91%8D). Expansion is normal — just watch total URL length if you're encoding a lot of non-Latin text.

Is it safe to paste a URL with a token into an online encoder?

With FileNaut's URL Encoder/Decoder, yes — the encoding runs in your browser using built-in JavaScript functions, and the text is never sent to a server. Be careful with tools that don't state this: many encoders post your input to a backend, which means a session token or internal hostname ends up in someone else's logs.

Why does my OAuth or AWS signature fail even though I encoded everything?

Standard URL encoders leave five characters untouched — ! ' ( ) and * — because they're technically legal in a URL. OAuth 1.0 and AWS Signature V4 require them to be percent-encoded anyway, so the string you sign differs from the string the server signs and the signatures don't match. Replace them manually: %21, %27, %28, %29 and %2A.

Do I need to encode a URL before putting it in an email or chat?

If it contains spaces, yes — that's the single most common reason a link "cuts off" partway through when someone clicks it. Most clients stop reading the link at the first space. Encode the spaces as %20 and the whole link stays clickable.

---

Approx. word count: ~2,300 words of prose (excluding code blocks and metadata).

---

# DEPLOY NOTES — read before publishing

Ready to try it?

Use the tool right now — free, no signup, no upload.