Skip to content

Free HTML Entity Decoder — Unescape HTML

Decode HTML entities and unescape HTML online — free, no signup, 100% in your browser. Converts named, decimal & hex references back to characters; never uploaded.

No Tracking Runs in Browser Free

Your text is decoded locally in your browser and never uploaded, logged, or stored. It stays on this device.

0 characters
Decoded HTML / Text
0 characters
Reviewed for entity-decoding spec correctness (named / decimal / hex resolution), astral-plane and emoji reconstruction, lenient legacy-entity parsing, the XSS risk of rendering decoded untrusted text (and the re-escape guidance that mitigates it), no-network/no-storage privacy of the input, and accessibility (labelled controls, live-region announcements on decode and copy). — Go Tools Encoding Team · Jun 17, 2026

What Is HTML Entity Decoding?

HTML entity decoding — also called HTML unescaping — is the process of converting character references back into the characters they represent. Where encoding replaces a literal < with the entity < so a browser displays it as text, decoding does the reverse: it scans a string for references like <, &, <, >, or © and substitutes the actual character (<, &, <, >, ©) for each one. It is the operation you run when you have markup that was stored or transmitted in its escaped form and you need the real text back — to read it, edit it, hand it to another program, or work out why a page is rendering &lt; instead of <.

It is worth being precise about what this tool does. It decodes entities into characters; it does not reformat or validate the markup. If you want to take an escaped string and recover its literal characters, this is the right tool. To go the other direction and turn characters into entities, use the HTML Entity Encoder; and to indent and tidy a block of HTML, use the HTML Formatter. Encoding and decoding are exact inverses, so a string sent through the encoder and back through the decoder returns unchanged.

There are three kinds of reference the decoder must understand, and it handles all of them. A named reference uses a defined label (< for <, © for ©, — for —); a decimal numeric reference writes the Unicode code point in base 10 (< for <); and a hexadecimal numeric reference writes the same code point in base 16 (< for <), matching the U+XXXX notation of the Unicode standard. A robust decoder accepts any of them, in any mix, because different encoders emit different forms. The table below shows the references you will meet most often and the character each one decodes to:

| Entity (named) | Decimal | Hex | Decodes to | |----------------|---------|-----|------------| | &lt; | &#60; | &#x3C; | < | | &gt; | &#62; | &#x3E; | > | | &amp; | &#38; | &#x26; | & | | &quot; | &#34; | &#x22; | " | | &#x27; | &#39; | &#x27; | ' | | &nbsp; | &#160; | &#xA0; | (no-break space) | | &copy; | &#169; | &#xA9; | © | | &reg; | &#174; | &#xAE; | ® | | &trade; | &#8482; | &#x2122; | ™ | | &euro; | &#8364; | &#x20AC; | € | | &pound; | &#163; | &#xA3; | £ | | &mdash; | &#8212; | &#x2014; | — | | &ndash; | &#8211; | &#x2013; | – | | &hellip; | &#8230; | &#x2026; | … | | &#x1F600; | &#128512; | &#x1F600; | 😀 |

Two behaviors set a thorough decoder apart. First, it reconstructs astral-plane characters — anything above U+FFFF, including most emoji — from their numeric references rather than producing a broken half-character; 😀 correctly becomes 😀. Second, it follows the browser's lenient parsing for the small set of legacy named entities that historically appeared without a trailing semicolon, so &copy 2026 still decodes to © 2026 even though strict XML would reject it. This tool does both, matching the behavior of the widely used he library so its output agrees with what a real browser would render.

A word of caution that belongs with every decoder: decoded text is unescaped by definition. Decoding is the inverse of the escaping that protects pages from cross-site scripting, so a decoded string containing a <script> tag or an event handler is once again live, dangerous markup. Never decode untrusted input and then insert it into a page with innerHTML — that reopens the exact hole encoding was meant to close. Decode when you need the raw characters for reading, editing, or storage; if the result will be rendered back into HTML, re-escape it in its destination context first. And because every byte is processed in your browser, the escaped strings you decode — even a private record or an unpublished draft — never cross the network. For neighbouring conversions, the URL Encoder / Decoder handles percent-encoding and Base64 Encode / Decode handles binary-safe transport.

