HTML Decoder

Turn HTML entities back into plain characters. Use it when a CMS export, a scraped page or an RSS feed arrives full of & and ’ where the punctuation should be.

Encoded HTML
Decoded Text

1 HTML Decoder example

Encoded

1
<p class="note">Café & croissant — €4.50</p>

Decoded

1
<p class="note">Café & croissant — €4.50</p>

2 What it handles

Named references

The full HTML5 set, so &eacute;, &hellip;, &nbsp; and the other 2,000-plus names all resolve.

Numeric references

Decimal like &#233; and hexadecimal like &#x1F600;, including emoji and other characters outside the Basic Multilingual Plane.

Missing semicolons

&amp without the semicolon is decoded the way a browser would. Fix it in the source anyway, since stricter parsers reject it.

Double encoding

Tick Decode twice to unwrap &amp;lt; in one pass. If that fixes your text, look for a template that escapes a value twice. That is the bug to fix.

3 It decodes, it does not render

Decoding &lt;script&gt; gives you the literal characters <script> as text. The result goes into a textarea and is never inserted into this page, so pasting hostile markup here is safe. Keep the same distinction in your own code: turning an entity back into a character does not make it safe to put in the DOM.

How to use the HTML Decoder tool

  1. Paste text containing entities into the left panel.
  2. The decoded version appears on the right immediately.
  3. Tick Decode twice when the text is double-encoded, for example when you see &amp;amp;lt;.
  4. Copy Result takes the plain text. The result is only ever shown as text, never inserted into this page.

How to decode HTML entities in JavaScript, PHP and Python

JavaScript

// In a browser, borrow the parser's own entity table
function decodeEntities(str) {
    const el = document.createElement("textarea");
    el.innerHTML = str;
    return el.value;
}

console.log(decodeEntities("Caf&eacute; &amp; croissant &mdash; &#8364;4.50"));
// Café & croissant — €4.50

// A textarea, not a div: a div would parse tags as markup.
// In Node.js there is no DOM, so use a library:
//   npm i he
//   require("he").decode(str);

Using innerHTML on a div and reading textContent works too, but it parses any tags in the input as elements. A textarea treats its content as text, which is what you want here.

PHP

<?php
$encoded = 'Caf&eacute; &amp; croissant &mdash; &#8364;4.50';

// Decodes every named and numeric entity
echo html_entity_decode($encoded, ENT_QUOTES | ENT_HTML5, 'UTF-8'), PHP_EOL;

// Only the five special ones, the inverse of htmlspecialchars
echo htmlspecialchars_decode('&lt;b&gt;bold&lt;/b&gt;', ENT_QUOTES), PHP_EOL;

// Double-encoded input needs two passes
$twice = html_entity_decode(html_entity_decode($encoded, ENT_QUOTES, 'UTF-8'), ENT_QUOTES, 'UTF-8');

Python

import html

encoded = "Caf&eacute; &amp; croissant &mdash; &#8364;4.50"

print(html.unescape(encoded))
# Café & croissant — €4.50

# html.unescape handles the full HTML5 named set plus numeric
# references, including ones missing their semicolon.

# Scraping? BeautifulSoup already decodes entities while parsing,
# so decoding again gives you double-decoded text.

Common errors and how to fix them

The text still shows &amp;amp;
The text was encoded twice upstream. Tick Decode twice to confirm, then fix the template that escaped a value that was already escaped, instead of adding a permanent second decode to the pipeline.
Decoding produced working HTML tags
Decoding turns &lt;b&gt; back into <b>, so this is expected. If the source is untrusted, sanitize the result before it goes anywhere near innerHTML, because decoding does not validate anything.
An entity was left as-is
The entity is either a typo (&ampp;) or a numeric reference outside the valid Unicode range. The decoder leaves both as they are instead of guessing.
&nbsp; became an invisible character that breaks string comparison
It decodes to U+00A0, a non-breaking space, which is not the same character as a regular space. Replace it explicitly if you are about to compare or split on whitespace.

Good to know

Entities show up in scraped pages, RSS and Atom feeds, CMS exports and any API that returns HTML fragments. Decode once at the boundary where the data arrives, store the plain text, then escape again when you output it. Stored escaped text is what produces the &amp;amp; that later turns up in a CSV export.

Specifications and references

This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.

Frequently Asked Questions

Which entities can it decode?

All of them: the full HTML5 named set, decimal references like &#233; and hex ones like &#x1F600;.

Does it strip the HTML tags?

No. It only converts entity references back to characters. &lt;b&gt; becomes the text <b>, not bold text.

Why is my text still full of &amp;amp;?

The text was encoded twice upstream, usually by a template that escapes a value the framework already escaped. Tick Decode twice here to confirm it, then fix the template rather than the data.

Can it handle an entity with no semicolon?

Yes, for the common ones. Browsers accept &amp without the semicolon and so does this decoder. Fix it at the source anyway, since stricter parsers such as XML reject it.

Is it safe to paste untrusted HTML here?

Yes. The result is shown as text in a textarea, never inserted into the page, so nothing in it can run.

Going the other way

The HTML encoder escapes text for safe output. If the text is percent-encoded rather than entity-encoded, you want the URL decoder; if it is Base64, the Base64 decoder.

More Encoders & Decoders

Browse all encoders & decoders

Copied to clipboard!