Toolvore

HTML Entity Encode/Decode

Escape or unescape HTML entities in text.

This tool runs entirely in your browser. Your data is never uploaded, never stored, and never leaves your device.

Escape rewrites the five characters HTML treats as markup — & < > " and ' — as &amp;, &lt;, &gt;, &quot; and &#39;, which is what stops user-supplied text turning into tags. Unescape goes the other way through the browser's own HTML parser, so it understands the entire named and numeric entity set, not just those five.

How to use it

  1. 1Press Escape or Unescape; Escape is the mode the page opens in.
  2. 2Paste into the Input box — the result appears underneath as you type, with nothing to submit.
  3. 3Copy the output with the button above the result box.

Example

Input
<a href="/x?a=1&b=2">Ben & Jerry’s — café</a>
Output
&lt;a href=&quot;/x?a=1&amp;b=2&quot;&gt;Ben &amp; Jerry’s — café&lt;/a&gt;

Look at what did not change: the curly apostrophe, the em dash and the é come through as themselves. Escaping here is about stopping text being read as markup, not about making it ASCII-safe — if you arrived wanting &eacute; and &copy;, this will not produce them, and serving the page as UTF-8 removes the reason to want them. The two directions are deliberately unequal. Unescape borrows the browser's parser, so it resolves &eacute;, &nbsp; and numeric references like &#x1F600; that Escape would never emit, and it honours the legacy rule that a few entities work without their closing semicolon — which is why &notarealentity; decodes to ¬arealentity;. Decoding also peels one layer at a time: &amp;lt; becomes &lt;, and needs a second pass to become a bare <.

What happens to your data

This tool runs entirely in your browser. Your input is never uploaded to a server, never stored, and never logged. Escaping is five string replacements. Unescaping assigns your text to the innerHTML of a detached textarea element and reads the value back, which borrows the browser's entity table without shipping a copy of one. A textarea's contents are parsed as text rather than as elements, so a decoded <img src=x onerror=…> lands in the output box as characters and is never inserted into the page or run.

Last updated August 2026

A code sample pasted into a blog post shows a gap where the tags should be, because the browser read them as markup and drew them. A CSV export opens with &amp;#39; scattered through every surname carrying an apostrophe. A comment box on a site you maintain turns out to render whatever anyone types into it. Those are one problem seen from three sides: text and markup share a character set, and nothing in the characters says which is which.

Work out which direction you need before you paste anything. Escaping takes text on its way into an HTML document and neutralises the characters a parser would otherwise read as structure. Unescaping takes text that has already been through that — lifted from page source, a log line, an API response, a column somebody encoded on the way in — and returns the characters a person actually typed.

The bigger decision is whether hand-escaping is the right answer at all. Doing it once, by hand, suits a snippet going into a template, a documentation example, or a message that has to show markup rather than run it. It is the wrong answer for anything a user can type, where escaping belongs in your template engine, at output time, on every field.

The mistake that costs the most time is escaping the same text twice. Nothing in a second pass can tell that the ampersand in front of it was already part of an entity, so &amp; becomes &amp;amp; and the page shows the entity instead of the character.

How it works

Toolvore handles the two directions with two different mechanisms, which is why they are not mirror images of each other. Escaping is five ordered replacements over your text, and the order carries the trick: the ampersand goes first, so the entities written by the four passes after it are not themselves re-escaped — reverse those steps and a less-than sign comes out as &amp;lt;. Decoding instead hands the string to the browser's own HTML parser through a detached textarea, which is why it resolves references this side would never emit. Both run in a memoised calculation on every keystroke, so there is nothing to press and nothing to wait for, and switching direction re-runs the same input, so a round trip needs no retyping. What it cannot do is judge context: it has no idea whether the result is going into page text, an unquoted attribute, a URL or a script block, and those five characters are sufficient only for the first of those. It cannot tell escaped text from unescaped either, so a second pass re-encodes work already done.

