Skip to content
jsonbeautifiers
English

JSON Unescape

Get readable JSON back out of an escaped string, however many layers deep.

Escaped
Decoded

Nothing you paste leaves your browser. The connect-src allowlist makes that a browser guarantee rather than a promise. Check it yourself

Take an escaped JSON string and get the original text back. Surrounding quotes are stripped if present, escape sequences are decoded, and \uXXXX becomes the character it names.

It also counts how many layers of encoding a value has, because a payload that has been JSON-stringified twice is a common API bug and an unreadable one.

Double encoding, and how to spot it

A value that has been serialised, put into a string field, and serialised again arrives looking like a mess of backslashes: "{\"a\":1}". Serialised a third time it doubles again.

This tool detects the number of layers and offers to peel all of them. The usual cause is a service that stores a payload as text and then returns it inside a JSON envelope without decoding it first, or a client that calls stringify on something already stringified.

What it reports rather than guesses

An invalid escape sequence is a warning, not a silent decision. \x41 is not valid JSON, and a tool that quietly turned it into A would be inventing a meaning the document does not have. You get the position and an explanation, and the backslash is dropped so the rest of the text survives.

If the decoded result is itself valid JSON, that is reported too, which is the fastest way to confirm you have finished peeling.

How to do this in code

Unescaping in code.

js JavaScript
// If the value includes its quotes, parse it as a JSON string
const text = JSON.parse('"line one\\nline two"');

// Peel every layer of encoding
function fullyDecode(value) {
  let out = value;
  for (let i = 0; i < 8 && typeof out === 'string'; i++) {
    try { out = JSON.parse(out); } catch { break; }
  }
  return out;
}
py Python

unicode_escape is the answer people find first and it is wrong for anything non-ASCII.

import json

text = json.loads('"line one\\nline two"')

# Standard library, without the surrounding quotes
text = bytes(raw, 'utf-8').decode('unicode_escape')
# Note: unicode_escape assumes Latin-1 for bytes above 127,
# so it mangles non-ASCII. json.loads is the correct route.
sh jq

fromjson is the jq builtin for exactly the double-encoded case.

# Decode a JSON string to raw text
jq -r . <<< '"line one\nline two"'

# Peel a doubly encoded field
jq -r '.payload | fromjson' response.json

Questions

Why does my output still have backslashes?
Because it was encoded more than once. Turn on peel every layer, or run the tool again on its own output until the count reaches zero.
What does it mean when the result is valid JSON?
That the string contained a JSON document rather than plain text. That is the double-encoding case, and the tool says so specifically.