HTML Entity Encoder and Decoder
Encode text to safe HTML entities or decode them back, instantly — a free tool for developers.
Your text stays on your device
Nothing to delete afterwards
Safe for real user data
Works in every modern browser
How it works
- 1
Paste your text
A string with angle brackets, an ampersand, quotes or accented characters that has to sit inside markup.
- 2
Choose the context
Text content, attribute value, or full encoding — each escapes a different set of characters.
- 3
Copy the result
Paste it into a template, an XML document, a feed or an email body.
Why use this tool
Context is a choice, not a guess
Escaping for text content, for an attribute value and for a URL are different jobs, and you pick which one.
Double encoding is caught
An input that already contains entities is flagged, so you do not turn an ampersand into an ampersand entity twice.
Named or numeric output
Numeric references work in XML, feeds and SVG, where most named entities are simply undefined.
Decoding is round-trip safe
Both named and numeric forms are recognised, including the hexadecimal spelling and the entities without a semicolon.
Honest about what escaping does
It makes text safe to place in a context, which is a smaller claim than making untrusted HTML safe.
Nothing leaves the browser
Text is converted on this page, so the ticket contents and customer names you are testing with stay yours.
There is no single “escape for HTML” — the context decides
This is the idea that makes the rest of the subject make sense. A browser parses a document in several different states, and the characters that can end the current state are different in each one. Inside text content, only `<` and `&` can start something new, so those are the two that must be escaped. Inside a double-quoted attribute value, `<` is harmless and `"` is fatal, because the quote ends the attribute. Inside an unquoted attribute value, a space ends it, and so do a tab, a newline, a backtick, an equals sign and a greater-than sign. Inside a `<script>` block, HTML escaping does nothing useful at all and JavaScript string escaping is what you need. This is why a single `escape()` helper applied everywhere produces both broken output and real vulnerabilities: it over-escapes where the characters were safe, and under-escapes where they were not. Choosing a context before you encode is not a nicety — it is the whole decision.
Only a handful of characters ever have to change
It is worth knowing exactly how short the list is, because most over-escaping comes from not knowing. The characters with syntactic meaning in HTML are `<`, `>`, `&`, `"` and the apostrophe. Of those, `&` always needs escaping because it starts an entity, and `<` always needs escaping because it starts a tag. `>` is a courtesy rather than a requirement in text content — a browser renders a bare `>` fine — though escaping it is habit in most codebases because it costs nothing and helps when markup is later processed by something stricter. The two quotes matter only inside attribute values, and only the one you used as the delimiter. Everything else, including every accented letter, every Arabic or Chinese character, every emoji, needs no escaping at all in a UTF-8 document: the encoding already handles them. Turning `café` into `café` is legal and almost always pointless, and it makes your file larger and harder to search.
Double encoding is the bug this tool exists to prevent
Escaping is not idempotent, and forgetting that produces one of the most recognisable defects on the web. Encode `&` once and you get `&`. Encode the result again and you get `&amp;`, which renders on the page as the literal text `&`. You have seen it: page titles reading “Tom & Jerry”, email subject lines with `'` in the middle of a word, product names with `"` around them in search results. It happens because escaping was applied at two layers that did not know about each other — a template engine that auto-escapes, plus a controller that escaped defensively before handing the string over. The fix is never to escape twice, and the way to be sure is to escape exactly once, at the last possible moment, at the point where the string enters the markup. Anything stored escaped in a database will eventually be escaped again by whatever renders it.
Named entities are an HTML feature, not a text feature
HTML5 defines more than two thousand named entities, from the familiar ` ` and `©` to things like `⨂`. XML defines exactly five: `<`, `>`, `&`, `"` and `'`. That gap causes a specific and common failure. Put ` ` into an RSS feed, an SVG file, an XHTML document, an Android layout or a SOAP payload and you get a parse error, because the parser has never heard of it and an undefined entity is fatal in XML rather than merely ignored. The numeric form ` ` works everywhere, since it needs no definition. There is a matching trap in the other direction: `'` is one of XML’s five but was not in HTML4, so old HTML documents and some email clients render it as literal text. If a string might travel between formats — and most strings in a modern stack do — numeric references are the safe spelling.
Escaping is not sanitisation, and the difference matters
These two get conflated constantly, and the conflation is where injection bugs live. Escaping takes text and makes it safe to place into a particular context, so that it is displayed rather than interpreted. Sanitisation takes markup that is meant to remain markup and removes the dangerous parts of it. Escaping a comment before printing it is correct; escaping a rich-text field the user is allowed to format destroys the formatting, and the usual response — allowing the HTML through unescaped — is what actually opens the hole. The sharpest example of the difference is a URL: entity-encode a link and `javascript:alert(1)` survives completely intact, because entity decoding happens before the URL scheme is checked, so `javascript:` becomes `javascript:` and runs. No amount of HTML escaping protects an `href`; only validating the scheme does. Escaping solves exactly one problem, and knowing which one is the point.
Why converting locally matters for this particular job
The strings people bring to an entity encoder are unusually sensitive, because of what the job is. You escape text when it came from somewhere you do not control: a support ticket, a customer name, a form submission, a comment, an imported product feed, an error message containing part of a request. Testing an encoder means pasting a real example of exactly that — the message that broke, with the customer’s apostrophe and the customer’s name still in it. Pasting it into a hosted encoder means uploading the untrusted user data you were trying to handle carefully, to a third party, for a transformation your browser can do in a single pass. This page converts the text in JavaScript and issues no request while it does; the same developer tools you would use to debug the escaping will confirm it.
Common mistakes to avoid
- Using one escape function everywhere. Text content, attribute values and script blocks end on different characters, so a single helper over-escapes in one place and under-escapes in another.
- Escaping the same string twice. Escaping is not idempotent — `&` becomes `&` and then `&amp;`, which is why page titles end up reading “Tom & Jerry”.
- Putting named entities into XML. Only five are defined there, so ` ` is a fatal parse error in a feed, an SVG or an XHTML document; ` ` works everywhere.
- Escaping accented or non-Latin characters. In a UTF-8 document they need no escaping at all — converting `café` to `café` only makes the file bigger and harder to search.
- Trusting entity encoding to make a URL safe. Entities are decoded before the scheme is checked, so `javascript:` becomes `javascript:` and runs; only validating the scheme helps.
How it compares
| Aspect | This tool | Online encoders | A language library |
|---|---|---|---|
| Text sent to a server | Never | Usually yes | No |
| Lets you pick the context | Yes | Rarely | Usually |
| Warns about double encoding | Yes | No | No |
| Numeric output for XML | Yes | Sometimes | Configurable |
| Decodes the full HTML5 named set | Yes | Partially | Usually |
| Price | Free | Free / paid tiers | Free |
Features
Encode and decode
Both directions, so you can check what a system produced as easily as prepare what you are about to send.
Minimal or full encoding
Escape only the characters the context requires, or every non-ASCII character, depending on where the text is going.
Named entity support
The full HTML5 named set is recognised when decoding, including the long tail almost no one types by hand.
Hexadecimal and decimal
Numeric references are read and written in both spellings, since real documents contain both.
Double-encoding detection
Existing entities in the input are highlighted before you encode them a second time.
Large inputs supported
A whole template or a long export converts without an upload or a size ceiling.
Nothing to install
No build tool, no runtime, no dependencies — it runs in the web page.
Arabic and RTL ready
The full interface in eight languages, including right-to-left Arabic.
Secure by default
Served over HTTPS, with no content tracking and no third-party upload.
Who uses it
Web developers
Checking how a string will behave once it is inside an attribute value.
Email developers
Preparing subject lines and body text for clients that parse strictly.
Technical writers
Showing code samples in a page without the browser trying to run them.
Anyone debugging mojibake
Decoding a string that arrived with `&amp;` in the middle of it.
Frequently Asked Questions
No. Everything runs locally in your browser — your text is never uploaded, stored, or shared.
Yes — completely free, with no account and no limits.