How to URL Encode and Decode a String

Independently researched No sponsored picks Affiliate supported

To URL encode a string, you replace any character that is not allowed in a URL with a percent sign followed by its two-digit hexadecimal byte value — so a space becomes %20 and & becomes %26. To decode, you reverse the process: every %XX sequence is turned back into the original character. The fastest way to do this without writing code is to paste your text into the free URL Encoder/Decoder, which runs entirely in your browser.

URL encoding (more precisely, percent-encoding) is one of those topics that seems trivial until a stray ampersand breaks your API call or a double-encoded space shows up in a customer’s email link. This guide explains exactly what gets encoded and why, the difference between the JavaScript encoding functions, how query strings differ from path segments, and the double-encoding traps that bite even experienced developers.

What Is URL Encoding?

A URL has a strict grammar defined by RFC 3986. Only a limited set of characters is allowed to appear literally in a URL. Everything else — spaces, accented letters, emoji, and characters that have special structural meaning (like ?, &, #, and /) when they appear in the wrong place — must be escaped.

Percent-encoding works in three steps:

  1. The character is converted to its bytes using a character encoding (today, almost always UTF-8).
  2. Each byte is written as a two-digit uppercase hexadecimal number.
  3. Each hex pair is prefixed with a %.

So the space character (byte value 0x20) becomes %20. The character é, which is two bytes in UTF-8 (0xC3 0xA9), becomes %C3%A9. Decoding simply runs the steps in reverse.

Reserved, Unreserved, and Everything Else

RFC 3986 splits characters into categories. Understanding these categories is the whole game:

Category Characters Need encoding?
Unreserved A–Z a–z 0–9 - _ . ~ Never — always safe
Reserved (gen-delims) : / ? # [ ] @ Only when used as data, not structure
Reserved (sub-delims) ! $ & ' ( ) * + , ; = Only when used as data, not structure
Everything else space, " < > \ ^ ` { } ` `, accented letters, emoji, control chars

The subtle part is the reserved set. A / is perfectly legal — as a path separator. But if a slash is part of a single path segment’s value (say, a filename literally named report/2024), it must be encoded as %2F, or the server will read it as two segments. The character is the same; the meaning is what changes.

When You Need to URL Encode

You reach for URL encoding any time user-controlled or arbitrary text has to travel inside a URL. Common situations:

  • Building query strings?q=hello world&category=books & more will break unless the values are encoded.
  • Path segments with special characters — slugs, IDs, or filenames containing spaces, slashes, or Unicode.
  • Redirect parameters — passing one URL as a parameter of another (?next=https://example.com/page?a=1) requires encoding the inner URL completely.
  • OAuth and signed requests — signature algorithms depend on a precisely defined encoding; one wrong character invalidates the signature.
  • Form submissions — HTML forms with application/x-www-form-urlencoded encoding (the default) percent-encode field names and values automatically.

If you are debugging any of these and just need to see the encoded or decoded version of a string, the URL Encoder/Decoder gives you the answer instantly — paste, click, copy.

How to URL Encode a String (Step by Step)

Method 1: Use the Online Tool (Fastest)

  1. Open the URL Encoder/Decoder.
  2. Paste your raw text into the input box.
  3. Click Encode to get the percent-encoded result, or Decode to reverse an encoded string.
  4. Copy the output.

Everything happens locally in your browser — nothing is uploaded to a server, which matters when your URLs contain tokens, internal hostnames, or anything sensitive.

Method 2: In JavaScript

The browser and Node.js give you two built-in functions:

encodeURIComponent("hello world & more");
// => "hello%20world%20%26%20more"

decodeURIComponent("hello%20world%20%26%20more");
// => "hello world & more"

Use encodeURIComponent for a single piece of data — one query value, one path segment.

const base = "https://api.example.com/search";
const term = "blue + green shoes";
const url  = `${base}?q=${encodeURIComponent(term)}`;
// => "https://api.example.com/search?q=blue%20%2B%20green%20shoes"

Method 3: On the Command Line

curl can encode query data for you with --data-urlencode:

curl -G "https://api.example.com/search" \
     --data-urlencode "q=blue + green shoes"

In Python, the standard library does it cleanly:

from urllib.parse import quote, quote_plus, unquote

quote("hello world & more")        # 'hello%20world%20%26%20more'
quote_plus("hello world & more")   # 'hello+world+%26+more'  (form style)
unquote("hello%20world%20%26%20more")  # 'hello world & more'

encodeURI vs encodeURIComponent

This is the single most common source of confusion in JavaScript, so it deserves its own section. Both functions percent-encode strings, but they treat the structural characters of a URL completely differently.

Function Leaves these unescaped Use it for
encodeURI() A–Z a–z 0–9 - _ . ! ~ * ' ( ) plus ; / ? : @ & = + $ , # An entire, already-structured URL
encodeURIComponent() A–Z a–z 0–9 - _ . ! ~ * ' ( ) only A single component (query value, path segment)

The practical difference: encodeURI assumes the string is a complete URL and deliberately leaves the delimiters (/, ?, &, =, #, etc.) alone so the URL stays usable. encodeURIComponent assumes the string is just a value that will be dropped into a larger URL, so it escapes those delimiters too.

const value = "a/b?c=d&e";

encodeURI(value);
// => "a/b?c=d&e"        ← delimiters left intact (often WRONG for a value)

encodeURIComponent(value);
// => "a%2Fb%3Fc%3Dd%26e"  ← everything escaped (correct for a value)

Rule of thumb: if you are inserting a piece of data into a URL, you almost always want encodeURIComponent. Reach for encodeURI only when you have a whole URL with spaces or Unicode in it and you want to make it valid without destroying its structure.

One caveat: neither function escapes !, ', (, ), or *. These are technically legal in URLs, but some stricter servers and the OAuth 1.0 spec want them encoded. If you need full compliance, post-process the output:

function strictEncode(str) {
  return encodeURIComponent(str)
    .replace(/[!'()*]/g, c => "%" + c.charCodeAt(0).toString(16).toUpperCase());
}

Query Strings vs Path Segments

Although percent-encoding looks the same everywhere, the rules about which characters are dangerous shift depending on where in the URL you are.

Path segments

In the path (/users/alice/files/report.pdf), the slash is the separator. If a value within a segment contains a slash, it must be encoded as %2F, and a space as %20. The + character has no special meaning in a path — it is a literal plus sign, so a literal space must never be written as + in a path.

Raw segment:   my report (final).pdf
Encoded path:  /files/my%20report%20(final).pdf

Query strings

In the query string (?key=value&key2=value2), the separators are ?, &, and =. Any of those characters appearing inside a key or value must be encoded (%3F, %26, %3D). And here is the historical wrinkle: the application/x-www-form-urlencoded format — used by HTML forms and many APIs — encodes a space as + rather than %20, and treats a literal + as %2B.

Raw value:     blue + green
Form-encoded:  q=blue+%2B+green
Plain-encoded: q=blue%20%2B%20green

Both forms decode to the same thing if the decoder knows the context. A query-string decoder turns + into a space; a path decoder leaves + as a literal plus. This is why decodeURIComponent("a+b") returns "a+b" (it does not touch +) while a form parser returns "a b". Mixing them up produces stray + signs or missing spaces in your data.

Position Space encodes as + means
Path segment %20 literal +
Query string (form-urlencoded) + (or %20) a space, unless written %2B

Common Mistakes and Pitfalls

1. Double encoding

The most frequent bug. You encode a value, then accidentally encode the whole URL again — or your framework encodes it once and you encode it a second time.

Original:        hello world
Encoded once:    hello%20world
Encoded twice:   hello%2520world   ← the % itself got encoded to %25

When you see %25 in a place where you expected %20, you have a double-encoding problem. Decode the string twice to confirm, then remove the duplicate encoding step in your code. Pasting the broken value into the URL Encoder/Decoder and decoding it once or twice is the quickest way to diagnose this — if it takes two decode passes to read, it was encoded twice.

2. Encoding an entire URL with encodeURIComponent

If you run a full URL through encodeURIComponent, the slashes and colons get escaped and the URL stops working as a link:

encodeURIComponent("https://example.com/path");
// => "https%3A%2F%2Fexample.com%2Fpath"

That output is correct only when the URL is itself a value (for example, a ?next= redirect parameter). As a standalone address it is broken. Use encodeURI (or nothing) for whole URLs.

3. Forgetting the character-set step

Percent-encoding operates on bytes, not characters. A non-ASCII character must first be turned into bytes via UTF-8. Encoding é as a single %E9 (its Latin-1 byte) instead of %C3%A9 (its UTF-8 bytes) leads to mojibake — garbled text — on any UTF-8 server. Modern functions like encodeURIComponent always use UTF-8, so prefer them over hand-rolled encoders.

4. Encoding + in form data by hand

If you manually build a form body and write a space as %20, most parsers accept it. But if you write a literal + expecting it to survive, it will be decoded as a space. Always encode a literal plus in form data as %2B.

5. Trusting decoded input

Decoding is where security bugs hide. A value like %2e%2e%2f decodes to ../, which can enable path-traversal attacks if you decode and then use the result as a file path. Always validate decoded input after decoding, and never decode a value more than once unless you can prove it was encoded that many times.

Worked Examples (Input → Output)

Raw string URL encoded
hello world hello%20world
a&b=c a%26b%3Dc
100% 100%25
[email protected] user%40example.com
café ☕ caf%C3%A9%20%E2%98%95
path/to/file (as a value) path%2Fto%2Ffile
?key=val#frag %3Fkey%3Dval%23frag

To decode, simply read the table right-to-left: caf%C3%A9 becomes café once each percent-pair is converted back to its byte and the bytes are interpreted as UTF-8.

Quick Reference: Characters That Always Need Encoding

These never appear safely as data and should always be percent-encoded when they are not serving their structural role:

space  →  %20   (or +  in form data)
"      →  %22
#      →  %23
%      →  %25
&      →  %26
+      →  %2B   (when it must stay a literal plus)
/      →  %2F   (inside a single path segment)
:      →  %3A
;      →  %3B
=      →  %3D
?      →  %3F
@      →  %40

Encode and Decode in One Click

You do not need to memorize the hex tables. Open the URL Encoder/Decoder, paste your string, and switch between Encode and Decode. It handles UTF-8 and special characters, runs entirely in your browser (nothing is uploaded), and is free with no sign-up. It is the fastest way to verify a query string, untangle a double-encoded value, or sanity-check what your backend is actually receiving.

If you work with the data formats and tokens that travel through URLs, these related guides pair well with this one:

Frequently Asked Questions

What is the difference between URL encoding and Base64?

URL encoding (percent-encoding) makes a string safe to put inside a URL by replacing unsafe characters with %XX codes. Base64 converts binary data into 64 printable ASCII characters. They solve different problems and are not interchangeable, though both are sometimes used to make data “URL-safe.”

Should I use encodeURI or encodeURIComponent in JavaScript?

Use encodeURIComponent for individual pieces of a URL like a query parameter value or a single path segment. Use encodeURI only when you have a full URL and want to leave the structural characters (such as / ? & = #) intact.

Why does my space turn into a + sign sometimes and %20 other times?

Inside the query string of an application/x-www-form-urlencoded form, a space is encoded as +. Everywhere else in a URL a space should be encoded as %20. Decoders must know the context to turn + back into a space correctly.

Why Trust FindPicked?

Our recommendations are based on extensive research, real user reviews, and spec-by-spec analysis. We never accept payment for placement. When you buy through our links, we may earn a commission — this supports our work at no extra cost to you.

Learn how we pick →