HTML Encoder

Escape text into HTML entities so a stray angle bracket renders as a character instead of a tag. Use it to show code on a page, or to find out why a user's apostrophe broke a template. Choose Named, Numeric or Hex entities depending on what will read the output.

Plain Text
Encoded HTML

1 HTML Encoder example

Plain text

1
<a href="/search?q=cats&safe=on" title='Ryan’s picks'>Cats & dogs</a>

Encoded

1
&lt;a href=&quot;/search?q=cats&amp;safe=on&quot; title=&apos;Ryan&rsquo;s picks&apos;&gt;Cats &amp; dogs&lt;/a&gt;

2 The five that matter

& for &

Encode & first, always. Encoding it last turns every entity you already wrote into visible text: &lt; becomes &amp;lt;.

< and >

Without these, a user typing <script> gets a script tag instead of the words they meant.

" and '

Required only inside an attribute. Escaping them everywhere costs nothing, and a value can then move from text into an attribute without opening a hole.

Everything else

Optional. Turn on Encode all non-ASCII when the text has to pass through a Latin-1 database or an old email gateway that mangles UTF-8.

3 Escaping is contextual

The same string needs different treatment depending on where it lands. In HTML text, escaping the five characters above is enough. Inside an unquoted attribute, a space ends the value. Inside a script block, HTML escaping does not help and you need JSON encoding instead. Inside a URL, you want percent-encoding, not entities.

Escape at output, never at input. Pre-escaped text in storage breaks every consumer that is not HTML, and it is how &amp;amp; ends up in a database. Let the template engine do it: Blade, Twig, Django and JSX all escape by default, so review each place where your code deliberately bypasses that.

How to use the HTML Encoder tool

  1. Paste the text or markup you want to escape into the left panel.
  2. Choose the entity style: Named for readable output such as &amp;, Numeric or Hex for maximum compatibility.
  3. Tick Encode all non-ASCII if accents and emoji also have to survive a Latin-1 pipeline.
  4. The escaped result appears on the right. Copy Result puts it on the clipboard.

How to escape HTML in JavaScript, PHP and Python

JavaScript

// Escape for HTML text and attribute values
const escapeHtml = (s) =>
    s.replace(/&/g, "&amp;")     // & first, always
     .replace(/</g, "&lt;")
     .replace(/>/g, "&gt;")
     .replace(/"/g, "&quot;")
     .replace(/'/g, "&#39;");

console.log(escapeHtml('<a href="x">Cats & dogs</a>'));

// In practice, do not build HTML by hand at all:
el.textContent = userInput;                    // safe, no escaping needed
el.setAttribute("title", userInput);           // safe
el.innerHTML = "<b>" + userInput + "</b>";     // this is the bug

textContent and setAttribute escape for you. Use a manual escape only when you are producing a string that something else will parse as HTML.

PHP

<?php
$text = '<a href="x">Cats & dogs</a>';

// ENT_QUOTES escapes both quote styles; the third argument avoids
// silently returning an empty string on invalid UTF-8.
echo htmlspecialchars($text, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'), PHP_EOL;

// htmlentities() also escapes every accented character.
// Only useful if the output is not UTF-8.
echo htmlentities('Café', ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'), PHP_EOL;

// In Blade, {{ $value }} already does htmlspecialchars.
// {!! $value !!} does not, which is exactly when to be careful.

Python

import html

text = '<a href="x">Cats & dogs</a>'

print(html.escape(text))              # quote=True by default
print(html.escape(text, quote=False)) # leaves " and ' alone

# Django and Jinja2 autoescape in templates. The dangerous move
# is turning it off:
#   {{ value|safe }}          Django
#   {{ value|safe }}          Jinja2
# Both mean "I have already made sure this is safe", so be sure.

Common errors and how to fix them

The output contains &amp;amp;
The text was escaped twice. Escape at output only, never before storing, and check whether your template engine is already doing it for you.
htmlspecialchars returned an empty string
The input contains invalid UTF-8. Pass ENT_SUBSTITUTE so bad bytes become a replacement character instead of emptying the whole string.
An attribute value broke the tag
The value contained the quote character that delimits it, and the default escaping did not cover it. Use ENT_QUOTES in PHP, quote=True in Python, and always quote your attributes.
Escaping did not stop the XSS
The escaping did not match the context. HTML escaping does not protect a script block, a style block or a javascript: URL. Each context needs its own encoding, and some, such as an event handler attribute, should never take user data.

Good to know

XML predefines exactly five entities: &amp; &lt; &gt; &quot; &apos;. HTML5 defines around 2,200 more, including &nbsp; and &eacute;, which is why an XML parser rejects HTML that uses them. If the output has to be valid XML or XHTML, use numeric references instead of named ones.

Escape the ampersand first. If you escape it last, every entity you already produced gets its & turned into &amp;, so &lt; becomes &amp;lt; and renders as visible text.

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 characters get escaped?

By default, the five that matter for correctness: < > & " and '. Turn on Encode all non-ASCII and every accented letter, symbol and emoji is escaped too. Use that when the text has to pass through a Latin-1 pipeline.

Named entities or numeric ones?

Use named entities such as &amp; when people will read the source. Use numeric ones such as &#38; when the output must also parse as XML, since XML knows only five predefined names.

Does escaping protect me from XSS?

Escaping the right way in the right place does. Escape when you output, not when you store, and use the escaping that matches the context: HTML text, an attribute value and a script block each need different treatment. Use this box for debugging; in production, let your template engine escape.

Why is my ampersand becoming &amp;amp;?

The text was already escaped once and you escaped it again. Run it through the HTML decoder first, then encode once.

Do I need to escape the apostrophe?

In HTML text, no. Inside a single-quoted attribute, yes, or the value ends early. We recommend escaping it everywhere, so a value can move into an attribute without breaking.

HTML entity hex vs decimal: what is the difference?

Nothing, to the browser. &#38; and &#x26; both mean the ampersand, and every HTML and XML parser accepts both. Hex is the Unicode code point written the way the charts show it, so &#xE9; is easy to check against U+00E9 and matches the \u00e9 form used in CSS and JavaScript. Decimal is what older tools and many CMS editors emit. Pick whichever your codebase already uses.

How do I encode emoji or accented characters as HTML entities?

Tick Encode all non-ASCII. Every character above the ASCII range then becomes one entity per code point: with Hex selected, é becomes &#xE9; and an emoji such as the grinning face becomes &#x1F600;, and with Numeric they are &#233; and &#128512;. Named covers only characters that have a name, so anything without one falls back to the decimal form.

Going the other way

The HTML decoder turns entities back into readable text. For URLs use the URL encoder instead, and to tidy up the markup itself there is the HTML formatter.

More Encoders & Decoders

Browse all encoders & decoders

Copied to clipboard!