{ }jsonkitOpen

How to escape and unescape JSON strings

9 min read · updated 2026-09-24

To escape JSON, you encode the characters that would otherwise break a string, so the value stays valid JSON. This gets tricky when you embed one JSON document in another, paste JSON into source code, pass it through a shell or store it in a database column. That is when quotes and backslashes start to collide.

This guide covers which characters JSON requires you to escape, how \uXXXX works, and how to turn a whole JSON document into a string literal and unescape it again. It also covers the double-escaping bugs that produce unreadable \\\" sequences. Every example runs as written, and you can test any input in the JSON Escape / Unescape tool as you read.

What escaping a JSON string means

A JSON string is a sequence of characters in double quotes. Some characters have special meaning inside those quotes. A literal double quote would end the string early, and a backslash starts an escape sequence. Escaping replaces them with a safe two-character sequence, \" for a quote and \\ for a backslash, so the parser reads them as data and not as structure.

Escaping takes raw characters and produces the text that goes *between the quotes* of a JSON string. Unescaping does the reverse. It takes an escaped JSON string literal and gives back the original characters. The two are exact inverses, so escaping and then unescaping a value always returns what you started with.

Which characters must be escaped in JSON

The JSON specification (RFC 8259) is strict here. Inside a string you must escape the double quote, the backslash and every control character from U+0000 to U+001F. Common control characters have short escapes. The rest use the generic \uXXXX form.

CharacterEscapeNotes
" (quote)\"Required
\ (backslash)\\Required
/ (forward slash)\/Optional. Valid either way
Backspace\bU+0008
Form feed\fU+000C
Newline\nU+000A
Carriage return\rU+000D
Tab\tU+0009
Other control chars\uXXXXU+0000 to U+001F must be escaped

Everything else can appear literally in a UTF-8 JSON document, including letters, digits, punctuation, emoji and accented characters. The forward slash is the odd one out. It is valid escaped or unescaped, and encoders escape it only to avoid a </script> sequence when JSON is embedded in HTML.

When you need to escape JSON

You need to escape JSON when it passes through another context that also treats quotes or backslashes specially. The common cases:

  • JSON inside JSON. An API envelope has a payload field whose value is a serialized JSON document. The inner document must be escaped to fit inside the outer string.
  • JSON in source code. To paste a JSON fixture into a JavaScript, Python or Go string literal, you escape quotes and backslashes so the compiler reads it as one string.
  • JSON in a shell or environment variable. Passing JSON as a curl body or an env var means dealing with shell quoting and JSON escaping at the same time.
  • JSON in a database column. Storing a raw JSON blob in a text column (not a native JSON column), or inside a larger document in a JSONB field, requires the inner value to be escaped.

The operation is the same each time. You take the JSON text and encode it as one string literal. Only the outer layer you escape *for* changes.

How to escape a whole JSON document into a string

The most common task is turning a whole JSON document into one string so you can embed it somewhere else. In JavaScript, JSON.stringify does this correctly for any string. It returns a valid JSON string literal with every special character escaped.

Embedding a JSON document inside another JSON documentjs
const inner = { name: "Ada", tags: ["a", "b"] };

// 1. Serialize the inner document to text.
const innerText = JSON.stringify(inner);
// innerText === '{"name":"Ada","tags":["a","b"]}'

// 2. Escape that text by placing it in a field of the outer document.
const envelope = { payload: innerText };
const out = JSON.stringify(envelope);

console.log(out);
// {"payload":"{\"name\":\"Ada\",\"tags\":[\"a\",\"b\"]}"}

The inner quotes became \", and the outer JSON now sees the inner document as one opaque string. To read it back, parse the outer document, then parse the payload string a second time to get the object.

JSON Escape / UnescapeOpen the tool→

The tool checks that your input is valid JSON, then encodes it as a string literal. To unescape a JSON string, switch direction and paste the quoted literal. You get readable, indented JSON back. If your input was not valid JSON, the tool tells you.

Escape and unescape JSON in code: stringify and parse

For any plain string, JSON or not, JSON.stringify is the right escaper, because JSON string literals follow the same rules everywhere. Here is the round trip with a Windows path, where the backslashes matter.

Escape and unescape a single string in JavaScriptjs
const path = "C:\\Users\\Ana"; // the 12-char string C:\Users\Ana

const escaped = JSON.stringify(path);
console.log(escaped);
// "C:\\Users\\Ana"   (a valid JSON string literal, quotes included)

const back = JSON.parse(escaped);
console.log(back === path); // true

