Toolypet
Back to Blog
Dev

Complete Guide to URL Encoding - Solving Character Encoding and Special Character Issues

Why do Korean characters break and special characters cause errors in API calls? Learn the difference between encodeURI vs encodeURIComponent and practical solutions.

Toolypet Team

Toolypet Team

Development Team

5 min read

Complete Guide to URL Encoding

"I sent Korean parameters to the API and they came back garbled."

Sent: ?name=John Doe
Received: ?name=John%20Doe

The cause of this issue is URL encoding. Understanding it properly means you'll never struggle with broken characters again.


Why Encoding is Necessary

URLs were created in the 1990s and only allow ASCII characters.

Safe Characters in URLs

A-Z  a-z  0-9  - _ . ~

That's all.

Problematic Characters in URLs

CharacterProblem
Non-ASCIINot ASCII characters
SpaceInterpreted as URL delimiter
&Parameter separator
?Query string start
=Key-value separator
#Fragment start
/Path separator

What Encoding Does

Converts problematic characters to %XX format (hexadecimal).

Space  -> %20
&      -> %26
e      -> %65 (though safe, as example)

JavaScript Encoding Functions

Key Differences

const text = "hello world&name=John Doe";

encodeURI(text);
// "hello%20world&name=John%20Doe"
// & and = remain intact (preserves URL structure)

encodeURIComponent(text);
// "hello%20world%26name%3DJohn%20Doe"
// & -> %26, = -> %3D (encodes everything)

When to Use Which

SituationFunctionReason
Query parameter valueencodeURIComponentMust encode &, =
Entire URLencodeURIPreserve URL structure
Path segmentencodeURIComponentMust encode /

Common Mistakes

// Wrong: encodeURIComponent on entire URL
const url = "https://api.com/search?q=test";
encodeURIComponent(url);
// "https%3A%2F%2Fapi.com%2Fsearch%3Fq%3Dtest"
// Not usable as URL!

// Correct: Only encode the value
const query = "test";
const url = `https://api.com/search?q=${encodeURIComponent(query)}`;
// "https://api.com/search?q=test"

URLSearchParams - The Modern Way

Use URLSearchParams instead of manual encoding.

Basic Usage

const params = new URLSearchParams({
  name: "John Doe",
  city: "New York City",
  tags: "developer,frontend"
});

params.toString();
// "name=John+Doe&city=New+York+City&tags=developer%2Cfrontend"

Encoding happens automatically. No room for mistakes.

With URL Object

const url = new URL("https://api.com/search");
url.searchParams.set("q", "John Doe");
url.searchParams.set("page", 1);

url.toString();
// "https://api.com/search?q=John+Doe&page=1"

Parsing (Decoding)

const url = new URL("https://api.com/search?name=John%20Doe");

url.searchParams.get("name");  // "John Doe" <- auto-decoded!

Practical Problem Solving

Problem 1: Double Encoding

// Encoding an already encoded value
const encoded = "%20";
encodeURIComponent(encoded);
// "%2520"
// % -> %25 causing complete corruption

Solution: Check if already encoded before encoding

function safeEncode(str) {
  try {
    // If already encoded, decode first then re-encode
    return encodeURIComponent(decodeURIComponent(str));
  } catch {
    // Decode failure = not encoded yet
    return encodeURIComponent(str);
  }
}

Problem 2: Two Faces of Space

%20  vs  +

Both represent space but have different origins.

MethodUsage
%20URL standard (RFC 3986)
+HTML forms (application/x-www-form-urlencoded)
encodeURIComponent("hello world");  // "hello%20world"
new URLSearchParams({q: "hello world"}).toString();  // "q=hello+world"

Both are processed correctly by servers. But choose one method for consistency.

Problem 3: Framework Already Encodes

axios, fetch, React Router, etc. automatically encode.

// axios - auto encoding
axios.get('/search', { params: { name: 'John Doe' } });
// Request: /search?name=John%20Doe

// Wrong: Manual encoding causes double encoding
axios.get('/search', { params: { name: encodeURIComponent('John Doe') } });
// Request: /search?name=John%2520Doe (broken)

Rule: If using a framework, don't encode manually.


Server-Side Handling

Node.js / Express

// Auto-decoded
app.get('/search', (req, res) => {
  const name = req.query.name;  // "John Doe"
});

// Same for path parameters
app.get('/users/:name', (req, res) => {
  const name = req.params.name;  // "John Doe"
});

Python / Flask

from flask import request

@app.route('/search')
def search():
    name = request.args.get('name')  # "John Doe"

PHP

$name = $_GET['name'];  // "John Doe"
// PHP also auto-decodes

Special Cases

Base64 in URL

Standard Base64 contains +, /, = which cause problems in URLs.

// Standard Base64
btoa("hello");  // "aGVsbG8="

// URL-safe Base64
function base64UrlEncode(str) {
  return btoa(str)
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=+$/, '');  // remove padding
}

base64UrlEncode("hello");  // "aGVsbG8"

JWT uses this format.

Fragment (#) Caution

https://example.com/page?name=John#section
                                   ^
                        Not sent to server from here

Everything after # (fragment) is processed only in the browser and not sent to the server.


Debugging Tips

Browser Address Bar

Browsers show decoded URLs for readability.

Displayed: https://example.com/users/John Doe
Actual: https://example.com/users/John%20Doe

Check the actual request URL in Developer Tools Network tab.

Testing with curl

# Direct encoded URL
curl "https://api.com/search?name=John%20Doe"

# Let curl encode
curl -G "https://api.com/search" --data-urlencode "name=John Doe"

Summary

SituationSolution
Creating query parametersUse URLSearchParams
Encoding values onlyencodeURIComponent
Encoding entire URLencodeURI
Using a frameworkDon't encode manually
Broken charactersSuspect double encoding

Core Principle: Whenever possible, let URLSearchParams or your framework handle it, and avoid manual encoding.


Related Tools

ToolPurpose
URL EncoderEncoding/Decoding
URL ParserURL structure analysis
Base64Base64 conversion
URLencodingdecodingweb developmentAPIquery string

About the Author

Toolypet Team

Toolypet Team

Development Team

The Toolypet Team creates free, privacy-focused web tools for developers and designers. All tools run entirely in your browser with no data sent to servers.

Web DevelopmentCSS ToolsDeveloper ToolsSEOSecurity