JSON Escape/Unescape_
JSON has exactly eight two-character escapes, and the apostrophe is not one of them. \' is a JavaScript habit that produces invalid JSON — a single quote is an ordinary character here and needs nothing done to it. The full list is closed, and it is shorter than most people expect.
The other half is that escaping once is rarely the job. Almost everyone arrives with a JSON document that has to go inside a JSON string, and every level doubles: a quotation mark carries one backslash at a single level, three at two, and seven at three. So this escapes to a depth, and shows the arithmetic while it does it.
- Input
- Any text, in either direction. Unescaping strips the surrounding quotation marks if the value was pasted with them.
- Output
- The escaped or unescaped string, optionally wrapped in quotes so the result is a complete JSON value rather than its contents.
- Processing
- Escaping matches JSON.stringify character for character, which the test suite asserts against the platform rather than against a table.
- Limits
- This escapes strings. It does not validate the JSON document a string came from — a payload can be perfectly escaped and still be malformed once it is read back.
- Why an invalid escape is passed through rather than refused
- The input people actually have is a payload that is nearly right — one \x41 or one stray apostrophe in three thousand characters. Failing the whole thing would hide the rest of the answer, so every bad sequence is reported with its position and left exactly as it was found.
JSON has eight escapes and no apostrophe
The complete list, and why it is closed
RFC 8259 §7 enumerates them: \", \\, \/, \b, \f, \n, \r, \t, and \u followed by exactly four hexadecimal digits. That is everything. The list being closed is the part that matters: JSON does not ignore an escape it does not recognise, it rejects the document. So \' is not a harmless redundancy — it is a parse error, and it is the single most common one, because every language people write JSON from allows it in their own string literals.
Escaping twice is the actual job
A webhook body inside a config value. A fixture inside a test payload. A response captured into a log line that is itself JSON. Each level of nesting escapes what is already escaped, so a backslash doubles every time — one becomes two, two become four, four become eight — and a quotation mark accumulates 2ⁿ − 1 backslashes in front of it. At three levels that is seven, which is where a value stops being something anyone can read or edit by hand. The arithmetic is not hard; it is just never shown, and counting backslashes by eye is how the wrong number gets shipped.
A literal newline inside a string is invalid
Every character below U+0020 has to be escaped — there is no exception for the ones that look like whitespace. Paste a multi-line block into a JSON string and the parse fails on the first line break, which is the usual reason a hand-edited config or a copied SQL query will not load. A tab does the same and is far harder to spot, because the error points at a position rather than at something you can see.
The forward slash is the only optional one
\/ and / mean the same thing, and no parser cares which you write. It exists for one reason: JSON embedded in an HTML page. A string containing </script> ends the script element as far as the HTML parser is concerned, whatever the JavaScript around it says, so escaping the slash is what keeps the page intact. Outside that case it is noise, which is why JSON.stringify does not do it and why the option here is off by default.
Two characters that are legal here and break JavaScript
U+2028 and U+2029 — line separator and paragraph separator — are ordinary characters in a JSON string and were line terminators in JavaScript source until ES2019. So a valid JSON document inlined into a <script> block could produce a syntax error in the surrounding script, from a character that is invisible in every editor. Newer engines accept them, older ones and some tooling do not, and escaping them costs nothing. The ASCII option here does it.
Escapes are not encoding
\uXXXX is a way of writing a character, not a way of encoding one, and the two get confused constantly. There is no \u{1F600} in JSON — that form is JavaScript — so an emoji is written as its surrogate pair, \ud83d\ude00. A lone half of a pair is allowed by the grammar and is not valid Unicode, which means it will survive JSON.parse untouched and fail later, somewhere with a worse error message.
Escape, nest, or read one back
- 01Paste the value. Escape is the default; switch to Unescape to read a payload that arrived already escaped.
- 02Set the nesting level if the result is going inside another JSON string. The note beside the slider says how many backslashes a quotation mark will end up with.
- 03Turn on quotes when you want a complete JSON value rather than its contents — that is the difference between what JSON.stringify returns and what most tools show.
- 04Escape forward slashes only if the output is going into a <script> block, and ASCII only if it has to survive a channel that mangles Unicode.
- 05On the way back, read the notes. Every invalid escape is named with its position, and the commonest of them is one an editor put there.
A payload inside a payload
A webhook body has to be stored as a string field in another JSON document. Everything doubles, and by hand it goes wrong at about the second level.
{"id":1,"note":"he said \"no\""}{\"id\":1,\"note\":\"he said
\\\"no\\\"\"}An apostrophe that will not parse
The string came out of a language where \\' is legal, and the JSON parser rejects the whole document over one character.
{"msg":"it\'s fine"}{"msg":"it's fine"}
Nothing. An apostrophe is an
ordinary character here.A multi-line block that fails to load
A query or a certificate pasted straight into a config file. The error names a position rather than the problem.
SELECT * FROM users
SELECT *\nFROM users Every character below U+0020 has to be escaped.
JSON going into a script tag
Server-rendered state inlined into the page. A single string containing a closing tag ends the element early, and the page breaks in a way the JavaScript cannot see.
"</script><script>…"
"<\/script><script>…" The HTML parser no longer sees a closing tag.
Every escape JSON has
| Character | Escape | Required? |
|---|---|---|
Quotation mark " | \" | Required |
Reverse solidus \ | \\ | Required |
Solidus / | \/ | Optional — for </script> inside HTML |
| Backspace | \b | Required |
| Form feed | \f | Required |
| Line feed | \n | Required |
| Carriage return | \r | Required |
| Character tabulation | \t | Required |
| Any other character below U+0020 | \u00XX | Required — there is no short form for these |
| Anything else | — | Nothing. Apostrophes, ampersands and accented letters are ordinary characters |
The list is closed. An escape that is not on it is not ignored — it makes the document invalid, which is why \\' and \\x41 are parse errors rather than harmless extras.
Working with escaped JSON
- Let a library do it. JSON.stringify, json.dumps and their equivalents are correct by construction; string concatenation with manual quoting is where the bugs come from.
- Never escape an apostrophe. It is an ordinary character in JSON, and the escape your editor or your language suggested is a parse error.
- Count the levels rather than the backslashes. Seven in front of a quotation mark means three levels of nesting, and reading it the other way round is how the wrong depth gets shipped.
- Prefer not to nest at all where you control the format. A structured field beats a string containing a document, and it removes the whole class of problem.
- Escape forward slashes only when the output goes into HTML. Everywhere else it is noise, and it makes a diff harder to read.
- Treat a lone surrogate as a bug upstream. It parses, it is not valid Unicode, and it will fail later somewhere with less context.
Where JSON escaping goes wrong
\' is not a redundant escape, it is an error
JSON rejects any escape outside its eight. A single quote needs nothing at all, and adding a backslash before it invalidates the document — which is confusing because almost every language people write JSON from allows it in their own literals.
Whitespace inside a string still has to be escaped
A literal newline or tab is below U+0020 and therefore illegal, even though it looks like ordinary formatting. Pasted multi-line text is the most common cause of a JSON file that will not load.
Escaping twice by hand does not work
The counts stop being intuitive at the second level and are unreadable at the third. A quotation mark reaches seven backslashes at three levels, and there is no way to verify that by looking.
Escaping is not sanitising
Correct JSON escaping makes a value safe to put in a JSON document. It says nothing about whether it is safe to put in HTML, a shell, or a SQL statement — those need their own escaping, applied at the point of use rather than in advance.
A lone surrogate is legal and still broken
The grammar allows \ud83d with nothing after it. JSON.parse accepts it, the result is not well-formed Unicode, and the failure surfaces much later — in a database write, a hash, or a terminal.
Grammar, encoding and equivalence
- Specification
- RFC 8259 §7, which is identical to ECMA-404 on this point. Eight two-character escapes and \u with exactly four hexadecimal digits.
- Required
- The quotation mark, the reverse solidus, and every code point from U+0000 to U+001F. Five of those control characters have short forms; the rest need \u00XX.
- Optional
- The solidus, and only the solidus. \/ and / are equivalent to every parser, and the escape exists for JSON embedded in HTML.
- Not escapes
- \', \x41, \0, \v and \u{1F600} are all JavaScript rather than JSON, and each makes a document invalid. This page names them individually rather than reporting a generic failure.
- Astral characters
- Written as a surrogate pair — 😀 is \ud83d\ude00. There is no code-point escape in JSON, and an unpaired surrogate is permitted by the grammar while not being valid Unicode.
- Equivalence
- Escaping here matches JSON.stringify character for character with the quote option on, which the test suite asserts against the platform for every sample rather than against a table.
- Network
- None from tool code. A test sweep calls every function this page uses with
fetchandXMLHttpRequestreplaced by stubs that throw, so a stray request fails the build instead of shipping. Disconnect from the network and the page still works.
Questions about escaping JSON
How do you escape a single quote in JSON?
You do not. An apostrophe is an ordinary character in JSON and needs no escape at all — JSON has no \' sequence, and adding one makes the document invalid. The confusion comes from JavaScript, Python and PHP, all of which accept it inside their own string literals.
Which characters have to be escaped in JSON?
The quotation mark, the reverse solidus, and every control character from U+0000 to U+001F. Five of those have short forms — \b, \f, \n, \r and \t — and the rest are written \u00XX. Nothing else is required, and the forward slash is the only optional escape.
How do I escape a JSON string inside another JSON string?
Escape it twice, and expect the counts to look wrong. Each level doubles every backslash, so a quotation mark ends up with one backslash at a single level, three at two levels and seven at three. Set the nesting level above rather than doing it by hand.
Why does my JSON fail with a literal newline in it?
Because every character below U+0020 must be escaped, including the ones that look like ordinary formatting. A pasted multi-line query, certificate or log entry has to become \n before it will parse — this is the most common cause of a JSON file that will not load.
Do I need to escape forward slashes in JSON?
No parser requires it, and JSON.stringify does not do it. The one reason to is JSON embedded in an HTML page: a string containing </script> closes the element as far as the HTML parser is concerned, no matter what the surrounding JavaScript looks like. Escaping the slash prevents that and changes nothing else.
What is the difference between escaping and JSON.stringify?
JSON.stringify returns a complete JSON value including the surrounding quotation marks; most escape tools return only the contents. Both are useful and they are not interchangeable — pasting one where the other is expected produces either doubled quotes or a value with no quotes at all. The wrap option here switches between them.
How do I write an emoji in JSON?
As a surrogate pair: 😀 is \ud83d\ude00. JSON has no \u{1F600} form — that is JavaScript. You can also just include the character literally, since JSON documents are UTF-8 and there is no requirement to escape anything above U+001F.
Is \x41 valid in JSON?
No. Hexadecimal escapes are a JavaScript feature; JSON has only \u with exactly four hexadecimal digits, so the same character is \u0041. An unknown escape is not ignored — it makes the whole document invalid.
What does "bad escaped character" mean?
A backslash followed by something that is not one of the eight legal escapes or a valid \uXXXX. The usual culprits are an apostrophe, a \x sequence, a \0, or a \u with fewer than four digits. Paste the string into the unescape direction above and each one is named with its position.
Is the text I paste here uploaded?
No. The work is JavaScript running in this tab. Every function it calls is covered by a test that stubs fetch and XMLHttpRequest to throw, so a request that slipped in would break the build rather than reach a server — and you can confirm it for yourself by disconnecting and carrying on.