JSON Escape / Unescape

Turn any text into a JSON string body you can paste between quotes, or take an escaped string from a log line and get the readable text back. Quotes, backslashes, line breaks and emoji are handled the way JSON.stringify does, and if your input was escaped twice, the tool says so.

Plain Text
JSON String

1 JSON Escape / Unescape example

Plain text

Invoice #1042 for "Zoë Müller"
Path: C:\invoices\2026\
Note:	tab-separated, total €49.90 😀

Escaped, wrapped in quotes

"Invoice #1042 for \"Zoë Müller\"\nPath: C:\\invoices\\2026\\\nNote:\ttab-separated, total €49.90 😀"

With Non-ASCII as \uXXXX turned on, the same input comes out as pure ASCII. The emoji becomes a surrogate pair, two escapes for one character, because JSON escapes are UTF-16 code units:

"Invoice #1042 for \"Zo\u00eb M\u00fcller\"\nPath: C:\\invoices\\2026\\\nNote:\ttab-separated, total \u20ac49.90 \ud83d\ude00"

2 What JSON requires

Must escape

The double quote, the backslash, and every control character below U+0020. That is the whole list in RFC 8259. Newline and tab are control characters, which is why a raw line break inside a JSON string is a syntax error.

May escape

Anything else, as \uXXXX. Use it when the JSON has to pass through a system that mangles non-ASCII bytes. It makes the payload bigger (six bytes for é instead of two) and changes nothing once parsed.

The forward slash

\/ is legal but optional. PHP's json_encode() adds it by default so that a string containing </script> cannot close a script tag early. JSON.stringify leaves it unescaped.

Not allowed

Single quotes around the string, \' , \x41 and octal escapes. Those are JavaScript string syntax, not JSON, and a strict parser rejects them. For those, use the backslash escape tool.

3 Double-escaped strings

If a log shows {\"id\":1}, a value that was already a JSON string was encoded again. It happens when a JSON body is stored in a JSON column, or when a message queue wraps the payload and the producer serialized it first. Unescape it once and you get another escaped string. When that happens here, an Unescape again button appears and peels off the next layer.

Fix double encoding where it starts. Decode the right number of times in code, or better, stop encoding twice. When the result of the last layer is a JSON document rather than a string, the note under the tool says so, and the JSON formatter is the next stop.

How to use the JSON Escape / Unescape tool

  1. Pick Escape or Unescape in the Mode dropdown.
  2. Paste your text into the left panel. The result on the right updates as you type.
  3. When escaping, tick Wrap in quotes for a complete JSON string literal, Non-ASCII as \uXXXX for ASCII-only output, and Escape / to match PHP's default.
  4. When unescaping, a red message shows the line and column of any invalid escape. If the result is still escaped, click Unescape again.
  5. Swap moves the output into the input and flips the mode, which is a quick round-trip check. Copy Result copies the output.

How to escape and unescape JSON strings in JavaScript, PHP and Python

JavaScript

const text = 'He said "hi"\nC:\\temp 😀';

// Escape: JSON.stringify adds the surrounding quotes
const quoted = JSON.stringify(text);
console.log(quoted); // "He said \"hi\"\nC:\\temp 😀"
const body = quoted.slice(1, -1); // just the part between the quotes

// ASCII-only: escape everything above 0x7E as \uXXXX (UTF-16 units)
const ascii = quoted.replace(/[\u007f-\uffff]/g,
    (c) => "\\u" + c.charCodeAt(0).toString(16).padStart(4, "0"));
console.log(ascii); // "He said \"hi\"\nC:\\temp \ud83d\ude00"

// Unescape: JSON.parse needs the quotes back
console.log(JSON.parse('"' + body + '"') === text); // true

JSON.stringify never escapes non-ASCII, so the regex step is only needed when the output must be pure ASCII.

PHP

<?php
$text = "He said \"hi\"\nC:\\temp 😀";

// Default: escapes / and every non-ASCII character
echo json_encode($text), PHP_EOL;
// "He said \"hi\"\nC:\\temp \ud83d\ude00"

// Readable output, same as JavaScript
echo json_encode($text, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), PHP_EOL;

// Unescape. JSON_THROW_ON_ERROR turns a silent null into an exception.
$back = json_decode('"He said \"hi\""', false, 512, JSON_THROW_ON_ERROR);
echo $back, PHP_EOL; // He said "hi"

Without JSON_THROW_ON_ERROR, json_decode() returns null on bad input, which is indistinguishable from a valid null.

Python

import json

text = 'He said "hi"\nC:\\temp 😀'

print(json.dumps(text))                      # ensure_ascii=True: \ud83d\ude00
print(json.dumps(text, ensure_ascii=False))  # keeps the emoji

body = json.dumps(text)[1:-1]
print(json.loads('"' + body + '"') == text)  # True

# Double-encoded: keep decoding while the result is still a string
value = json.loads(json.dumps(json.dumps({"id": 1})))
while isinstance(value, str):
    value = json.loads(value)
print(value)  # {'id': 1}

Common errors and how to fix them

SyntaxError: Bad control character in string literal
The string contains a raw line break or tab. JSON requires them escaped as \n and \t. Escape the text first, or fix whatever built the JSON by string concatenation.
SyntaxError: Bad escaped character (or Invalid \escape)
A backslash is followed by something JSON does not allow, often a Windows path like C:\temp or JavaScript-only escapes such as \' and \x41. Double the backslash, or escape the value with a JSON encoder instead of by hand.
The output is full of \\\" sequences
The data was JSON-encoded twice. Decode twice, or better, find the place that encodes a value that is already a JSON string and pass the object instead.
json_decode() returns null for a string that looks fine
Check json_last_error_msg(), or pass JSON_THROW_ON_ERROR. The usual causes are invalid UTF-8 bytes and single quotes used as string delimiters.

Good to know

RFC 8259 keeps this short: a string is zero or more characters between double quotes, where the quote, the backslash and U+0000 to U+001F must be escaped, and anything may be written as \u followed by four hex digits. There is no \x, no octal, no \', and no single-quoted strings.

JSON.stringify has escaped lone surrogates since ES2019 (well-formed JSON.stringify), so a broken half of an emoji comes out as a visible \uD83D rather than invalid UTF-8. This tool does the same.

Specifications and references

This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.

Frequently Asked Questions

Which characters have to be escaped in a JSON string?

Three kinds: the double quote, the backslash, and control characters below U+0020 such as newline and tab. Everything else, including emoji, may appear as-is in UTF-8 JSON.

Why does the emoji turn into two \u escapes?

JSON escapes are UTF-16 code units, and characters above U+FFFF need a surrogate pair. JSON.parse and every other conforming parser joins the pair back into one character.

Do I need to escape the forward slash?

No. \/ is allowed but optional. PHP's json_encode() adds it by default so that </script> inside a string cannot end an inline script block. Tick Escape / to match PHP's output.

Can I paste the string with its surrounding quotes?

Yes. Unescape mode accepts the string with or without the outer double quotes, and it reports the line and column of the first invalid escape or stray quote.

Why do I get backslashes again after unescaping?

The value was encoded twice, for example a JSON body stored inside another JSON field. The tool detects this and shows an Unescape again button that peels off the next layer.

Related escaping tools

For string literals in other languages, the backslash escape tool covers JavaScript, Python, PHP, Bash and SQL. To validate or pretty-print the whole document use the JSON formatter, and for text headed into HTML or a URL there is the HTML encoder and the URL encoder.

More Encoders & Decoders

Browse all encoders & decoders

Copied to clipboard!