Back to blog
ExplainersOctober 18, 2025

What Is URL Encoding? The Complete Explanation

URL encoding converts special characters into percent-encoded sequences so they can safely appear in URLs and query strings.

URL encodingdeveloper toolsweb developmentHTTP

For related fixes and guides, see our troubleshooting hub.

You paste a URL into a browser and it looks normal. You look at the raw HTTP request and the same URL looks like this:

https://example.com/search?q=hello%20world&type=text%2Fplain

That %20 is a space. The %2F is a forward slash. This is URL encoding also called percent encoding.

Why URLs Need Special Character Handling

URLs have a defined syntax. Characters like ?, &, =, #, and / have specific meaning in a URL's structure:

  • / separates path segments
  • ? starts the query string
  • & separates query parameters
  • = assigns values
  • # starts a fragment identifier

If you want to include a literal & in a query parameter value (say, a search for "bread & butter"), you can't write:

/search?q=bread & butter

The URL parser interprets the & as a parameter separator and reads two parameters: q=bread and butter= (with empty value).

URL encoding escapes the & so the parser treats it as part of the value, not as a structural character.

How Percent Encoding Works

Each character is converted to its UTF-8 byte representation, and each byte is written as %XX where XX is the hexadecimal value.

Examples:

CharacterUTF-8 byteEncoded
Space0x20%20
&0x26%26
=0x3D%3D
+0x2B%2B
/0x2F%2F
?0x3F%3F
#0x23%23
@0x40%40
:0x3A%3A

Non-ASCII characters (accented letters, CJK characters, emoji) are encoded using multiple bytes:

CharacterUTF-8 bytesEncoded
é0xC3 0xA9%C3%A9
0xE4 0xB8 0xAD%E4%B8%AD
😀0xF0 0x9F 0x98 0x80%F0%9F%98%80

Safe Characters (Never Encoded)

Unreserved characters are passed through unchanged:

  • Letters: A–Z, a–z
  • Digits: 0–9
  • -, _, ., ~

These are "unreserved" in RFC 3986 they carry no special meaning in any part of a URL.

The + Confusion

+ is a legacy alternative encoding for a space in query strings (from the older application/x-www-form-urlencoded format, used in HTML forms).

So a space can be encoded as either %20 or +, but only in query strings. In URL paths, + is a literal plus sign not a space.

This causes bugs when people assume + always means space or always means plus. The URL encoder/decoder handles this correctly by context.

URL Encoding vs. HTML Encoding

These are different things:

  • URL encoding %XX percent sequences. For URLs, query strings, API parameters.
  • HTML encoding &, <, >, etc. For HTML content, not URLs.

A URL in an HTML attribute needs both:

<a href="https://example.com/search?q=bread+%26+butter">Search</a>

The %26 URL-encodes the &. Inside an HTML attribute, you'd additionally HTML-encode any & that's part of the URL syntax but a formatter handles that automatically.

When You Actually Encode URLs

Building query strings

// Never do this:
const url = `/search?q=${userInput}`;

// Do this:
const url = `/search?q=${encodeURIComponent(userInput)}`;

encodeURIComponent encodes everything except unreserved characters. It's the right function for encoding individual query parameter values.

Don't use encodeURI for query values it intentionally leaves :, /, ?, #, &, and = unencoded because it's meant for encoding a whole URL, not a parameter value.

Fetch/axios requests

Most HTTP libraries handle encoding automatically when you pass parameters as an object:

// The library URL-encodes the params object for you:
fetch('/search?' + new URLSearchParams({ q: 'bread & butter' }))

URLSearchParams handles encoding correctly and is the preferred modern approach.

API documentation

When API docs show a raw URL with special characters, the actual request must use the encoded version. If the docs show:

GET /search?filter=type:image

Your request should be:

GET /search?filter=type%3Aimage

Because : has special meaning in some URL contexts.

Decoding a URL

If you receive an encoded URL and want to read it, the URL encoder/decoder decodes it instantly.

In JavaScript:

decodeURIComponent("bread%20%26%20butter") // "bread & butter"
decodeURI("https%3A%2F%2Fexample.com%2Fsearch") // Wrong  decodeURI doesn't decode these

In Python:

from urllib.parse import unquote
unquote("bread%20%26%20butter")  # "bread & butter"

What Happens If You Don't Encode

Browsers are forgiving they often encode URLs automatically when you type them in the address bar. But:

  • APIs built in code aren't automatically forgiving
  • Logs and server access records show literal characters, which can misparse
  • Some servers reject requests with unencoded special characters
  • Sharing URLs with special characters in messages often breaks the URL at those characters

Full Example

You're building a search URL where the query is C++ programming.

Without encoding: /search?q=C++ programming
With encoding:    /search?q=C%2B%2B%20programming

The + signs in C++ become %2B (literal plus in query strings can be ambiguous with the space shorthand). The space becomes %20.


The URL encoder/decoder handles encoding and decoding in both directions. For query string building in code, prefer encodeURIComponent() in JavaScript or urllib.parse.quote() in Python.

Related articles