Python's json module works the same way. json.dumps escapes and json.loads unescapes. By default dumps also escapes non-ASCII characters to \uXXXX. Pass ensure_ascii=False to keep UTF-8 characters literal.

The same round trip in Pythonpython
import json

data = {"name": "Ada", "note": "say \"hi\""}

# Escape: serialize, then embed as a string field.
inner = json.dumps(data)
envelope = json.dumps({"payload": inner})
print(envelope)
# {"payload": "{\"name\": \"Ada\", \"note\": \"say \\\"hi\\\"\"}"}

# Unescape: parse twice.
outer = json.loads(envelope)
restored = json.loads(outer["payload"])
print(restored == data) # True

The double-escaping trap

The most common escaping bug is escaping twice. Each extra JSON.stringify on an already-stringified value doubles the backslashes, and you get values like "{\\\"ok\\\":true}" that no consumer expects.

How double-escaping happens and how to reverse itjs
const obj = { ok: true };

// Correct: escape once.
const once = JSON.stringify(obj);
// '{"ok":true}'

// Wrong: escape the already-serialized string again.
const twice = JSON.stringify(once);
// '"{\\"ok\\":true}"'

// Reversing a double-escaped value takes two parses.
JSON.parse(JSON.parse(twice)); // { ok: true }

This usually happens when a value is already a JSON string by the time your code gets it. A framework or ORM may serialize the field for you, and your own stringify call escapes it again. The symptom is a stored or sent value with runs of \\ where you expected single backslashes.

How to tell how many times a value was escaped

Count the backslashes in front of an inner quote. One escape gives \", two give \\\", and three give \\\\\\\". Each parse removes one layer. If one unescape does not give valid JSON, try another. If you need three or more, fix the code that produces the value instead of adding more parses.

How to escape quotes, slashes, apostrophes and \u0000 in JSON

Most escaping questions are about one character. The forward slash and the apostrophe never need escaping in JSON. The double quote always does. Control characters such as NUL must use a \u escape.

CharacterInside a JSON stringWhat encoders do
Forward slash // or \/. Both are valid and both parse to /JSON.stringify and Python json.dumps leave it alone. PHP json_encode writes \/ unless you pass JSON_UNESCAPED_SLASHES
Apostrophe 'Always literal. \' is not a valid JSON escape and makes the document invalidNever escaped. Escape it for the surrounding context (SQL, shell) instead
Double quote "\" (required)Always escaped
Backslash \\\ (required)Always escaped
NUL U+0000\u0000 (required, and valid JSON)Escaped as \u0000. Some stores, such as PostgreSQL jsonb, reject it
Other control characters\n, \r, \t, \b, \f, or \u00XXJSON.stringify uses the short forms where they exist and \u00XX (for example \u001b) otherwise

Quotes inside an array of stringified JSON

When each element of an array is a JSON document stored as a string, every inner double quote is escaped once. Build it by stringifying each item and then the array. Don't concatenate strings.

An array whose elements are serialized JSON documentsjs
const events = [{ id: 1, type: "click" }, { id: 2, type: "view" }];

// Each element becomes a JSON string, then the array is serialized.
const out = JSON.stringify(events.map((e) => JSON.stringify(e)));
console.log(out);
// ["{\"id\":1,\"type\":\"click\"}","{\"id\":2,\"type\":\"view\"}"]

// Reverse it: parse the array, then parse each element.
const back = JSON.parse(out).map((s) => JSON.parse(s));

If you control the format, use an array of objects ([{"id":1},{"id":2}]) instead of an array of strings. It is smaller, needs no escaping, and consumers can read it with one parse.

Python json.dumps and ensure_ascii

Like every JSON encoder, Python's json.dumps escapes quotes, backslashes and control characters. It also defaults to ensure_ascii=True, which writes every non-ASCII character as \uXXXX (emoji become a surrogate pair). Pass ensure_ascii=False to keep UTF-8 characters readable. The result is still valid JSON, but write it to a file or socket opened with UTF-8 encoding.

ensure_ascii controls non-ASCII escaping. Slashes are never escapedpython
import json

print(json.dumps({"city": "Zürich", "path": "a/b"}))
# {"city": "Z\u00fcrich", "path": "a/b"}

print(json.dumps({"city": "Zürich"}, ensure_ascii=False))
# {"city": "Zürich"}

Unicode and \uXXXX escapes

The \uXXXX escape writes a character as its UTF-16 code unit in four hex digits. JSON only requires it for control characters. Many encoders use it for every non-ASCII character to keep the output pure ASCII, which is safer for older transports and terminals. Both forms parse to the same value, so "café" and "caf\u00e9" are equal strings.

