HTML entity encoder / decoder

Escape text so it is safe inside HTML, or decode named and numeric entities back to the characters they stand for.

Text
Encoded

Output will appear here

What this tool does

HTML has no way to tell the difference between a less-than sign you meant as text and one that opens a tag. The language solves this with entities: short escape sequences that stand for a character without being read as markup. This tool converts in both directions — plain text into its escaped form, and escaped HTML back into the characters it stands for.

Both directions run entirely in your browser. That matters more here than for most tools, because the text people paste into an entity decoder is usually a scraped page, a customer email or a database column someone is trying to make sense of.

The five characters that matter

Thousands of entities exist, but only a handful are needed to make text safe. Encoding here replaces exactly five characters and leaves everything else readable:

  • The ampersand becomes & — this one first, or every other replacement would itself be re-read as an entity.
  • The less-than sign becomes < — the character that can start a tag.
  • The greater-than sign becomes > — less dangerous on its own, escaped for symmetry and to survive careless parsers.
  • The double quote becomes " — needed inside attribute values written with double quotes.
  • The apostrophe becomes ' — needed inside attribute values written with single quotes.

That last one is written numerically on purpose. There is a name for it, ', but it comes from XML and HTML 4 never defined it, so old parsers pass it through as literal text and the escaping quietly fails. The numeric form has always worked everywhere, which is why serious escaping libraries emit it.

Named, decimal and hexadecimal

Any character can be written three ways, and decoding accepts all of them. The em dash is a good example:

named     —      the readable form, but only for characters that have a name
decimal   —      the code point in base 10
hex       —     the same code point in base 16, the notation Unicode charts use

This tool recognises the 255 names of the HTML 4 set when decoding — the Latin-1 letters, the Greek alphabet, the arrows, the mathematical symbols and the typographic punctuation, which between them cover essentially everything that turns up in real text. HTML 5 defines around 2200 more, almost all obscure mathematical symbols; carrying that table would add tens of kilobytes to every page load in exchange for names most documents never use. A name outside the set is reported rather than dropped, so the cost is a warning, never a wrong answer.

Encoding goes the other way and stays deliberately plain: names for the five characters above, decimal numbers for everything else. Nothing is turned into … or ’ when the character itself is perfectly valid in a UTF-8 document.

Escaping is not one rule but four

It is tempting to treat entity escaping as the answer to injection, and inside element content it genuinely is. But HTML is really four languages nested in each other, and each has its own rules. Entity escaping is correct in the first two of these places and useless in the rest:

  • Element content — text between tags. Entity escaping is exactly right.
  • Quoted attribute values. Entity escaping is right, provided the attribute really is quoted; without quotes a space in the value ends the attribute and the escaping buys you nothing.
  • Inside a script block. JavaScript string escaping applies, not entities — the browser does not decode entities there, so an escaped quote arrives as the literal characters ".
  • URL attributes such as href and src. Entity escaping does not stop a javascript: URL, because the danger is in the scheme, not in any character an entity would replace.

The practical rule: escape at the point where text is inserted into a document, using the rules of the exact context it lands in — not once, early, in the hope that it will hold everywhere later.

Why you sometimes see &

This is the single most common reason to reach for an entity decoder. Text was escaped, then escaped again — usually once by application code and once by a template engine or framework that already escapes its output:

original     Fish & Chips
escaped      Fish & Chips        renders as: Fish & Chips
escaped x2   Fish & Chips    renders as: Fish & Chips

Decoding removes exactly one layer, so running it once tells you which case you are in. If the output still contains entities, there was more than one layer. The fix is almost never to strip entities at display time — it is to find and remove the duplicate escaping step, because the same bug is silently corrupting stored data.

Non-ASCII, and the option for it

A page served as UTF-8 needs no entities for accented letters, Hebrew, Arabic, Chinese or emoji. Those characters are valid as they are, and leaving them readable keeps the source legible and the file smaller. That is the default here.

The option exists because some destinations still insist on plain ASCII: older email templates, systems that mangle bytes above 127, or a database column whose encoding nobody is willing to change. Turning it on writes every such character as a decimal reference — é becomes é, א becomes א.

Emoji are worth a note. An emoji is written as one reference for its whole code point, for example 🙂, never as two halves. If you have used the JSON escape tool this is the opposite of what happens there, where the format specifically requires an emoji to be split into two \u escapes. Same character, two correct answers, because the two formats define escaping over different units.

When a reference cannot be decoded

Decoding here never fails and never deletes anything. A reference that cannot be resolved is left exactly as it was found and listed above the output with its line and column. Three things get reported:

  • An unknown name, such as &nbps; — nearly always a typo for  . This is the warning worth acting on: it means a space is missing from your content and nobody noticed.
  • A number that is not a character, such as � or a value above the Unicode range. There is nothing to decode it to, so it stays as text.
  • A number between 128 and 159. See below.

A lone ampersand is not reported at all. In HTML, R&D and Q&A are ordinary text, and treating every stray ampersand as an error would bury the warnings that matter under noise from prose.

The 128-to-159 range is a genuine oddity. Those numbers name invisible control characters that nobody ever means to write; they appear because a document was authored in Windows-1252, where the same numbers are curly quotes, dashes and the euro sign. Browsers quietly read them as Windows-1252 for exactly that reason, and this tool matches that behaviour so the result equals what a page would actually display — but it says so in the warnings, because a silent substitution you did not ask for is worse than a noisy one.

Frequently asked questions

Is escaping these five characters enough to stop XSS?
In element content and quoted attribute values, yes — that is precisely what it is for. It is not enough inside a script or style block, in an unquoted attribute, or in a URL attribute such as href, each of which needs its own escaping rules. Escaping is a property of where text lands, not of the text.
Why is the apostrophe encoded as ' and not '?
Because ' is an XML entity that HTML 4 never defined. Parsers that predate HTML 5 leave it as literal text, so an apostrophe you thought was escaped is not. The numeric form works in every parser, which is why it is the safe default.
My page shows & instead of an ampersand. What happened?
The text was escaped twice. Decode it here: one pass turns & into &, confirming the extra layer. Fix the pipeline rather than the text — usually your code escapes output that the template engine was already escaping.
Do I need to encode Hebrew, Arabic or emoji?
Not for a modern page served as UTF-8; they are valid as they are. Turn on the non-ASCII option only when something downstream insists on plain ASCII, such as an old mail template. Each emoji is then written as a single numeric reference.
Why does the tool warn about “ when it decoded it fine?
Because 147 names an invisible control character, not the quotation mark you see. Documents that use it were written in Windows-1252, where 147 is a curly quote — browsers read it that way and so does this tool. The warning tells you a substitution happened, so you can fix the source encoding if it is yours to fix.
Is my text sent anywhere?
No. Encoding and decoding both run entirely in your browser; nothing you paste leaves your device.