Common use cases

  • Pasting a code sample into a blog post so the tags show instead of running
  • Recovering apostrophes and dashes from an export full of numeric references
  • Preparing a value to sit inside a hand-written HTML attribute
  • Reading a log line where the payload was stored HTML-encoded
  • Checking what a template engine actually produced when output looks wrong
  • Putting an example of markup into a support ticket or an email

Frequently asked questions

Why does my page show &amp;amp; instead of an ampersand?

Text has been escaped twice, and each pass encodes the ampersand at the front of whatever the previous one wrote. One layer gives you &amp; where an ampersand was; two gives &amp;amp;, which a browser resolves to the visible text &amp;. The same fault reads as &lt;p&gt; showing up as words mid-paragraph. Look for two things encoding the same value — a form handler escaping on the way into the database and a template engine escaping again on the way out. Decoding the stored column is a patch; the fix is to store what people typed and escape once, at output.

What is the difference between &#39; and &apos;?

They mean the same character. &apos; is defined in XML and in HTML5's named list, but it was absent from HTML 4.01, so older parsers leave it on the page as literal text. The numeric reference &#39; carries no such history and is resolved everywhere, which is why encoders reach for it. The apostrophe is on the list at all because a single quotation mark can delimit an attribute value, and an unescaped one inside a value quoted that way closes it early — the opening an injected attribute needs. In ordinary page text an apostrophe needs no encoding.

If my page is UTF-8, do I still need entities for accented characters?

For display, no. Serve the document as UTF-8, declare the character set early in the head, save the file in the same encoding, and an accented letter, a copyright sign or an em dash can sit in the source as itself. Named references for those survive from a time when the transport could not be trusted to carry the bytes. Where they still earn a place is with characters that look like nothing: a non-breaking space, a soft hyphen, a zero-width joiner. Written as an entity, the next person reading your source can see what is there; written raw, it is an invisible byte.

Why does my text show é and ’ instead of accents?

That is an encoding mismatch rather than an entity problem, and escaping will not touch it. The bytes were written as UTF-8 and read back as Windows-1252 or Latin-1, so one character became two. Once it has been saved in that state the wrong characters genuinely are the characters now, and decoding entities cannot recover them. Check, in order: the charset in the response header, the meta tag, the encoding your editor saved with, and the collation of the database column and connection. Fix the declaration first, or you will repair the stored text and watch it break again.

Is escaping those five characters enough to prevent XSS?

In element text and inside a quoted attribute, yes. In three other places, no. An unquoted attribute can be escaped from with a space, a tab, a newline or a backtick, none of which are on that list. Inside a script block the parser is JavaScript rather than HTML, so JavaScript escaping is what applies. A URL-valued attribute such as href passes javascript: through HTML escaping untouched, so the scheme has to be checked separately. Escaping is per context, which is why template engines encode by destination rather than applying one function everywhere.

What is &nbsp; and why does it keep appearing in my content?

It is U+00A0, a space that does not allow a line break and does not collapse into its neighbours the way an ordinary space does. Most of the ones people find were never typed: word processors and rich-text editors insert them when pasting. The trouble comes later. A run of text joined by them will not wrap, so it overflows its container on a narrow screen, and code that trims whitespace or splits on a space often fails to match it, because it is not the character the pattern expects. Decoded, it looks exactly like a space.

Are HTML entities the same as escaping for XML or JSON?

No, and mixing them up breaks feeds. XML predefines five references only — lt, gt, amp, quot and apos — so &nbsp; in an XML document is an undefined entity and a parser rejects the file rather than guessing. That is why HTML pasted into an RSS item or an XML API can fail on a character that was fine on the page. JSON has no entities at all: it escapes with backslashes, and a code point that needs it is written as a backslash-u sequence. An HTML entity inside a JSON string is ordinary text, still needing decoding after the parse.

Does anything I paste here get sent to a server?

No. The component runs in the browser with no network call of any kind in it: your text is held in the page's own state, the result is computed from it directly, and closing the tab is the whole of the cleanup. Nothing is written to storage, there is no account and no history, and no file is involved in either direction — you paste, and you copy. Nothing caps how much you paste, though a very large block is re-processed on every keystroke. This matters because encoded values are usually lifted from production logs and live database columns.