Characters outside the Basic Multilingual Plane, such as most emoji, need a surrogate pair of two \uXXXX escapes. The encoder writes these for you, but it helps to recognize the pattern.

Literal vs. escaped Unicode are equivalentjs
JSON.parse('"caf\\u00e9"') === "café"; // true

// An emoji as a surrogate pair.
JSON.parse('"\\ud83d\\ude80"'); // "🚀"

// JSON.stringify has no ASCII-only option; it keeps BMP
// characters literal by default:
JSON.stringify("café"); // '"café"'

A \uXXXX sequence must have exactly four hex digits. \u1 or non-hex characters are a syntax error. A lone surrogate (one half of a pair) is invalid JSON, though many parsers accept it. If you are unsure, run the value through the escape/unescape tool or a validator to check that it round-trips cleanly.

Frequently asked questions

What does it mean to escape a JSON string?

It means encoding the characters that have special meaning inside a JSON string, so the whole value stays valid JSON. These are mainly the double quote and the backslash, plus control characters. For example, the quotes in he said "hi" become \" so they don't end the string early.

How do I escape JSON in JavaScript?

Call JSON.stringify on the string. It returns a complete JSON string literal, with surrounding quotes and every special character escaped. Call JSON.parse on the result to reverse it. For a whole object, stringify it, put the resulting string in a field of another object, and stringify again. That escapes it once for the outer document.

Why does my JSON have double backslashes like \\\"?

That means the value was escaped twice. It went through JSON.stringify (or json.dumps) two times, and each pass doubles the backslashes. Find the code that serializes the value and make sure only one layer does it. To read a double-escaped value, parse it once for each time it was stringified.

What characters must be escaped in a JSON string?

The double quote (\"), the backslash (\\) and all control characters from U+0000 to U+001F. Common control characters have short forms: \n, \r, \t, \b, \f. You may escape the forward slash as \/ but don't have to. All other printable and Unicode characters can appear literally in UTF-8.

Do I need to escape forward slashes in JSON?

No. You can write the forward slash as / or \/ and both parse to the same character. Some encoders escape it by default, such as PHP's json_encode, to avoid a literal </script> when JSON is embedded in an HTML page. JavaScript's JSON.stringify and Python's json.dumps leave slashes unescaped.

How do I escape an apostrophe (single quote) in JSON?

You don't. An apostrophe is an ordinary character inside a double-quoted JSON string, and \' is not a valid JSON escape, so a strict parser rejects it. If the JSON sits inside a single-quoted SQL literal or shell argument, escape the apostrophe for that outer language (for example '' in SQL), or write it as \u0027 in the JSON.

How do I escape double quotes in JSON?

Put a backslash before each one, as in {"quote": "She said \"hi\""}. In code, let JSON.stringify or json.dumps add the backslashes. In an array of stringified JSON documents, each element contains escaped quotes, like ["{\"id\":1}"], and needs one extra parse per element to read.

What does \u0000 mean in JSON?

It is the escaped NUL character (U+0000). JSON requires all control characters from U+0000 to U+001F to be escaped, so \u0000 is valid JSON, and JSON.stringify produces it for a NUL byte. Some systems still reject it, such as PostgreSQL's jsonb type. Strip NUL bytes before you store text that may contain them.

Does Python json.dumps escape non-ASCII characters?

Yes, by default. ensure_ascii=True turns every non-ASCII character into a \uXXXX escape, so café becomes caf\u00e9. Pass ensure_ascii=False to keep the characters as UTF-8. Both outputs are valid JSON and parse to the same string.

What is the difference between an escaped JSON string and serialized JSON?

Serialized JSON is data written as JSON text, for example {"a":1} from JSON.stringify(obj). An escaped JSON string is that text encoded again as a JSON string literal, "{\"a\":1}", so it can sit inside another JSON value or a string field. Parsing serialized JSON once gives you the object. Parsing an escaped JSON string once gives you the serialized text, and a second parse gives you the object.

How do I unescape a JSON string back to its original form?

Parse the quoted string literal with JSON.parse in JavaScript or json.loads in Python. If the original was a JSON document embedded as a string, parse a second time to get the object. You need one parse for each time the value was escaped.

What is the \uXXXX escape used for?

It writes a character as its UTF-16 code unit in four hex digits, for example \u00e9 for é. JSON requires it for control characters, and many encoders use it for all non-ASCII characters to keep output ASCII-safe. Emoji and similar characters need a surrogate pair of two \uXXXX escapes.