Unescape JSON String

Examples:

Last updated: 2026-09-17

Paste an escaped JSON string — like the kind you get from API responses or database fields — and this tool unescapes it back to real JSON. It auto-detects how many levels of escaping are present and shows you the count. Everything runs locally.

What this tool does

Takes an escaped JSON string — where double quotes, backslashes, and control characters are prefixed with backslashes — and unescapes it back to readable JSON. The tool detects multiple layers of escaping (double, triple, or more) and unescapes all of them in one pass, reporting how many levels were removed.

Under the hood, the tool calls JSON.parse repeatedly. Each call peels off one layer of string escaping. The first parse turns an escaped string literal into its inner content. If that content is itself a quoted string literal, the tool parses again, and so on. This repetition is what makes it possible to handle arbitrary nesting depths in a single operation rather than forcing you to run the same conversion manually several times.

Everything runs locally in your browser. The input never leaves your machine, which matters when you are debugging fields that contain credentials, tokens, or other sensitive material copied from production systems.

Example

Input (single-escaped):

"{\"name\":\"test\",\"value\":42}"

Output:

{"name":"test","value":42}

Input (double-escaped):

"\"{\\\"name\\\":\\\"test\\\"}\""

Output (after 2 levels of unescaping):

{"name":"test"}

The tool reports “Unescaped 2 levels” so you know the depth of escaping.

Escape sequence reference

SequenceUnescaped toMeaning
\""Double quote
\\\Backslash
\nnewlineLine feed
\ttabHorizontal tab
\rcarriage returnCarriage return
\uXXXXUnicode characterCode point

Sequences outside this set — such as backslash-b or backslash-f — are not defined by the JSON specification. The tool leaves them untouched rather than inventing a meaning.

How the output is displayed

The unescaped result appears in a separate panel beside or below the input editor, so your original pasted text stays intact for reference. A depth badge sits next to the output, stating how many levels were stripped. If parsing fails at some point, the tool shows the partially unescaped text together with an explanatory note describing where the parse stopped, rather than silently discarding your input or showing a blank result.

A copy button lets you grab the cleaned JSON for pasting into a database console, a code editor, or a test fixture. Because the output is genuine JSON, you can feed it directly into validators, formatters, or downstream scripts without any intermediate cleanup.

Where double-escaping comes from

Double-escaping happens when a JSON string is itself serialized as JSON. Common sources:

Do it in code

JavaScript:

// Single level: JSON.parse the quoted string
const unescaped = JSON.parse(escapedString);
// If the result is still a JSON string, parse again
const result = JSON.parse(unescaped);

A safe general-purpose loop that mirrors what this tool does internally:

function unwrap(s, maxDepth = 10) {
  let current = s;
  let depth = 0;
  while (typeof current === 'string' && depth < maxDepth) {
    let parsed;
    try {
      parsed = JSON.parse(current);
    } catch (e) {
      break; // not a parseable JSON string, stop
    }
    current = parsed;
    depth++;
  }
  return { value: current, depth };
}

The try/catch around JSON.parse is what stops the loop cleanly when the string is no longer JSON. Without it, a parse error throws an uncaught exception. The maxDepth guard prevents infinite loops on pathological input and mirrors the tool’s own 10-level cap.

Python:

import json
# Single level: json.loads the quoted string
unescaped = json.loads(escaped_string)
# If still a JSON string, parse again
result = json.loads(unescaped)

CLI (jq):

echo '"{\"name\":\"test\"}"' | jq -r '.'

Edge cases handled

Depth reference table

DepthMeaningTypical source
0Input was already valid JSONNo escaping present
1One layer of string escaping removedAPI embedding JSON as a string field
2Two layers removedDatabase export re-serializing a JSON column
3Three layers removedLog aggregator adding a layer on top of an already-double-escaped field
4+Four or more layers removedMulti-hop messaging pipeline or repeated re-ingestion

Use this table as a sanity check when you paste a field. If the reported depth is higher than the source column suggests, something between the origin and your clipboard added extra serialization passes.

Unescaping log aggregations

Log aggregation pipelines — Elasticsearch, Splunk, Datadog, Loki, and similar systems — routinely serialize log fields as JSON strings during ingestion. When a log entry already contains a JSON payload, the aggregator wraps that payload in quotes and escapes the inner double quotes. If the log then passes through another pipeline stage that serializes the entire record again, the escaping compounds. The result is a field that looks like a wall of backslashes when you inspect it in a query console or dashboard.

