Escape and unescape JSON strings

Turn arbitrary text — a stack trace, a Windows path, a regular expression, a multi-line note — into a JSON string literal that will parse, and turn an escaped literal back into readable text. Both directions run in this tab; nothing you paste is uploaded.

String escaper

Result

          

Escape & quote gives you a complete string literal including the surrounding double quotes, ready to drop in as a JSON value. Escape only gives you the same thing without the quotes, for when you are pasting into an existing pair. Unescape reverses either form.

Check a whole document

If you have a full JSON document rather than one string, use the formatter below — it will tell you exactly which escape sequence is wrong and where.

Indent

Nothing you paste is uploaded. Escaping is JSON.stringify, unescaping is JSON.parse, and both run in your browser. There is no upload endpoint and no stored copy. Why that matters →

The complete list of JSON escapes

Inside a JSON string, exactly three characters must be escaped: the double quote, the backslash, and any character below U+0020. Everything else may appear literally, although two more have optional escapes.

EscapeCharacterRequired?Notes
\"Double quote, U+0022YesOtherwise it ends the string.
\\Backslash, U+005CYesOtherwise it starts an escape.
\/Forward slash, U+002FNoLegal but never necessary. Exists so that </script> can be written <\/script> inside an HTML page.
\bBackspace, U+0008YesControl character.
\fForm feed, U+000CYesControl character.
\nLine feed, U+000AYesThe one you will meet daily.
\rCarriage return, U+000DYesWindows line endings are \r\n.
\tTab, U+0009YesControl character.
\uXXXXAny code unitOnly for other controlsExactly four hex digits. Case-insensitive.

Every other control character below U+0020 — U+0000 through U+001F, minus the five with named escapes — must be written in the \u form: \u0000 for NUL, \u001b for the escape character that begins an ANSI colour code in a captured terminal log.

Sequences that do not exist in JSON, however familiar they look from other languages:

Not JSONWhere it is fromWrite instead
\x41C, JavaScript, PythonA
\0C, JavaScript\u0000
\'C, JavaScript, Python' — no escape needed
\vC vertical tab\u000b
\aC bell\u0007
\u{1F600}ES6 code-point escape😀 or \ud83d\ude00
\N{…}Python named escape\uXXXX

Characters above the basic plane

JSON strings are sequences of UTF-16 code units, so a character outside the Basic Multilingual Plane — every emoji, many CJK extension characters, historic scripts — needs a surrogate pair when written in escaped form.

"😀"                 // literal, perfectly valid
"\ud83d\ude00"   // the same character, as a surrogate pair
"\u{1F600}"          // NOT valid JSON — that is JavaScript syntax

You will almost never write these by hand. Serialise with your language’s JSON library and it handles the pairing; the escaper above does the same. It matters when you are reading someone else’s output and wondering why a single emoji appears as two escapes, or why a string with a “length” of 2 displays as one character.

One consequence worth knowing: a lone surrogate — "\ud800" with no low partner — is accepted by the JSON grammar and by JSON.parse, even though the resulting string cannot be encoded as valid UTF-8. If such a value reaches a strict consumer, or a database with a UTF-8 column, it will be rejected there instead. Validate at the boundary if you accept untrusted text.

Worked examples

1. A Windows path

Invalid
{"path": "C:\Users\new\test.txt"}
Valid
{"path": "C:\\Users\\new\\test.txt"}

The invalid version has two separate problems. \U is not a legal escape, so the parser rejects it outright — that one you find immediately. But \new begins with \n, which is legal, so if the path had been C:\new\file the document would parse cleanly and give you a string containing a newline character followed by ew. A path that silently becomes wrong is far more expensive than one that fails loudly.

Forward slashes work on Windows in almost every API, and need no escaping at all. Where you cannot use them, double every backslash — or paste the raw path into the escaper above and let it do the counting.

2. A multi-line value

JSON has no triple-quoted or multi-line string. A note, a log excerpt, a PEM-encoded certificate or an SSH key must be collapsed into one line with \n escapes:

{"key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADAN...\n-----END PRIVATE KEY-----\n"}

Paste the raw multi-line text into the escaper above, press Escape only, and you get exactly that, with the trailing newline preserved. Note that a certificate pasted from a Windows file will contain \r\n; some parsers of the resulting PEM care, so check which line endings you actually escaped.

3. Double-encoded JSON

{"payload": "{\"id\":1,\"name\":\"Ada\"}"}

The value of payload is a string that happens to contain JSON. Parsing the outer document gives you the text {"id":1,"name":"Ada"}, not an object; you have to parse again.

