HTML encode

Paste text and get it back with the characters that change how a document parses replaced by their entities. That is five characters in the ordinary case, and the larger version — everything above ASCII as well — is offered separately, because it is a different job with a different cost. The escaping happens in this page.

The first is what a template engine does. The second is for a pipeline that is not UTF-8 clean.

Result

The answer appears here as you type.

  • Where it runs

    Nothing is uploaded, because there is no file — it is worked out in this page.

  • No queue, no account

    It answers as fast as your machine can, and it never asks who you are.

  • As often as you like

    Nothing is counted and nothing is capped — answering again costs us nothing.

How it works

  1. Paste the text or markup into the box.
  2. Choose how much to escape. The default is the five characters that affect parsing.
  3. Copy the result into your template, your CMS field or your documentation.

Five characters decide whether text stays text

An ampersand starts a reference, a less-than sign starts a tag, a greater-than sign ends one, and both kinds of quotation mark end an attribute value. Everything else in a document is inert. Escape those five and arbitrary text can be dropped anywhere in a page and will still be the text somebody wrote.

Leave them and the text becomes structure. That is the mechanism behind cross-site scripting, but it is also the mechanism behind a product description that silently swallows half a paragraph because an editor typed "under 5 < 10 units" into it. The second happens far more often and is noticed far later.

The order of the replacements is where it goes wrong

The ampersand has to be replaced first. Do the less-than sign first and it becomes `&lt;` — which now contains an ampersand, which the next pass escapes, and the output is `&amp;lt;`, rendering on the page as the literal text `&lt;`.

It is a two-line function that is wrong in this exact way in a good share of the implementations you will find pasted into an answer somewhere, and it is wrong invisibly: text containing none of the five comes out identical, so a test written on ordinary prose passes. That is why the test for this one is written on a string containing both characters at once.

What escaping everything is actually for

Not safety. The five characters are the whole of the safety argument; escaping an umlaut protects nothing, and it makes the output larger and unreadable, which is a real cost for whoever maintains the file it lands in.

It is for survival through a pipeline that is not UTF-8 clean: a mis-declared charset somewhere, a database column still in latin1, an export to a system that predates the decision that the web is UTF-8. In all of those `&#252;` arrives intact where `ü` arrives as two mojibake characters. If you do not have that problem, do not reach for it.

Escaping is not sanitising, and confusing them is a security bug

Escaping turns markup into text. Sanitising keeps markup and removes the dangerous parts — the difference between showing somebody a `<script>` tag and letting them keep a `<b>` tag but not a `<script>` one. Different operations, different failure modes, and only one of them is total.

If you want text, escape: there are no bypasses, and this page does it. If you want a subset of HTML you need a sanitiser with an allowlist and an active maintainer, and no amount of escaping substitutes for one. A tool offering both behind a toggle would mostly be inviting the wrong choice.

Emoji, and the surrogate pair that breaks encoders

A JavaScript string is a sequence of sixteen-bit units, and anything above U+FFFF — every emoji, much of the CJK extension range — takes two of them. An encoder that walks the string by index sees those halves separately and emits two numeric references, neither of which is a character.

The output then renders as two replacement glyphs and cannot be decoded back. This one walks by code point, so an emoji becomes `&#127757;` rather than `&#55356;&#57101;`. One word of difference in the implementation, and it is the difference between round-tripping and not.

HTML encode: common questions

Which characters does the default escape?

The ampersand, both angle brackets and both kinds of quotation mark. Those five change how a document parses; everything else is already inert, and escaping it buys nothing but length. The larger option adds every character above ASCII, which is a transport concern rather than a correctness one.

Does escaping protect me from cross-site scripting?

Escaping text before it goes into a page is the correct defence for that context — but only if it happens everywhere untrusted text is inserted, and only if the context really is text rather than an attribute inside a script or a URL. Pasting one string through a tool is not a strategy; escaping in your template layer is.

Why does my emoji become one number rather than two?

Because that is the correct answer. An emoji is a single character above U+FFFF, stored as two units in a JavaScript string. Encoders that walk by index emit two references for it, and those cannot be turned back into anything. This one walks by code point, so the emoji survives the round trip.

Should I escape text when I store it or when I show it?

When you show it. Store what the person actually wrote, and escape at the moment it is inserted into a page — the same text may later go into an email, a PDF or an API response, where HTML entities are simply wrong. Escaping on the way in is how a database ends up full of &amp;.

Is anything sent to a server?

No. The replacement happens in this page and the network panel shows nothing leaving while you type. That matters more than it looks here: the text people escape is often a customer comment or a support message, which is somebody else data rather than their own.

Other tools