Example — a triply-escaped log field as it arrives from the aggregator:

Input (three levels of escaping):

"\"\\\"{\\\\\\\"event\\\\\\\":\\\\\\\"login\\\\\\\",\\\\\\\"userId\\\\\\\":8842}\\\"\""

Output (after 3 levels of unescaping):

{"event":"login","userId":8842}

The tool reports “Unescaped 3 levels.” Each pass of JSON.parse strips one layer of backslash-escaping. The first pass removes the outermost quotes and unescapes the doubled backslashes, revealing a doubly-escaped string. The second pass unescapes again, and the third pass produces the final readable JSON object. This is exactly what the tool automates — you paste the mangled field and get clean JSON without manually counting escape levels or writing a recursive parser.

A triply-escaped field typically means the original event payload was serialized by the application, then wrapped again by the logging framework, then wrapped a third time by the aggregator’s ingestion pipeline. Recognizing this pattern helps you trace where each layer was added so you can fix the serialization at the source rather than unescaping on the receiving end every time you query.

When debugging log ingestion, paste the raw field value into the tool before writing any parsing code. The reported depth tells you exactly how many components in the pipeline re-serialized the payload, which narrows down which stage introduced the problem.

Different aggregators compound escaping differently. Elasticsearch with the default JSON codec escapes once during indexing. Splunk’s HEC (HTTP Event Collector) can add a second layer if the event source already serialized the payload and the collector does not detect the existing escaping. Datadog’s log intake adds escaping when the message attribute contains embedded JSON. Loki’s Promtail agent rarely adds escaping on its own, but downstream consumers that re-ingest Loki query results often do. Knowing which platform you are querying helps predict the expected depth before you even paste the field — a depth that exceeds the platform’s normal count points to a misconfigured source or an extra relay hop that should not exist.

Windows line endings deserve a mention here. Log fields captured from Windows services often contain carriage return plus line feed pairs. In escaped JSON these become backslash-r backslash-n sequences. After unescaping, they become actual control characters in the output. If your downstream consumer expects Unix-style line endings only, normalize the carriage returns separately after unescaping, because the tool faithfully restores them as genuine control characters matching the original payload.

Unescaping LLM output

Large language models like ChatGPT and Claude sometimes return JSON wrapped inside a markdown code fence, and that JSON may itself contain string fields whose values are escaped JSON. When you capture the model’s response programmatically through the API, the outer serialization layer the provider adds can turn the whole content into a multiply-escaped string before it reaches your code.

Example — an LLM response where the model returned a JSON object describing a function call, and the API wrapper serialized the content field:

Input (the content field from the API response, triple-escaped):

"\"\\\"{\\\\\\\"function\\\\\\\":\\\\\\\"createUser\\\\\\\",\\\\\\\"args\\\\\\\":\\\\\\\"{\\\\\\\\\\\\\\\"name\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"Ada\\\\\\\\\\\\\\\"}\\\\\\\"}\\\"\""

Output (after 3 levels of unescaping):

{"function":"createUser","args":{"name":"Ada"}}

The tool reports “Unescaped 3 levels” — one layer from the API content serialization, one from the model wrapping its JSON output in a string, and one from the inner args field being stored as an escaped JSON string inside the outer object.

When building pipelines that parse LLM output, run the model response through this tool before attempting schema validation. It handles the nested escaping that breaks naive JSON.parse calls, so your downstream code receives properly structured objects instead of raw string fragments that fail your type checks.

A practical workflow: extract the content string from the API response, paste it into the tool, confirm the depth count, then copy the clean JSON into your application. If the depth is consistently higher than expected, check whether your API client or SDK is adding an extra serialization layer around the response body.

Streaming responses add another wrinkle. When you read a streamed chat completion incrementally, the final assembled content string is sometimes double-escaped because the streaming buffer concatenates chunks that were each individually serialized. If your assembled stream output fails to parse, run it through the tool first — the depth counter will reveal whether the stream assembly introduced an extra wrapping layer. Function-calling and tool-use responses are especially prone to this because the arguments field is itself a JSON string embedded inside the function call object, so the arguments alone may need one or two levels of unwrapping before you can use them.

Some providers return tool-call arguments as a separate escaped string property rather than a nested object. That means even after you parse the outer response, the arguments remain escaped. The tool handles this gracefully — paste the arguments value, read the reported depth, and you get the structured arguments object ready to pass into your application logic.