This is produced by calling json.dumps or JSON.stringify twice, by storing a JSON document in a string column and re-serialising it on the way out, or by a message queue that wraps every payload. Copy the inner value into the escaper above and press Unescape to see what is really inside, then fix the producer — double encoding roughly doubles the byte cost of the nested part, defeats schema validation on it, and forces every consumer to know about the extra layer.

4. A quoted quote

Invalid
{"quote": "She said "hello" loudly"}
Valid
{"quote": "She said \"hello\" loudly"}

The invalid version parses as the string "She said " followed by the bare word hello, at which point the parser gives up. The error is reported at hello, not at the quote that caused it — another case where the fault lies before the caret.

Escaping in your own code

The correct answer, in every language, is: do not do it by hand.

// JavaScript — JSON.stringify on a string produces a complete literal
JSON.stringify('C:\\Users\\new')       // "\"C:\\\\Users\\\\new\""
JSON.stringify(text).slice(1, -1)      // the same, without the outer quotes
# Python
import json
json.dumps(text)                       # complete literal, with quotes
json.dumps(text, ensure_ascii=False)   # keep é and 😀 literal instead of \u-escaping
# Shell, using jq — -R reads raw text, -s slurps all lines into one string
printf 'line one\nline two' | jq -Rs .

Python’s ensure_ascii deserves a moment. It defaults to True, which escapes every non-ASCII character as \uXXXX. The output is valid, transport-safe over any 7-bit channel, and considerably larger — a document of Japanese text can grow by a factor of three. Setting it to False writes the characters literally, which is smaller and readable, and is safe as long as everything downstream agrees the encoding is UTF-8.

What you should never do is build a JSON string with string concatenation or a template, replacing quotes with a regular expression as you go. Every escaping bug on this page comes from exactly that. Build a value; serialise it.

JSON escaping is not HTML escaping

They solve different problems and do not substitute for one another. JSON escaping makes text survive a JSON parser. HTML escaping makes text survive an HTML parser. A string that is correctly JSON-escaped can still carry <script> tags, because < means nothing special to JSON.

If you take a value out of a JSON document and put it into a page, you must escape it for HTML at that point — or better, avoid the question entirely by assigning to textContent rather than innerHTML. That is what this page does with everything you paste, which is why a value containing <img src=x onerror=alert(1)> shows up here as those literal characters and nothing happens.

The one place the two do interact: </script> inside a JSON string embedded in an inline <script> block will end the block early, because the HTML tokenizer runs first and does not know it is inside a string. That is exactly what the optional \/ escape exists for. Writing <\/script> keeps the JSON identical and stops the HTML parser closing your tag.

Frequently asked questions

Do I have to escape forward slashes?

No. \/ is legal but never required, and "https://example.com" is perfectly valid unescaped. Some serialisers — notably PHP’s json_encode by default — escape it anyway, which is why you see https:\/\/example.com in the wild. Both parse to the same string. PHP’s JSON_UNESCAPED_SLASHES flag turns it off.

Do I have to escape single quotes?

No, and you must not try: \' is not a valid JSON escape and will be rejected. Inside a JSON string an apostrophe is an ordinary character. The confusion comes from JavaScript and Python, where \' is meaningful because those languages allow single-quoted strings. JSON does not.

Why does my string contain \u00e9 instead of é?

Because the producer escaped non-ASCII characters. Python’s json.dumps does this by default (ensure_ascii=True), and several Java and PHP configurations do too. It is entirely valid — \u00e9 and é parse to the identical string — just larger and harder to read. Paste it into the escaper above and press Unescape to see the text.

How do I put a newline in a JSON string?

Write the two characters backslash and n. A real line break inside a JSON string is a syntax error, because JSON has no multi-line string form. If you are writing the document by hand in an editor, paste the multi-line text into the escaper above and use the escaped result.

What is the maximum length of a JSON string?

The specification sets no limit. In practice you hit the implementation first: JavaScript engines cap a single string at roughly 229 characters in V8, and your available memory well before that. Any single JSON value in the hundreds of megabytes is a sign the data belongs somewhere other than a JSON string.

Can I use JSON escaping to make user input safe?

Only against JSON parsing problems. It does nothing about SQL injection, HTML injection, shell injection, or path traversal — each of those needs its own contextual handling at the point where the value is used. Escaping is per-context, never global. The correct habit is to keep data as data all the way through and let the API you are calling do the quoting: parameterised SQL statements, textContent rather than innerHTML, argument arrays rather than shell strings.

Is the text I paste here sent anywhere?

No. Escaping calls JSON.stringify and unescaping calls JSON.parse, both in your browser. There is no upload endpoint and nothing is stored. Neither operation uses eval or the Function constructor — unescaping runs through the JSON parser, so a hostile input is read as data and never executed.

Related pages

Related tools