Which characters JSON requires you to escape
A JSON string can hold almost any text, but a handful of characters change meaning unless they are escaped. The double quote would otherwise end the string, the backslash starts an escape sequence, and every control character below U+0020 is illegal as a literal. The escaper turns each of these into a safe two-character sequence (or a \uXXXX code).
Raw text Escaped form
" \" (double quote)
\ \\ (backslash)
newline \n (U+000A)
tab \t (U+0009)
carriage return \r (U+000D)
backspace \b (U+0008)
form feed \f (U+000C)Quotes, backslashes, newlines, and tabs in practice
The two characters people forget most often are the double quote and the backslash. A Windows file path must double every backslash, and a quoted phrase must escape each inner quote. Real line breaks and tabs are also illegal as literals — they must become \n and \t.
// ❌ Invalid JSON — literal backslashes, quotes, and a line break
{"path": "C:UsersAlice", "msg": "She said "hi"
again"}
// ✅ Valid — escaped
{"path": "C:\Users\Alice", "msg": "She said \"hi\"\nagain"}Unicode and the \uXXXX escape
JSON files are UTF-8 by default, so emoji and accented letters can appear as-is. But any code point may also be written as \uXXXX with a four-digit hex value, and characters above U+FFFF (most emoji) require a surrogate pair. Forcing every non-ASCII character into a \uXXXX escape is how you produce pure-ASCII JSON for older systems.
// Copyright sign as a Unicode escape
{"notice": "\u00A9 2026 Acme Corp"}
// Grinning face emoji (U+1F600) as a surrogate pair
{"emoji": "\uD83D\uDE00"}Escape vs. unescape: the round trip
Escaping prepares text to go into JSON; unescaping recovers text that came out of it. The two operations are exact inverses — escape the raw text, drop it between quotes, and a parser will hand you back the original.
Raw text: line one
line two (with a real tab here → end)
Escaped: line one\nline two (with a real tab here →\tend)
Unescaped: back to the original two lines with a tabWhen you embed JSON inside another JSON string
Sometimes a JSON value must itself contain a serialized JSON document — a webhook envelope whose payload is stringified JSON, or a text column that stores JSON. The inner document gets escaped, so its quotes become \" and its backslashes double. This is the famous "double-escaped" JSON.
// Outer envelope — the payload is a STRING that contains JSON
{
"event": "order.created",
"payload": "{\"id\":42,\"name\":\"Alice\"}"
}
// To read the inner document you parse twice:
const env = JSON.parse(raw)
const order = JSON.parse(env.payload) // { id: 42, name: "Alice" }Escape and unescape in code
Let the standard library do the escaping — never build escape sequences by hand:
// JavaScript — escape, then strip the outer quotes if needed
const inner = JSON.stringify('She said "hi"\nbye') // "\"She said \\\"hi\\\"\\nbye\""
const contentOnly = JSON.stringify(raw).slice(1, -1) // without surrounding quotes
// Unescape a fragment by wrapping it in quotes and parsing
const back = JSON.parse('"' + escaped + '"')# Python — json.dumps escapes; ensure_ascii forces \uXXXX for non-ASCII
import json
json.dumps('café\n"x"') # '"caf\u00e9\n\"x\""' (ensure_ascii default)
json.dumps('café', ensure_ascii=False) # '"café"' (raw UTF-8)
json.loads('"caf\u00e9\n\"x\""') # back to the original textFor the full escape-sequence reference and common parse errors, see the escape JSON string guide. To check that your escaped result parses, paste it into the JSON formatter.