About HTML Encode

HTML encoding replaces characters that have meaning in markup with entities: < becomes &lt;, > becomes &gt;, & becomes &amp;, " becomes &quot;. It is how you display code or user text inside a web page without the browser interpreting it as markup — and it is the canonical defense against reflected and stored XSS, the vulnerability class that has sat in the OWASP Top 10 since the list existed.

This encoder converts text to its entity-escaped form locally in your browser. Paste a code snippet to embed in a blog post, or check exactly what a template engine should be producing for a given input.

How to use HTML Encode

  1. Enter or paste the input in the text area.
  2. Click Convert to encode or decode.
  3. Copy or download the result.

Example

Input

Your input or data here

Output

Result will appear here after running the tool

The five characters that matter (and why)

Only a handful of characters can change parsing context: < opens a tag, & starts an entity, " and ' close attribute values, > closes a tag. Encode those five and text can no longer break out of its context — <script> becomes the harmless text &lt;script&gt;. Everything else (é, ก, emoji) does not need encoding on UTF-8 pages; numeric entities like &#233; are a legacy of non-Unicode encodings and only add noise today.

Order matters when encoding manually: & must be encoded first, or you double-encode your own entities (&lt; → &amp;lt;). Every serious library gets this right; hand-rolled replace chains regularly don't.

Context is everything — where entity encoding is NOT enough

Entity encoding protects HTML body and attribute contexts. It does not protect: URLs (javascript:alert(1) contains none of the five characters — validate schemes instead), JavaScript string contexts inside <script> (needs JS string escaping, or better, pass data via data-attributes/JSON), CSS contexts, or attribute values left unquoted in the template (onmouseover=… injects without any special characters). OWASP's XSS Prevention Cheat Sheet is organized around exactly these contexts.

The modern practice hierarchy: let your framework auto-escape (React, Vue, Django, Rails templates all do), reserve raw-HTML escape hatches (dangerouslySetInnerHTML, |safe) for sanitized content only, and sanitize rich user HTML with an allowlist library (DOMPurify) rather than encoding it.

Everyday non-security uses

  • Publishing code samples in CMSs and blog platforms that would otherwise render your <div> examples as actual divs.
  • Embedding XML/HTML snippets inside other XML (RSS feeds, SVG in HTML, sitemaps).
  • Writing about entities themselves — to show &lt; you must write &amp;lt;.
  • Preparing strings for HTML email templates, where stray & from URLs (?a=1&b=2) must become &amp; to validate.

Common errors and how to fix them

Text shows literal &amp;lt; on the page

Cause: Double encoding — the string was encoded twice (often once by you, once by the template engine's auto-escape).

Fix: Encode exactly once at output time. With auto-escaping frameworks, store raw text and let the framework do the encoding.

Encoded content still executes as script

Cause: The output landed in a context entity encoding doesn't protect: an unquoted attribute, a javascript: URL, or inside a <script> block.

Fix: Quote all attributes; validate URL schemes against an allowlist; never build script bodies by concatenation — use JSON in a data attribute.

Ampersands break my URLs in HTML

Cause: Query strings contain raw & which HTML parses as entity starts (&copy=1 renders ©=1).

Fix: Encode & as &amp; in href values. Browsers are forgiving, validators and edge-case entities are not.

Broken characters like &#65533; or � after encode/decode cycles

Cause: A charset mismatch upstream (UTF-8 bytes read as Latin-1) — not an entity problem.

Fix: Fix the page/database charset to UTF-8 end to end; entities can represent any character but can't repair mojibake already in the data.

Tips and best practices

  • Encode at output, not at storage: store the raw user text once, escape it per-context each time you render. Encoding before storage leads to double-encoding and un-searchable data.
  • &apos; is XML, not HTML4 — use &#39; for single quotes if you must support ancient renderers; modern HTML5 accepts both.
  • For attribute values, always quote them in templates; encoding cannot save an unquoted attribute.
  • Displaying user names/comments? Framework auto-escape covers it. Accepting rich HTML? That's sanitization (DOMPurify allowlist), a different operation than encoding.
  • Pair with the HTML Decode tool to inspect what encoded payloads in logs actually say.

Frequently asked questions

Which characters must be encoded?
The context-changing five: & < > " ' (ampersand first). On UTF-8 pages, everything else — accents, Thai, emoji — can stay literal; numeric entities for them are legacy practice.
Does HTML encoding prevent XSS?
In HTML body and quoted-attribute contexts, yes — it is the standard defense. It does not cover URL, JavaScript, CSS, or unquoted-attribute contexts, which need their own escaping or validation per the OWASP cheat sheet. Framework auto-escaping handles the common cases correctly.
What's the difference between encoding and sanitizing?
Encoding makes all markup inert — everything displays as text. Sanitizing selectively keeps allowed markup (bold, links) while stripping dangerous constructs. Plain text display → encode; rich user HTML → sanitize with an allowlist library.
Why am I seeing &amp;amp; in my page source?
Double encoding: an already-encoded string was encoded again. Encode exactly once, at render time, and check whether your template engine already auto-escapes before adding manual encoding on top.
Named or numeric entities — which should I emit?
For the five specials, named entities (&lt; &amp;) are conventional and readable. For everything else on modern UTF-8 pages, emit the literal character. Numeric forms (&#x27;) matter mainly for quotes in ancient-compat scenarios.

Embed this tool

Add HTML Encode to your own site, blog post, or internal docs — free, no signup. The widget runs entirely in your visitors' browsers, same as it does here.