Base64, URL encoding, and HTML entities explained
Three encodings that are constantly confused, what each one is for, and the mistakes that cause broken data.
Base64, URL encoding, and HTML entities all turn readable text into something less readable, which is why they get mixed up. They solve different problems, and using the wrong one produces values that look plausible and behave incorrectly. This guide explains what each encoding is for, shows the same text in all three, and covers the mistakes behind most broken links, garbled attachments, and escaping bugs.
One text, three encodings
Take the text Fish & chips / 5€ = ok?:
Base64: RmlzaCAmIGNoaXBzIC8gNeKCrCA9IG9rPw==
URL (component): Fish%20%26%20chips%20%2F%205%E2%82%AC%20%3D%20ok%3F
HTML entities: Fish & chips / 5€ = ok?Each output is safe in a different place. Base64 is safe anywhere text is allowed. The URL-encoded form is safe as a query parameter value. The HTML-escaped form is safe inside a web page. None of them is secret. All three are fully reversible by anyone.
Base64: moving bytes through text channels
Base64 represents binary data using 64 printable characters (A–Z, a–z, 0–9, + and /), so it can travel through systems that only handle text: JSON, email, data URLs, and database columns. Every 3 bytes become 4 characters, so encoded data is about 33% larger, and = pads the end when the input length is not a multiple of three.
Text is first converted to bytes as UTF-8, which is why non-ASCII characters take more space: é is two bytes and € is three. The URL-safe variant replaces + and / with - and _ and usually drops the padding. That is the form used in JWTs and many web APIs. Decoding URL-safe Base64 with a standard decoder, or the other way round, is the most common cause of “invalid character” errors.
Use the Base64 encoder / decoder when you need to see what a token, header, or attachment actually contains. If the input is not valid Base64 or does not decode to valid UTF-8 text, the tool says so instead of returning quietly corrupted text.
URL encoding: values inside URLs
Characters such as ? & = / # give a URL its structure. When a value contains them, they must be percent-encoded, written as % followed by two hex digits for each UTF-8 byte, or they will be read as structure. A search for “fish & chips” sent as ?q=fish & chips is actually a parameter q=fish and a second, empty parameter named chips.
The URL encoder / decoder has three modes, because there are three different jobs:
- Component, like JavaScript’s
encodeURIComponent, is for a single value or path segment. It escapes everything with structural meaning. - Whole URL, like
encodeURI, makes a complete URL valid, for example one with spaces, while leaving?,&, and/alone. It cannot fix a value that contains those characters. - Form is the
application/x-www-form-urlencodedformat used by HTML forms, where spaces become+and a literal plus must be written as%2B.
The classic bug is double encoding: encoding a value that was already encoded turns %20 into %2520. If a decoded result still contains %xx sequences, it was encoded twice. For editing parameters rather than raw encoding, the query string editor handles encoding for you.
HTML entities: text that must not become markup
If user text is inserted into HTML without escaping, characters like < and & change the structure of the page. At best the layout breaks. At worst, an attacker injects a script, which is cross-site scripting (XSS). Entity encoding replaces those characters with references: <, >, &, ", and '. Named references like é and numeric ones like é or é all decode to the same character, é.
The HTML entity encoder / decoder displays decoded output as plain text, so pasted content cannot execute in your browser. That matters when you are inspecting hostile input. Modern frameworks such as React and Vue, and most template engines, escape text automatically. Manual escaping matters for hand-built HTML strings and email templates. Remember that HTML escaping only protects HTML text and attribute contexts. JavaScript strings, CSS, and URLs such as href="javascript:…" need their own handling.
Quick decisions
- Binary data that must survive a text channel: Base64.
- A value that will sit inside a URL: percent-encoding, as a component.
- Text that will sit inside HTML: entity encoding, or better, a templating system that escapes by default.
- Seeing the bytes behind any text: text to binary shows each UTF-8 byte in binary and hex.
- A JWT you want to read: the JWT decoder, keeping in mind that decoding proves nothing about authenticity.
And the rule that covers all three: encoding is not encryption. If something must stay secret, it needs real encryption or should not be in the URL, the page, or the token at all.
