Developer Tools7 min read|MJMinjae

Why Your Korean URL Parameters Keep Breaking: URL Encoding Guide for 2026

A practical guide to URL encoding: percent-encoding explained, encodeURI vs encodeURIComponent compared, URL structure breakdown, common mistakes, and the %20 vs + space debate.

It was 11pm on a Wednesday when the bug report came in. A user in Seoul was trying to search for '서울 맛집' on our app, and the API was returning a 400 error. No data, no helpful message — just a broken request. I opened the network tab, looked at the outgoing URL, and saw it: raw Korean characters sitting in the query string, completely unencoded. Five hours of debugging, and the fix was two characters: wrapping the parameter value in encodeURIComponent().

URL encoding is one of those topics that feels obvious in hindsight but trips up developers at the worst possible times. Once you understand it properly, you'll never spend another evening chasing 400 errors caused by unencoded characters.

What you'll learn

  • How percent-encoding works — and why Korean characters turn into long strings of %XX sequences
  • The exact difference between encodeURI and encodeURIComponent, with a clear comparison table
  • The three most dangerous URL encoding mistakes and exactly how to avoid them

What Is URL Encoding (Percent-Encoding)?

URLs are governed by RFC 3986, which defines a very short list of characters that are allowed without modification: A-Z, a-z, 0-9, and the symbols -, _, ., ~. Everything else — spaces, Korean characters, ampersands, equals signs — must be converted to a safe format before being transmitted over the internet. That safe format is called percent-encoding.

The mechanism is straightforward: take the character, convert it to its UTF-8 byte representation, and write each byte as a percent sign followed by two hexadecimal digits. A space becomes %20. The Korean character 가 becomes %EA%B0%80 — three bytes in UTF-8, so three percent-encoded groups. That's why Korean search queries turn into those long strings of percent signs.

  • Space → %20 (or + in HTML form data — more on this below)
  • & → %26 (reserved as query string separator)
  • = → %3D (reserved for key=value assignment)
  • / → %2F (reserved as path separator)
  • ? → %3F (reserved as query string delimiter)
  • # → %23 (reserved as fragment identifier)
  • Korean, Japanese, Arabic, emoji → 3-4 %XX groups each, one per UTF-8 byte

encodeURI vs encodeURIComponent: The Decision You Get Wrong Most Often

JavaScript gives you two built-in functions for URL encoding, and mixing them up is easily the most common source of URL-related bugs. The rule is simple once you understand why they exist.

encodeURI() is designed to take a complete URL and make it safe to transmit, while leaving the URL's structural characters intact. It won't encode /, ?, &, =, #, or :, because those characters have meaning in a URL and need to remain untouched. encodeURIComponent() is designed to encode a single value that will be inserted into a URL — like a query parameter value. It encodes everything except the absolute bare minimum: letters, digits, and -, _, ., !, ~, *, ', (, ).

// encodeURI — safe for encoding a COMPLETE URL
// Does NOT encode: ; , / ? : @ & = + $ # (URL structure characters)
encodeURI('https://example.com/search?q=hello world&city=Seoul')
// → 'https://example.com/search?q=hello%20world&city=Seoul'
// Correct: spaces encoded, & and = left intact

// encodeURIComponent — safe for encoding a QUERY PARAMETER VALUE
// Does NOT encode: A-Z a-z 0-9 - _ . ! ~ * ' ( )
encodeURIComponent('hello world&city=Seoul')
// → 'hello%20world%26city%3DSeoul'
// Correct: & and = are encoded so they can't break query structure

// Building a URL with user input — always use encodeURIComponent for values
const query = '서울 맛집';
const url = `https://api.example.com/search?q=${encodeURIComponent(query)}`;
// → 'https://api.example.com/search?q=%EC%84%9C%EC%9A%B8%20%EB%A7%9B%EC%A7%91'
FeatureencodeURI()encodeURIComponent()
Use caseEncoding a complete URLEncoding a query value or path segment
Encodes spacesYes → %20Yes → %20
Encodes &No (left as &)Yes → %26
Encodes =No (left as =)Yes → %3D
Encodes /No (left as /)Yes → %2F
Encodes ?No (left as ?)Yes → %3F
Encodes #No (left as #)Yes → %23
Encodes KoreanYesYes

Understanding URL Structure

Knowing which part of a URL you're working with tells you exactly how to encode it. A URL has six components, and each has different encoding requirements.

