url-encoding converter developer-tools security tutorial

URL Encoding and Decoding: What Every Developer Needs to Know

UseEasyTool Team Developer Tools
July 28, 2026 8 min read

What Is URL Encoding?

Type "hello world" into a browser address bar and watch what happens. The space vanishes. What you actually see in the URL bar is hello%20world. That %20 is URL encoding in action.

URL encoding (also called percent encoding) converts characters into a format that can be transmitted over the internet. The rules come from RFC 3986, which defines the valid characters for URIs.

The idea is simple: take any character outside the safe set and replace it with a percent sign (%) followed by two hex digits representing the character's byte value.

hello world  -->  hello%20world
a+b=c       -->  a%2Bb%3Dc
cafe        -->  caf%C3%A9 (UTF-8 encoded)

The "safe" characters that do not need encoding are uppercase and lowercase ASCII letters (A-Z, a-z), digits (0-9), and a handful of special characters: hyphen (-), period (.), underscore (_), and tilde (~).

Everything else? Encoded. Spaces, ampersands, question marks, hash symbols, non-ASCII characters like Chinese or emoji -- they all get converted to their percent-encoded form.

Try This Tool

Put what you just read into practice — open the tool now.

Open Tool →

Why URL Encoding Exists

URLs have a job to do: they tell the browser where to go and what to send. The structure scheme://host/path?query#fragment relies on specific characters as delimiters. The ? marks the start of query parameters. The & separates key-value pairs. The # introduces a fragment.

If your actual data contains these delimiter characters, the parser has no way to tell whether & is part of your data or a separator. Encoding removes the ambiguity.

Consider a Google search for the phrase "URL encoding guide". The browser constructs something like:

https://www.google.com/search?q=URL%20encoding%20guide
                         ^^^^^^^^^^^^^^^^^^^^^^^^
                         query parameter "q" with the value "URL encoding guide"

The space between each word becomes %20. Without this encoding, the browser might interpret the raw spaces as malformed URL syntax.

API calls are where this really bites. Send a request with a user's name that contains special characters, and you will get 400 Bad Request errors or corrupted data if you skip encoding.

// Real-world API call with encoding needed
GET /api/users?name=Jos%C3%A9%20Garc%C3%ADa&city=New%20York

// Without encoding, this breaks:
GET /api/users?name=José García&city=New York
//                      ^^^^
// The server sees "city" parameter missing, and "García" as a separate param

Reserved vs Unsafe Characters

Not all characters that get encoded are equal. RFC 3986 draws a line between reserved and unsafe characters.

Reserved characters have structural meaning in URLs. They only need encoding when used as data rather than delimiters. Unsafe characters have no structural role and should always be encoded when they appear in data.

Character Encoded Form Category
!%21Reserved
#%23Reserved
$%24Reserved
&%26Reserved
'%27Reserved
(%28Reserved
)%29Reserved
*%2AReserved
+%2BReserved
,%2CReserved
/%2FReserved
:%3AReserved
;%3BReserved
=%3DReserved
?%3FReserved
@%40Reserved
[%5BReserved
]%5DReserved
Character Encoded Form Category
space%20Unsafe
"%22Unsafe
<%3CUnsafe
>%3EUnsafe
{%7BUnsafe
}%7DUnsafe
|%7CUnsafe
\%5CUnsafe
^%5EUnsafe
~%7EUnsafe
`%60Unsafe
%%25Unsafe

Notice that last entry. The percent sign itself is %25. This is the source of the double-encoding trap -- encoding something that is already encoded will turn %20 into %2520. The server then sees the literal string %20 instead of a space. This bug is surprisingly common and maddening to debug.

Common Encoding Mistakes

I have seen these mistakes in production code, in shipped apps, in well-funded startups. Here are the ones that cause the most damage.

Mistake 1: Encoding the entire URL

This is the classic blunder. You take a full URL and run it through your encoder, which mangles the ://, the slashes, and everything else.

// WRONG - encodes the entire URL
const encoded = encodeURIComponent("https://example.com/api?q=test");
// Result: https%3A%2F%2Fexample.com%2Fapi%3Fq%3Dtest
// This URL is now broken. The browser cannot parse it.

// RIGHT - encode only the parameter values
const param = encodeURIComponent("test value");
const url = `https://example.com/api?q=${param}`;
// Result: https://example.com/api?q=test%20value

The rule: encode the values, not the structure.

Mistake 2: Double encoding

This happens when data gets encoded twice before it reaches the server. Some frameworks encode query params automatically. If you also encode manually, the server receives %2520 instead of %20.