Common mistakes when unescaping

What the depth counter means

The depth counter reports how many successive JSON.parse calls the tool performed before the result was no longer a quoted string. Each level corresponds to one serialization pass that was applied somewhere upstream in the data pipeline.

Here is how the detection works step by step. The tool takes the input and attempts to parse it as a JSON string value. If the parse succeeds and the result is still a string — meaning it is surrounded by quotes or is itself another escaped JSON string — the tool increments the counter and parses the result again. It repeats this cycle until the parsed result is a non-string JSON value (an object, array, number, boolean, or null), or until the parse fails, or until it reaches the maximum of 10 levels.

A depth of 0 means the input was already valid, unescaped JSON — no parsing was needed and the content is returned unchanged. A depth of 1 means one layer of string escaping was removed, which is what you get from a standard API that embeds JSON as a string field. A depth of 2 means two layers were removed, typical of a database export that serialized an already-serialized column value. A depth of 3 or higher usually points to a logging or messaging pipeline where multiple independent components each re-serialize the same payload as it passes through.

The counter is displayed alongside the output so you can immediately see how deeply nested the escaping was. If the counter shows a number you did not expect, that is a signal to inspect the upstream serialization chain — each extra level represents a component that wrapped the payload in an unnecessary string conversion, and removing that conversion at the source will simplify every downstream consumer.

One subtlety worth understanding: the depth counter counts successful parse passes, not the raw number of backslash characters in the input. A string with a hundred backslashes might still only unescape one level deep if those backslashes all belong to a single serialization layer. Conversely, a string with relatively few visible backslashes could unescape three levels deep if each layer was thin. The depth is determined by structural nesting, not by backslash density, so never estimate the nesting by eyeballing the input.

Another subtlety: when the tool reaches a non-string value (an object, array, number, boolean, or null), it stops incrementing immediately even if that value contains string properties that are themselves escaped. The depth counter reflects how many times the top-level value was unwrapped, not how many escaped substrings exist inside the final object. If a property inside your unescaped object is still a quoted JSON string, paste that property value into the tool separately to unwrap it further. This two-step approach is common with LLM tool-call arguments and with database columns that store JSON inside JSON.

Frequently asked questions

What is an escaped JSON string?
When JSON is stored as a string value inside another JSON object, all the double quotes inside it must be escaped with backslashes. For example, {"key": "{\"a\":1}"} — the inner JSON is an escaped string. This is common in API responses that embed JSON as a string field.
How does auto-detect depth work?
The tool repeatedly unescapes the string and checks if the result is still valid JSON or another escaped string. Each successful unescape increments the depth counter until no more escaping is detected, up to a maximum of 10 levels.
What causes double or triple escaping?
Multiple layers of serialization. If a JSON string is stored in a database field that is itself serialized as JSON, you get two levels. APIs that return JSON inside JSON string values are a common source. Log aggregators that re-serialize fields can add another level.
Can I unescape a string that is not JSON?
The tool attempts to unescape any backslash-escaped string, but it is designed for JSON. If the unescaped result is not valid JSON, the tool shows it as-is with a note. The escape sequences handled are the standard JSON ones: backslash, quote, newline, tab, carriage return.
Does unescaping modify my original data?
No. The original input is preserved in the editor. The unescaped output appears in a separate panel. You can copy it or format it without affecting the input.
How do I unescape a JSON string in JavaScript?
Use JSON.parse on the quoted string. If the result is itself a JSON string, call JSON.parse again. This tool automates that repeated parsing — it detects how many levels of escaping are present and unwraps them all in one pass.
What is the maximum depth the tool can detect?
The tool detects and unwraps up to 10 levels of escaping. If your string is escaped more than 10 layers deep, the tool stops at the cap and reports that count. Strings nested that deeply almost always indicate a bug in an upstream serialization pipeline rather than legitimate data. If you hit the limit, investigate the system that produced the string to find where the repeated wrapping is happening.
Why does my unescaped output still contain backslashes?
If backslashes remain after unescaping, they are probably literal backslash characters in the original data, not escape sequences. A real backslash in a JSON string value is represented as a doubled backslash. When the tool unescapes one level, a doubled backslash becomes a single backslash, which is the correct literal value. If you see backslashes that look like escape sequences, you may need another level of unescaping — check the reported depth count to confirm.

Related tools