https://api.example.com:8080/v1/search?q=Seoul%20food&page=2#results
|____| |_______________|  |__||________|  |_________________| |_____|
scheme      host          port   path          query string    fragment
  • Scheme (https, http, ftp): Never encode. Fixed protocol identifiers.
  • Host (domain or IP): Rarely needs encoding. International domains use Punycode, not percent-encoding.
  • Port (the number after :): Never encode. Pure numeric.
  • Path (/v1/search): Encode individual path segments if they contain spaces or special characters. Don't encode the / separators.
  • Query string (?key=value&key2=value2): Always encode both keys and values using encodeURIComponent(). Never pass raw user input here.
  • Fragment (#results): Encode if it contains special characters, though fragments are client-side only and never sent to the server.

The Space Problem: %20 vs +

Here's a subtlety that causes confusion: there are two valid ways to encode a space, and they're not interchangeable. In URL paths and modern query strings, the correct encoding for a space is %20. This is what encodeURIComponent() produces, and it's what the URL specification requires. In HTML form data (the application/x-www-form-urlencoded format), spaces have traditionally been encoded as +. This format dates back to early HTML form submissions and is still used in many server-side frameworks when parsing POST bodies.

💡

Quick rule: always use %20 in code you write

When building URLs programmatically, stick with encodeURIComponent(). It always uses %20 for spaces, which is correct everywhere. The + encoding is a legacy artifact from HTML forms — you'll encounter it when reading other systems' output, but you shouldn't produce it yourself unless you're specifically building form-encoded data.

The Double-Encoding Trap

Double-encoding is when you encode a string that's already been encoded. The result: percent signs themselves get encoded, so %20 becomes %2520 (%25 is the encoding for %, followed by 20). Your server then decodes %2520 to %20, which is the literal string "%20" — not a space. The original data is corrupted.

// WRONG: double-encoding
const alreadyEncoded = 'hello%20world'; // received from somewhere already encoded
const broken = encodeURIComponent(alreadyEncoded);
// → 'hello%2520world' - %20 itself got encoded to %2520

// RIGHT: decode first if input might already be encoded, then re-encode
const decoded = decodeURIComponent(alreadyEncoded); // → 'hello world'
const correct = encodeURIComponent(decoded); // → 'hello%20world'

// Safe helper when you're not sure if input is already encoded
function safeEncode(input) {
  try {
    const decoded = decodeURIComponent(input);
    return encodeURIComponent(decoded);
  } catch {
    return encodeURIComponent(input);
  }
}
⚠️

The double-encoding pitfall

Double-encoding is especially common when you receive URL parameters from user input, a database, or an external API, and then construct a new URL from them. Always ask: is this value already encoded? If there's any chance it is, decode it first with decodeURIComponent() before re-encoding. Never stack encoding functions without checking the current state of the data.

Common URL Encoding Mistakes

  • Using encodeURI() for query values: It won't encode & or =, so user-supplied values containing those characters will silently corrupt your query string. Always use encodeURIComponent() for values.
  • Encoding the entire URL with encodeURIComponent(): This encodes ://, all slashes, question marks, and ampersands — turning a valid URL into a broken string. Only use it on individual values.
  • Skipping encoding entirely: Raw user input in URLs causes broken links at best, XSS and injection vulnerabilities at worst. Encoding is a security measure, not just a convenience.
  • Forgetting to encode path segments: If your path contains dynamic data (e.g., /users/홍길동/profile), encode the dynamic part — but not the slashes.
  • Inconsistent encoding: Encoding some parameters but not others leads to bugs that only appear with certain inputs. Encode all dynamic values, every time.

Frequently Asked Questions

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

%20 is the standard percent-encoding for a space, valid in all parts of a URL. The + symbol is a legacy encoding used only in HTML form data (application/x-www-form-urlencoded format). When building URLs in JavaScript, always use encodeURIComponent(), which produces %20. You'll encounter + when parsing form submissions, but don't produce it yourself unless specifically needed.

Do I need to encode all characters in a URL?

No. Unreserved characters (A-Z, a-z, 0-9, -, _, ., ~) never need encoding — they're always safe. Reserved characters like /, ?, #, &, and = only need encoding when used outside their structural role — specifically when they appear as literal values in query parameters or path segments. Everything else, including spaces and non-ASCII characters, must be encoded.

How does URL encoding work for Korean characters?

Korean (and all non-ASCII) characters are first converted to their UTF-8 byte sequences, then each byte is percent-encoded. For example, the character '한' is three bytes in UTF-8: 0xED, 0x95, 0x9C — so it becomes %ED%95%9C. That's why a short Korean word can become a long string of %XX groups. Your browser handles this automatically when you type in the address bar, but in code you need to call encodeURIComponent() explicitly.

Is URL encoding the same as HTML encoding?

No, they're different systems. URL encoding uses percent signs (%20, %26, %3D). HTML encoding uses named or numeric entities (&, <). URL encoding makes characters safe for transmission in URLs. HTML encoding makes characters safe for rendering in HTML documents. A character might need both — but applied separately in the right context.

Can skipping URL encoding cause security issues?

Yes. Failing to encode user input in URLs can enable open redirect attacks (where a crafted URL redirects users to a malicious site), reflected XSS (where script tags or data URIs get injected into page URLs and executed), and HTTP header injection if URL values end up in server response headers. Treat URL encoding as a security requirement, not just a formatting nicety.

What's the easiest way to build a URL with multiple query parameters?

Use the built-in URLSearchParams API in modern JavaScript. It handles encoding automatically and correctly: const params = new URLSearchParams({ q: '서울 맛집', page: '2' }); const url = 'https://api.example.com/search?' + params.toString();. This is much safer than string concatenation and handles all edge cases for you.

URL Encoder & Decoder

Paste any URL or text to encode it to percent-encoding format, or decode %XX sequences back to readable text

Encode or Decode a URL

Try the tools from this article

MJ

Minjae

Developer & tech writer. Deep dives into dev tools and file conversion technology.

Found this helpful? Get new guide alerts

No spam. Unsubscribe anytime. · By subscribing, you agree to our Privacy Policy.

You might also like

84+

Tools available

100+

Blog articles

English & 한국어

Languages

Bookmark this page! We add new free tools every week.