Skip to content

Escaping Strings in JSON, HTML, and URLs

Sep 2, 2026 · Web Development

Escaping means neutralising the characters that would otherwise be read as syntax in whatever context a string lands in, and each context, JSON, HTML, and URLs, has its own rules that are not interchangeable. The single most common source of text bugs and injection holes is treating escaping as one universal operation. It is not. A double quote is dangerous in a JSON string but harmless in a URL path; a less-than sign is dangerous in HTML but meaningless to JSON; a space is fine in HTML but must be encoded in a URL. Getting this right means asking, at every boundary a value crosses, which characters this particular context treats as special, and encoding exactly those.

Why can’t one escaping rule cover everything?

One rule cannot cover everything because each format defines its own special characters and its own way of neutralising them. Escaping is not about a fixed set of bad characters; it is about the grammar of the destination. The destination decides what counts as structure and what counts as data, so the same byte can be perfectly safe in one place and catastrophic in another.

Context Special characters Escape mechanism
JSON string " and control characters Backslash escapes: " \ n uXXXX
HTML text < & (and quotes in attributes) Entities: &lt; &amp; &quot;
URL component Anything outside a small safe set Percent-encoding: %20 %26 %3D

Notice there is almost no overlap. JSON cares about quotes and backslashes; HTML cares about the characters that begin tags and entities; URLs care about the delimiters that separate parts of an address plus anything non-ASCII. Because the danger sets differ, a value escaped for one context is simply wrong for another. This is why “escape it once and reuse it” fails: it optimises for the wrong boundary.

How does JSON escaping work?

JSON escaping neutralises the two characters that structure a JSON string, the double quote and the backslash, plus control characters that are not allowed raw. Inside a JSON string the double quote ends the string, so a literal quote in your data must become ". The backslash starts an escape sequence, so a literal backslash must become \. Control characters like newline and tab cannot appear raw and are written as n and t, while any character can be written as u followed by four hexadecimal digits.

Raw value:    He said "hi"then left
                       ^^^^  ^^ backslash-t was literal text

JSON string:  "He said "hi"\then left"
                       ^^   ^^  ^^
              quote -> "   "  backslash -> \

The subtle trap is that JSON escaping alone does not make a string safe to drop into an HTML page. If you serialise data to JSON and then embed that JSON inside a script tag or an HTML attribute, the HTML parser sees it first, and characters like < still need HTML treatment. JSON handled the JSON layer; it did nothing for the HTML layer. Each layer must be handled at its own boundary.

How does HTML escaping differ?

HTML escaping replaces the characters that the HTML parser reads as markup with named or numeric entities. In body text that means the less-than sign becomes &lt; and the ampersand becomes &amp;, because the first starts a tag and the second starts an entity. Inside an attribute value you additionally escape whichever quote delimits the value, since an unescaped matching quote would end the attribute early and let an attacker add new attributes.

The reason this matters for security is direct. If a user types <script>steal()</script> and you place it into a page without escaping, the browser executes it as a real script element. Escaping the less-than sign turns it into inert text that displays as characters rather than running as code. That single transformation, applied at the moment data becomes HTML, is the backbone of cross-site scripting prevention.

User input:   <b>Tom & Jerry</b>
Unescaped:    renders bold and could run tags   (data treated as structure)
Escaped:      &lt;b&gt;Tom &amp; Jerry&lt;/b&gt;
              displays the literal text          (data treated as content)

Note that HTML escaping ignores backslashes entirely, the opposite of JSON, and JSON ignores the less-than sign entirely, the opposite of HTML. The two rule sets barely touch, which is exactly why you cannot substitute one for the other.

How does URL escaping work?

URL escaping, called percent-encoding, replaces unsafe characters with a percent sign followed by their byte value in hexadecimal. A space becomes %20, an ampersand becomes %26, and an equals sign becomes %3D. This is necessary because a URL has a rigid structure: ? begins the query, & separates parameters, = separates a key from its value, and / separates path segments. If a value contains one of those characters unescaped, it collides with the structure and changes the meaning of the address.

The critical distinction is between encoding a whole URL and encoding a single component. Encoding a whole URL must preserve the structural characters, or you would destroy the address. Encoding one component must encode those same structural characters, or a value could inject an extra parameter.

Operation Leaves intact Use for
Whole-URL encoding : / ? & = # and similar Cleaning up a complete URL
Component encoding Only unreserved characters A single query value or path segment

Concretely, to put the value a&b=c into a query parameter, you must component-encode it to a%26b%3Dc. Left raw, the & would start a new parameter and the = would split a key, so the server would parse something you never intended.

What happens when you nest contexts?

When one context is embedded in another you must escape from the inside out, applying each layer rule in order. Real systems nest constantly: a URL sits inside an HTML attribute, JSON sits inside a script block, a value sits inside a query string that sits inside a link. Each boundary is a separate escaping step, and skipping any one leaves a hole.

Consider a search term placed into a link. First you URL-encode the term so it is a valid query value, then you HTML-escape the resulting URL because it is going into an href attribute:

Search term:      Tom & Jerry
1) URL-encode:    Tom%20%26%20Jerry
2) Build URL:     /search?q=Tom%20%26%20Jerry
3) HTML-escape:   href="/search?q=Tom%20%26%20Jerry"
                  (any & in the URL becomes &amp; for the attribute)

The order is not optional. URL-encoding first ensures the query is structurally correct; HTML-escaping second ensures the attribute is structurally correct. Reverse them and you get a value that is valid in neither. This inside-out discipline, one escape per boundary in the right order, is what keeps nested output both correct and safe.

How do you check your escaping quickly?

The practical way to verify escaping is to run a sample value through the exact transformation and read the output. You can encode and decode HTML with our HTML entities tool and percent-encode or decode query values with the URL encoder, comparing what goes in against what comes out so you can confirm the right characters, and only those, were touched. Both run client-side, so test data, which may contain real user content or secrets, stays in your browser rather than travelling to a server.

The mental model to carry away is that escaping is always relative to a destination. Before encoding anything, name the context it is entering, recall which characters that context treats as special, and neutralise exactly those. When contexts nest, escape from the innermost outward, one boundary at a time. Do that and the same value can travel safely through JSON, HTML, and URLs without ever being mistaken for structure, which is both the correctness win and the security win.

Frequently asked questions

Why does the same string need different escaping in different places?

Because each context has its own special characters and syntax. A quote matters in JSON, a less-than sign matters in HTML, and a space or ampersand matters in a URL. Escaping means neutralising exactly the characters that would break the current context, so the correct rules depend entirely on where the string is going.

What characters must be escaped in JSON strings?

Inside a JSON string you must escape the double quote and the backslash, and you must escape control characters such as newline and tab. JSON uses backslash escapes like backslash-n for newline and backslash-u followed by four hex digits for arbitrary characters.

What is the difference between encodeURI and encodeURIComponent?

encodeURI escapes a whole URL and leaves characters that have structural meaning, such as slash, question mark, and ampersand, intact. encodeURIComponent escapes a single piece meant to sit inside one component, so it also encodes those structural characters. Use component encoding for query values.

Can I escape once and reuse the result everywhere?

No. Escaping is context-specific, so a value escaped for HTML is wrong inside a URL and vice versa. You must escape at each boundary the value crosses, using that boundary rules, and never assume one round of escaping makes a string universally safe.

How does correct escaping prevent injection attacks?

Injection happens when data is mistaken for code or structure, such as user text becoming HTML tags or a query value becoming markup. Escaping at each boundary forces the parser to treat the data as inert content, so it cannot change the structure of the document, request, or query it lands in.