// WRONG - double encoding
let value = "hello world";
value = encodeURIComponent(value);  // "hello%20world"
value = encodeURIComponent(value);  // "hello%2520world" -- broken!

// RIGHT - encode once
let value = "hello world";
let encoded = encodeURIComponent(value);  // "hello%20world"

If you see %25 in your server logs, check for double encoding. Our free URL encoding tool lets you check what the encoded output should look like for any input string.

Mistake 3: Forgetting to encode Unicode characters

Some encoding functions only handle ASCII by default. Non-ASCII characters like Chinese, Arabic, or emoji get dropped or mangled if you do not specify UTF-8 encoding.

// WRONG - encoding that drops Unicode
// Some legacy functions only encode ASCII
const broken = escape("cafe"); // "cafe" -- loses the accent entirely

// RIGHT - proper UTF-8 encoding
const correct = encodeURIComponent("caf\u00E9");
// "caf%C3%A9" -- properly encodes the UTF-8 bytes

Mistake 4: Confusing URL encoding with Base64

These solve different problems. URL encoding makes data safe for URLs. Base64 converts binary data into ASCII text. They are not interchangeable. Using Base64 in a URL parameter without URL encoding the Base64 result will break because Base64 uses +, /, and = -- all characters with special meaning in URLs. If you need to embed Base64 in a URL, use a Base64 encoder with the URL-safe variant (replacing + with - and / with _).

URL Encoding in JavaScript

JavaScript has two functions that trip people up constantly: encodeURIComponent() and encodeURI().

The difference matters. encodeURIComponent() encodes everything that could be unsafe, including reserved characters like /, ?, and &. Use it for individual query parameter values.

encodeURI() leaves the URL structure intact -- it skips ://, /, ?, #, and a few others. Use it when you have a complete URL and want to clean up any unsafe characters in the path or fragment.

// encodeURIComponent - for parameter values
const query = encodeURIComponent("hello world & foo=bar");
// "hello%20world%20%26%20foo%3Dbar"

const url = `https://api.example.com/search?q=${query}`;
// https://api.example.com/search?q=hello%20world%20%26%20foo%3Dbar

// encodeURI - for a full URL that might have unsafe chars in the path
const fullUrl = encodeURI("https://example.com/path with spaces/page");
// https://example.com/path%20with%20spaces/page

// Decoding
const decoded = decodeURIComponent("hello%20world");
// "hello world"

When building API requests with JSON bodies, the JSON string itself often needs to be encoded if you are passing it as a query parameter (which you should avoid, but sometimes it happens):

const payload = JSON.stringify({ name: "Jos\u00E9 Garc\u00EDa", city: "S\u00E3o Paulo" });
const encoded = encodeURIComponent(payload);
const url = `https://api.example.com/data?payload=${encoded}`;

// Better approach: send JSON in the request body, not the URL
fetch("https://api.example.com/data", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: payload  // No encoding needed in the body
});

If you need to pretty-print or validate JSON before encoding, use our JSON formatter.

URL Encoding in Python

Python gives you urllib.parse.quote() for encoding and urllib.parse.unquote() for decoding. The safe parameter controls which characters are skipped during encoding.

from urllib.parse import quote, unquote

# Basic encoding
encoded = quote("hello world")
print(encoded)  # hello%20world

# The 'safe' parameter lets you exclude characters from encoding
encoded_slash = quote("/api/users/1", safe="/")
print(encoded_slash)  # /api/users/1 -- slash preserved

# Space encoding: %20 vs +
encoded_plus = quote("hello world", safe="")
print(encoded_plus)  # hello%20world

# quote_plus() uses + for spaces (application/x-www-form-urlencoded)
from urllib.parse import quote_plus
print(quote_plus("hello world"))  # hello+world

The difference between quote() and quote_plus() matters. quote() turns spaces into %20. quote_plus() turns spaces into +. Use quote_plus() when encoding form data (the application/x-www-form-urlencoded content type). Use quote() for path segments and query strings.

The requests library handles encoding for you in most cases:

import requests

# requests encodes query params automatically
resp = requests.get("https://api.example.com/search", params={"q": "hello world"})
# The actual URL sent: https://api.example.com/search?q=hello+world
print(resp.request.url)

# For form data, requests encodes that too
resp = requests.post("https://api.example.com/submit", data={"name": "Jos\u00E9 Garc\u00EDa"})
# Content-Type: application/x-www-form-urlencoded
# Body: name=Jos%C3%A9+Garc%C3%ADa