// Decoding is the inverse of escaping. The classic round-trip:
//   &lt;  →  <     &gt;  →  >     &amp;  →  &     &quot;  →  "     &#x27;  →  '

// Browser — the safest decoder is the platform itself. Use textarea, NOT innerHTML on a live node,
// so the decoded markup is never executed.
function decodeHtml(str) {
  const ta = document.createElement('textarea');
  ta.innerHTML = str;        // the parser resolves entities into text
  return ta.value;           // .value is plain text — no script runs
}

decodeHtml('&lt;div&gt; &amp; &copy;');   // → '<div> & ©'
decodeHtml('&#60;&#x3E;');                // → '<>'
decodeHtml('&#x1F600;');                 // → '😀'
decodeHtml('&copy 2026');                // → '© 2026'  (lenient, no semicolon)

// ---------------------------------------------------------------
// SECURITY: decoded text is unescaped. Never do this with untrusted input:
//   el.innerHTML = decodeHtml(userInput);   // ❌ reopens the XSS hole
// If the decoded value must be displayed, re-escape it in its destination context first,
// or assign it as text:
//   el.textContent = decodeHtml(userInput); // ✅ shown as literal text

// ---------------------------------------------------------------
// Node.js (no DOM) — use a tested library such as he:
//   import { decode } from 'he';
//   decode('&lt;div&gt; &amp; &copy;');     // → '<div> & ©'

Key Features

Decodes Named, Decimal, and Hex References

Resolves the full HTML5 named-entity set (<, ©, —), decimal numeric references (<), and hexadecimal references (<) in any combination, exactly as a browser would — so it reverses whatever an encoder produced.

Handles Emoji and Astral-Plane Characters

Numeric references above U+FFFF are reconstructed into their full code point, so 😀 decodes to 😀 rather than a broken surrogate. Rare CJK ideographs and mathematical symbols decode faithfully too.

Lenient Legacy-Entity Parsing

Follows the browser's backward-compatible rules for named entities missing a trailing semicolon, so legacy or sloppy markup like &copy 2026 still decodes to © 2026 where a strict parser would leave it broken.

Live, Instant Decoding

Output updates as you type — no submit button, no round-trip latency. Paste a large escaped block and the recovered text appears immediately, ready to copy.

Entity Quick-Reference Built In

A reference table mapping the most common entities — the reserved five plus ©, ®, ™, €, —,   and more — to their characters sits right on the page, so you never have to look an entity up elsewhere.

One-Click Swap to the Encoder

Swap direction jumps straight to the HTML Entity Encoder to reverse the operation. Encode and decode are exact inverses, so you can round-trip text without loss.

100% Private, Browser-Only

All decoding happens on your device with JavaScript — no network requests, no logging, no storage, verifiable in DevTools → Network. Private database fragments, email content, and unpublished drafts never leave the tab.

Available in 15 Languages

The full interface — labels, instructions, and guidance — is localized into 15 languages, so the tool and its security advice are clear no matter where your team works.

Worked Examples

Decode a mix of named entities

&lt;div&gt; &amp; &copy;
<div> & ©

The decoder resolves each named reference to the character it represents: < becomes <, > becomes >, & becomes &, and © becomes the copyright sign ©. This is the everyday case — taking a string that was stored or transmitted in its escaped form and turning it back into the real characters so you can read, edit, or re-process the markup. Decoding is the exact inverse of encoding, so a string round-tripped through the encoder and back arrives unchanged.

Decode decimal and hexadecimal numeric references

&#60;&#x3E;
<>

