DevLab
Encoding

URL Encoding Explained: What %20 Actually Means

Understand percent-encoding, why spaces become %20, when to use encodeURI vs encodeURIComponent, and how to decode URLs correctly.

Why URLs Need Encoding

URLs can only contain a limited set of ASCII characters. Spaces, punctuation, non-ASCII characters, and reserved URL characters must be percent-encoded. Percent-encoding replaces unsafe characters with a percent sign followed by two hex digits representing the UTF-8 byte value.

  • Space → %20
  • Ampersand (&) → %26
  • Equal sign (=) → %3D
  • é → %C3%A9 (two bytes in UTF-8)

encodeURI vs encodeURIComponent

encodeURI('https://example.com/path?q=hello world')
// Preserves URL structure chars: : / ? & = # @
// → 'https://example.com/path?q=hello%20world'

encodeURIComponent('hello world&lang=fr')
// Encodes EVERYTHING — safe for individual values only
// → 'hello%20world%26lang%3Dfr'

Rule: use encodeURIComponent() for individual query parameter values. Use encodeURI() only when encoding a complete URL you want to preserve as-is.

Form Encoding vs URL Encoding

HTML forms use application/x-www-form-urlencoded, where spaces are encoded as + instead of %20. This is why search engines historically used q=hello+world — form encoding, not standard percent-encoding.

Decoding Safely

decodeURIComponent('hello%20world%26lang%3Dfr')
// → 'hello world&lang=fr'

function safeDecodeURI(str) {
  try { return decodeURIComponent(str); }
  catch { return str; }
}

Common Mistakes

  • Double-encoding: Encoding an already-encoded value converts %20 to %2520 — always decode before re-encoding
  • Using encodeURIComponent on a full URL — this encodes slashes and colons, breaking the URL structure
  • Not encoding user input before inserting into URLs — can lead to open redirect vulnerabilities

Practice with these tools

More Learning Topics

RegexRegex Basics: A Complete Beginner's GuideRegexRegex Special Characters: Complete ReferenceRegexRegex Groups and Captures ExplainedRegexRegex Quantifiers: Complete GuideCSSCSS Selectors: The Complete GuideCSSCSS Specificity: Why Your Styles Aren't ApplyingJSONJSONPath Syntax: Query JSON Like XPathTimeUnix Timestamps ExplainedEncodingBase64 Encoding ExplainedEncodingJWT Structure and How It WorksEncodingJWT vs Session Tokens: Which Should You Use?EncodingJWT Refresh Tokens ExplainedCryptoHash Functions Explained: MD5, SHA-256, and When to Use EachJSONJSON Schema Explained: Validate Your JSON DataJSONJSON vs YAML: Which Should You Use?JSONJSON.stringify and JSON.parse: Edge Cases You Should KnowRegexRegex Lookahead and Lookbehind: Match Without ConsumingRegexRegex for Email Validation: The Right ApproachCSSThe CSS Box Model: margin, padding, border, and contentCSSFlexbox vs CSS Grid: When to Use EachCSSCSS Custom Properties (Variables) ExplainedTimeISO 8601 Explained: The Right Way to Format DatesTimeUnix Timestamps vs ISO 8601: Which to Use in Your API?EncodingUTF-8 Explained: How Computers Store TextTextCORS Explained: Why Your API Call is BlockedTextHTTP Status Codes: A Practical Developer GuideRegexNamed Capture Groups in Regex: Clean ExtractionsColorsColor Spaces Explained: RGB, HSL, HEX, and BeyondColorsColor Contrast for Developers: WCAG Rules and How to CheckNumbersNumber Bases Explained: Binary, Octal, Decimal, and HexNumbersBitwise Operations for Web DevelopersHTMLHTML Semantic Elements: A Complete ReferenceTextText Encoding for Developers: ASCII, UTF-8, and UnicodeRegexWhat is Regex? Complete Guide for DevelopersJSONJSON Format Explained: Structure, Syntax, and Common ErrorsEncodingHow JWT Works: Header, Payload, Signature DecodedHTMLHow to Convert Any Website to Markdown (for LLMs, RAG & Docs)TextPreparing Website Content for RAG: Clean Markdown Pipelines