This auto-encoding is convenient but also where double-encoding bugs creep in. If your framework also encodes, you get double-encoded params. Check what your HTTP library is doing before adding your own encoding layer.

URL Encoding in Other Languages

Here is a quick reference for encoding in a few other popular languages.

Go

import "net/url"
encoded := url.QueryEscape("hello world")  // hello+world
decoded, _ := url.QueryUnescape("hello+world")  // hello world

PHP

$encoded = urlencode("hello world");      // hello+world (spaces become +)
$encoded = rawurlencode("hello world");    // hello%20world (spaces become %20)
$decoded = rawurldecode("hello%20world");  // hello world

In PHP, urlencode() uses + for spaces (for form data), while rawurlencode() uses %20 (for raw URL components). Use rawurlencode() for most URL construction tasks.

Java

import java.net.URLEncoder;
import java.net.URLDecoder;
String encoded = URLEncoder.encode("hello world", "UTF-8");  // hello+world
String decoded = URLDecoder.decode("hello+world", "UTF-8");  // hello world

Java's URLEncoder.encode() uses + for spaces by default. If you need %20, replace the + signs after encoding: encoded.replace("+", "%20").

URL Encoding and Security

URL encoding is not just a formatting concern. It has direct security implications. Poorly handled encoding opens the door to URL injection, parameter tampering, and cross-site scripting (XSS).

URL injection via unencoded input

Imagine a web application that takes a redirect URL as a parameter but does not validate or encode it properly:

// VULNERABLE - user controls the entire redirect target
app.get("/login", (req, res) => {
  const returnUrl = req.query.return;
  res.redirect(returnUrl);  // An attacker can set this to any URL
});

// An attacker crafts:
// /login?return=https://evil.com/phishing
// The user gets redirected to a phishing site after login

The fix involves validating the redirect target against an allowlist and properly encoding any user input that ends up in URLs:

// FIXED - validate against an allowlist
const ALLOWED_DOMAINS = ["mysite.com", "app.mysite.com"];

app.get("/login", (req, res) => {
  const returnUrl = req.query.return;
  const parsed = new URL(returnUrl, "https://mysite.com");

  if (ALLOWED_DOMAINS.includes(parsed.hostname)) {
    res.redirect(parsed.pathname + parsed.search);
  } else {
    res.redirect("/dashboard");  // Fallback to a safe default
  }
});

XSS via improperly decoded URLs

Some applications decode URL-encoded input before rendering it in HTML without sanitizing. An attacker can encode malicious payloads to bypass naive filters:

// An attacker sends:
// /search?q=%3Cscript%3Ealert(1)%3C/script%3E
// Decoded: <script>alert(1)</script>

// If the server decodes this and renders it in the page without escaping,
// the script executes -- XSS.

Always escape output for the correct context. URL encoding is for transport, HTML escaping is for rendering. They serve different purposes.

Parameter tampering

Encoded URLs can be tampered with just as easily as plain ones. If your API relies on URL parameters for authorization decisions, sign them. Use a URL signature generator to create signed URLs that prevent parameter tampering. A signed URL includes a hash of the parameters, so any modification invalidates the link.

For critical operations, combine URL signing with a hash generator to create tamper-evident request identifiers. This gives you an audit trail and makes it possible to detect modified requests.

Quick Conversion Without Code

Sometimes you do not need a function call. You need to figure out what a URL in your logs actually says, or verify what your app is sending before filing a bug report.

Copy a garbled URL from your server logs, paste it into our online URL encoder/decoder, and see the decoded result instantly. No code, no terminal, no python -c "import urllib.parse; print(...)".

Common scenarios where an online tool saves time:

  • Debugging encoded URLs pulled from browser DevTools Network tab
  • Checking that your API client is sending correctly encoded parameters
  • Decoding webhook callback URLs from third-party services
  • Verifying email tracking links and marketing campaign URLs
  • Encoding test data to paste into API testing tools

The URL encoder tool handles both encoding and decoding, supports UTF-8 input, and works entirely in your browser -- nothing gets sent to any server.

Quick tip: if you are debugging a URL in Chrome DevTools, the Network tab shows decoded query parameters by default. Right-click any request and select "Copy as URL" to get the encoded version, or look at the "Query String Parameters" section for the decoded values.

Related Articles

Base64 vs URL Encoding: When to Use Which?

Understand the key differences between Base64 and percent encoding, and learn which one fits your use case.

Regular Expressions for Beginners

A practical introduction to regex patterns, from basic matching to advanced techniques for text processing.

View All Articles

Browse our complete collection of developer tutorials, guides, and tips.