UTF-8 maps characters to bytes, Base64 maps bytes to restricted text, and URL percent-encoding protects data inside URI components. They are different layers, not interchangeable styles.
Broken APIs often apply a correct algorithm at the wrong layer: calling btoa on Unicode, encoding an entire URL as one component, or treating reversible representation as encryption.
A layer model
A JavaScript string represents Unicode text. TextEncoder produces UTF-8 bytes. Base64 can represent those bytes as ASCII. If that value enters a query parameter, it may then need percent-encoding.
Order matters. The text 你好 must become UTF-8 bytes before Base64; standard Base64 plus, slash, and equals characters may need escaping in a URL.
Unicode text -> UTF-8 bytes -> Base64 text -> URL componentWhat each mechanism does
UTF-8 enables interoperable text storage. Base64 carries arbitrary bytes through text-only channels. Percent-encoding protects URI syntax. Unicode escapes are source notation; HTML entities belong to HTML parsing contexts.
None provides confidentiality. They solve representation and syntax problems.
| Mechanism | Input | Output | Purpose |
|---|---|---|---|
| UTF-8 | Unicode text | Bytes | Text interchange |
| Base64 | Bytes | ASCII text | Binary in text |
| Percent encoding | URL component | %HH | URI safety |
| Unicode escape | Code point/unit | \uXXXX | Source notation |
| HTML entity | HTML character | &name; | HTML context |
Base64 is not a charset
Base64 only sees bytes. Encode text with TextEncoder first and decode bytes with TextDecoder after Base64 decoding.
btoa assumes byte-like Latin-1 input and can fail on non-ASCII. Byte-first code avoids this legacy trap.
URL context matters
encodeURIComponent is for one path or query component; encodeURI preserves complete URL separators. Encoding a complete URL with encodeURIComponent breaks its structure.
In form-encoded queries, plus can represent space. URLSearchParams applies the correct serialization rules and avoids manual substitutions.
Base64URL is still not encryption
Base64URL replaces plus and slash with URL-friendly characters and often omits padding. JWT uses Base64URL segments.
Anyone can normally decode JWT header and payload; signature verification is separate.
Selection rules
Choose according to the receiving interface, not appearance. Send binary when supported, Base64 only to text-only fields, percent-encode URL components, and use UTF-8 for text boundaries.
- Text to bytes: UTF-8.
- Bytes to text field: Base64.
- Query value: URLSearchParams.
- JWT segment: Base64URL plus signature verification.
- HTML: escape for HTML context.
Key takeaways
Choose by layer: UTF-8 defines bytes for text, Base64 turns bytes into restricted text, and percent-encoding protects a URI component. This prevents corrupted Unicode, broken links, and false security assumptions.