JSON Escape and Unescape

Turn any text into a valid JSON string literal, or decode a JSON string back to the raw text.

JSON string

Overview

Text can only go inside a JSON document as a string literal: wrapped in double quotes, with quotes, backslashes and control characters replaced by escape sequences. You need this conversion when you put a stack trace into a bug report payload, store a template or SQL query in a config file, write a test fixture by hand, or send a message body to an API that wraps it in JSON. Unescaping is the reverse. It turns "line 1\nline 2" from a log or API response back into text you can read.

In Escape mode the tool uses JSON.stringify, so the output is exactly what JavaScript would produce. You can drop the surrounding quotes, or write every non-ASCII character as \uXXXX for systems that only accept 7-bit text. In Unescape mode a strict parser reads the literal, with or without quotes, and reports the line and column of any invalid escape. Both directions update as you type and run entirely in your browser.

Which characters must be escaped in JSON

RFC 8259 section 7 requires escapes for only three things: the quotation mark, the backslash and the control characters U+0000 through U+001F. Everything else, including every emoji and non-Latin script, may appear as-is.

CharacterEscapeRequired?
Quotation mark "\"Yes, it would end the string
Backslash \\\Yes, it starts every escape
Line feed, carriage return, tab\n \r \tYes (control characters)
Backspace, form feed\b \fYes (control characters)
Other U+0000–U+001F\u0000 … \u001fYes, no short form exists
Solidus /\/No, optional
Any other character\uXXXXNo, optional

Characters outside the Basic Multilingual Plane are written as a UTF-16 surrogate pair, so 🚀 (U+1F680) escapes to 🚀. JSON has no \u{1F680} syntax. A lone surrogate such as \ud800 is syntactically valid JSON but does not represent real Unicode text. Since ES2019, JSON.stringify writes unpaired surrogates as escapes so the output stays valid UTF-8. When unescaping produces one, this tool warns you.

JSON escaping is not JavaScript, HTML or URL escaping

JSON escapes look like JavaScript escapes, but the set is much smaller. Escapes that are valid in a JS string literal are errors in JSON:

"\x41"       // JS: "A"      JSON: invalid, use "A"
"it\'s"      // JS: "it's"   JSON: invalid, ' needs no escape
"\u{1F680}"  // JS: "🚀"     JSON: invalid, use "🚀"
"\v" "\0"    // JS: valid    JSON: invalid, use "\u000b" "\u0000"

JSON escaping also does nothing to make text safe for another context. A JSON string can legally contain </script> or <img onerror=…>. To put JSON inside HTML you also need HTML escaping, or < for every <. To put it into a query string you need percent-encoding, which the URL encoder handles. Each layer needs its own escaping, applied once, in order from the inside out.

Double escaping: why \\n shows up in your logs

If a log line or API response contains literal \n and \" where you expected line breaks and quotes, something serialized the data twice. A common way it happens:

const body = JSON.stringify({ msg: "a\nb" });  // {"msg":"a\nb"}
logger.info(JSON.stringify(body));
// "{\"msg\":\"a\\nb\"}"

The second JSON.stringify treats the already-encoded text as a plain string, so every quote gets a backslash and every existing backslash is doubled. The fix belongs in the code: pass the object to the logger, not a pre-serialized string. To read output that is already double-escaped, paste it here in Unescape mode. If the status says the result still contains escape sequences, press Swap to move the output into the input, then click Unescape again. Each pass removes one layer.

Embedding JSON inside a JSON string

Sometimes the double layer is intentional. AWS API Gateway proxy integrations deliver the request body to a Lambda function as a string in event.body. Many webhook and queue formats likewise wrap a JSON document in a string field of an outer envelope:

{
  "type": "order.created",
  "payload": "{\"id\":\"ord_81\",\"total\":49.5}"
}

The consumer has to decode twice: JSON.parse(JSON.parse(raw).payload). To write such a fixture by hand, minify the inner document with the JSON minifier, escape it here, and paste the result as the value. Don't build it with string concatenation. A single unescaped quote inside the inner document breaks the outer one, and the JSON validator will only show an error at the place where the outer string ended too early.

Frequently Asked Questions

Do I need to escape forward slashes in JSON?

No. \/ is allowed but never required, and JSON.stringify doesn't produce it. Some serializers escape / so that </script> can't appear inside JSON embedded in HTML. Both forms parse to the same string.

Do single quotes need escaping?

No. JSON strings are always delimited by double quotes, so an apostrophe is an ordinary character. Writing \' is an error in JSON even though JavaScript accepts it.

When should I escape non-ASCII characters?

Only when the receiving system can't handle UTF-8, such as some legacy databases, old HTTP clients or files that are later opened with the wrong encoding. JSON exchanged between systems must be UTF-8, so raw characters are normally correct and also shorter.

Why do I get "Raw control character" when unescaping?

A real newline or tab inside a JSON string is invalid. It has to appear as \n or \t. This usually means the text was never escaped in the first place, so switch to Escape mode instead.

Is the text I paste stored or uploaded?

It's not uploaded. Conversion runs in your browser. The input is saved in this browser's local storage so it survives a reload. Click Clear to remove it.