Numeric character references work in both bases: < is the decimal form of code point 60, which is <, and > is the hexadecimal form of code point 62, which is >. The decoder handles decimal (&#NNN;) and hex (&#xHHH;) references interchangeably, resolving each to its Unicode character. This matters because encoders disagree on which form to emit — some prefer decimal, some hex — and a robust decoder must accept either.

Decode a legacy entity that is missing its semicolon

&copy 2026
© 2026

Older HTML allowed a small set of named entities to appear without a trailing semicolon, and browsers still resolve them for backward compatibility — &copy 2026 renders as © 2026. This decoder follows the same lenient parsing rules, so it recovers the intended character from sloppy or legacy markup that a strict parser would leave untouched. If you are debugging text that shows a stray &copy, this is why.

Decode an emoji from its hex reference

&#x1F600;
😀

Numeric references are not limited to the Basic Multilingual Plane — 😀 is the hexadecimal reference for code point U+1F600, the grinning-face emoji 😀. The decoder correctly reconstructs astral-plane characters (anything above U+FFFF) from their numeric references, so emoji, rare CJK ideographs, and mathematical symbols all decode faithfully rather than turning into a broken surrogate or a replacement glyph.

Decode an escaped attribute string

&lt;a href=&quot;x&quot;&gt;Tom &amp; Jerry&#x27;s&lt;/a&gt;
<a href="x">Tom & Jerry's</a>

This is a full round-trip of the encoder's flagship example. " resolves to a double quote, ' (the compatibility-safe numeric apostrophe) resolves to ', and the angle-bracket and ampersand entities resolve to their literal characters, reconstructing the original Tom & Jerry's exactly. Because the decoder accepts named, decimal, and hex references in any combination, it reverses whatever an encoder produced, regardless of which entity style was used.

How to Use the HTML Entity Decoder

  1. 1

    Paste the escaped string

    Drop the text full of HTML entities into the input box. The decoded characters update live as you type — there is no submit button and nothing is sent anywhere.

  2. 2

    Read the decoded result

    Named, decimal, and hexadecimal references all resolve automatically to the characters they represent, including emoji and other astral-plane code points. No format selection is needed — the decoder detects each reference's type.

  3. 3

    Copy the decoded text

    Click Copy to put the recovered characters on your clipboard, ready to paste into an editor, a database, or another tool. Clear resets both panes for the next string.

  4. 4

    Re-escape before re-displaying untrusted text

    If the decoded output will be rendered back into a web page and any of it came from an untrusted source, escape it again first with the encoder to avoid reopening an XSS hole.

  5. 5

    Need to encode instead? Swap direction

    Use Swap direction to switch to the HTML Entity Encoder when you want to turn raw characters into entities.

Common HTML Decoding Mistakes

Rendered decoded untrusted input with innerHTML

Decoding unescapes the text, so a decoded <script> tag is live markup again. Inserting it via innerHTML executes it — a textbook XSS hole. Re-escape decoded untrusted text, or use textContent.

✗ Wrong
el.innerHTML = decode(userInput)  →  script runs (XSS)
✓ Correct
el.textContent = decode(userInput)  →  shown as text

Decoded only once when the text was double-encoded

Double-encoded text needs two decode passes. Decoding &lt; once yields <, not <. Decode again — and fix the pipeline so it never double-encodes in the first place.

✗ Wrong
&amp;lt;  decoded once  →  &lt;  (still an entity)
✓ Correct
&amp;lt;  decoded twice  →  <

Confused HTML decoding with URL or Base64 decoding

Entities, percent-encoding, and base64 are different schemes. An HTML decoder will not turn %20 into a space or decode a base64 blob. Use the matching tool for each encoding layer.

✗ Wrong
HTML-decode "%3Cdiv%3E"  →  unchanged, still percent-encoded
✓ Correct
URL-decode "%3Cdiv%3E"  →  <div>

Used a regex that misses numeric or astral references

A hand-written regex for named entities silently skips <, >, and emoji like 😀, leaving them in the output. Use the browser parser or a tested library that covers all reference forms.

✗ Wrong
regex for &name; only  →  &#x1F600; left undecoded
✓ Correct
full decoder  →  &#x1F600; becomes 😀

Output displayed as mojibake after decoding

Decoding é gives the real é, but if the receiving page or file is not served as UTF-8 the character corrupts into garbage. Set the charset to UTF-8 before writing decoded text out.

✗ Wrong
decoded é into a Latin-1 file  →  é mojibake
✓ Correct
decoded é into a UTF-8 file  →  é

Assumed strict parsing and missed legacy entities

A strict XML parser ignores semicolon-less entities like &copy, leaving them literal. Browsers resolve them, so a faithful decoder must too — otherwise your output disagrees with what users see.

✗ Wrong
strict parse of "&copy 2026"  →  &copy 2026 literal
✓ Correct
lenient parse of "&copy 2026"  →  © 2026

Who Uses This Tool

Read Markup Stored in Escaped Form
Pulled an HTML fragment out of a database, a log, or a JSON field where it was saved as <div>…? Decode it to see and edit the real markup instead of squinting at a wall of entities.
Debug Double-Encoded Text
Seeing &lt; on a live page where < should be? Paste it here to confirm it is double-encoded, decode it twice to recover the original, and trace the duplicate escaping back to its source in your pipeline.
Extract Plain Text from HTML Snippets
Need the human-readable text out of an escaped email body or CMS field? Decode the entities to recover the actual characters before you index, search, or display the content elsewhere.
Recover Characters from Scraped or Exported Data
Exports and scrapers often deliver content with entities intact. Decode &, é, and friends back to their characters so the data is clean before it enters your own systems.
Verify an Encoder's Output Round-Trips
After escaping a string with the encoder, decode it here to confirm you get the original back unchanged. A clean round-trip proves your escaping is correct and reversible.
Resolve a Mystery Entity
Stuck on what ™ or … actually is? Paste it in and read the decoded character, or consult the built-in quick-reference table — no need to memorise the entity tables.
Decode Legacy Markup Safely
Working with old HTML that uses semicolon-less entities like &copy or &nbsp inconsistently? The lenient decoder recovers the intended characters the way a real browser would, so your cleanup matches what users actually see.

How the Decoder Works

Resolves All Three Reference Forms
The decoder matches named references against the full HTML5 named-character table, parses decimal references (&#NNN;) as base-10 code points, and parses hexadecimal references (&#xHHH;) as base-16 code points. Each resolves to its Unicode character; the three forms are interchangeable on input.
Astral-Plane Reconstruction
Numeric references whose code point exceeds U+FFFF — most emoji and many symbols — are converted to the correct surrogate pair so the character renders as a single glyph. 😀 becomes 😀, not two broken half-characters.
Lenient Legacy-Entity Handling
A defined subset of named entities historically appeared without a trailing semicolon, and browsers still resolve them. The decoder mirrors this behavior — &copy 2026 yields © 2026 — matching the rendering of a real browser rather than a strict XML parser.
Idempotent on Plain Text
Characters that are not part of a recognized reference, including raw non-ASCII text already present in the input, pass through untouched. Decoding a string with no entities returns it unchanged, so the operation is safe to run on mixed content.
Decoded Output Is Unescaped
Decoding is the inverse of XSS-protective escaping, so the result is live markup again. The tool surfaces this so you do not insert decoded untrusted text into a page with innerHTML — re-escape it in its destination context before rendering.
Browser-Local, Zero Network
Decoding runs synchronously in JavaScript on the main thread; there is no API call, no server round-trip, and no persistence. The input never leaves the page, which you can confirm by watching an empty Network panel while you type.

HTML Unescaping Best Practices

Never Render Decoded Untrusted Text Directly
Decoded output is unescaped markup. If any of it came from a user or an external source, re-escape it before inserting it into a page, or assign it via textContent rather than innerHTML. Skipping this reopens the cross-site-scripting hole escaping was meant to close.
Decode in Reverse Order of Encoding
A value may be HTML-encoded, then URL-encoded, then Base64-encoded. Undo the layers in the opposite order they were applied — and use the matching tool for each: this one for entities, the URL decoder for percent-encoding, the Base64 tool for base64.
Decode Once, Not Reflexively
If a single decode leaves visible entities like <, the input was double-encoded — decode again to recover the original, then fix the upstream pipeline so text is escaped exactly once. Do not blindly loop; understand why the extra layer exists.
Serve the Result as UTF-8
Decoding numeric references produces real Unicode characters — accents, symbols, emoji. Make sure the page, file, or field that receives the decoded text is UTF-8, or those recovered characters will display as mojibake.
Prefer a Tested Library in Application Code
For one-off conversions this tool is ideal; in production, decode with a well-tested library (he in Node, the browser's own parser via a detached textarea) rather than a hand-rolled regex, which routinely misses numeric references, astral characters, and legacy entities.

Frequently Asked Questions

Is my text sent to your server when I decode it?
No. Every entity is resolved entirely in your browser with JavaScript — open DevTools → Network and you will see zero requests fire when you type or paste. Nothing is uploaded, nothing is logged, nothing is written to disk. That privacy matters because the escaped strings people decode are often sensitive: a fragment pulled from a private database, an internal email, a customer record, or markup copied out of an application you do not want leaking. On a server-side decoder every one of those would travel across the network to a machine you do not control; here the text never leaves the tab. This is the whole reason to decode HTML client-side rather than paste it into a website that could, in principle, keep a copy of everything it processes.
What does it mean to decode or unescape HTML?
Decoding HTML — also called unescaping — is the reverse of HTML escaping: it takes character references like <, &, <, or © and converts each back into the real character it stands for (<, &, <, ©). You reach for it whenever you have a string that was stored or transmitted in its escaped form and you need the literal text back — to read it, edit it, feed it to another program, or debug why a page is showing &lt; on screen instead of <. If you want to go the other way and turn characters into entities, use the companion HTML Entity Encoder; the two are exact inverses.
Which kinds of entities can this decoder handle?
All three forms, in any mix. It resolves named references (<, &, ©, — and the full HTML5 named-entity set), decimal numeric references (<, é), and hexadecimal numeric references (<, é). It also reconstructs astral-plane characters above U+FFFF from their numeric references, so an emoji like 😀 decodes correctly to 😀. And it follows the browser's lenient parsing for a handful of legacy named entities that omit the trailing semicolon — &copy 2026 still decodes to © 2026 — which strict parsers would skip. In short, whatever an encoder produced, this decoder reverses it.
Why does my text show &lt; instead of
That is the classic symptom of double-encoding. Somewhere in your pipeline the text was escaped twice: the first pass turned < into <, and the second pass turned the & in < into &, giving &lt;. When the browser decodes that once, it shows < as literal text rather than <. To recover the original, decode it twice — paste the string here to get <, then paste that result back in to get <. The real fix is upstream: escape exactly once, at output time, so the text is never double-encoded in the first place.
Will the decoded output be safe to put back into a page?
Be careful here. Decoding is the opposite of escaping, so decoded text is by definition unescaped — if it contains a <script> tag or an onerror handler, that markup is now live again. Never take untrusted input, decode it, and insert the result into your page with innerHTML, or you reintroduce exactly the cross-site-scripting (XSS) hole that escaping was meant to close. Decoding is the right move when you need the raw characters for reading, editing, or storage; but anything you render back into HTML must be re-escaped in its destination context. If you are about to display the decoded result, run it through the HTML Entity Encoder again first.
Does decoding handle non-ASCII characters and emoji correctly?
Yes. Numeric references can encode any Unicode code point, and the decoder resolves them all — accented letters (é → é), symbols (€ → €), em dashes (— → —), and full-plane emoji (😀 → 😀). For astral characters above U+FFFF it reconstructs the complete code point rather than producing a broken half-character. Raw non-ASCII characters that are already in the input pass through untouched, so a string that mixes real UTF-8 with entities decodes cleanly without corrupting either part. Make sure the page or file you paste the result into is served as UTF-8 so the recovered characters display correctly.
How do I encode text back into entities?
Use the companion HTML Entity Encoder. It takes raw characters like <div> & © and escapes them to <div> & ©, with options for named, decimal, or hex output and an "encode all non-ASCII" mode for legacy charsets. Encoding and decoding are exact inverses for the reserved characters, so you can round-trip text through both tools without loss. You can jump straight there with the Swap direction button on this page.
Is this the same as URL decoding or Base64 decoding?
No — they are three different encodings for three different jobs, and mixing them up is a common source of bugs. HTML entity decoding turns < back into <. URL (percent) decoding turns %20 back into a space and is for query strings and paths — use the URL Encoder / Decoder for that. Base64 decoding turns a base64 string back into the original bytes and is for binary-safe transport — use Base64 Encode / Decode. A value can be wrapped in more than one of these, so decode them in the reverse order they were applied. This tool handles HTML entities only.

Related Tools

View all tools →