Convert a JavaScript object to JSON
Parsed, never evaluated. Everything JSON cannot hold is listed with its path — not dropped in silence.
- SECURE
- NO UPLOADS
- NO SIGNUP
- BROWSER BASED
- FREE
- FOREVER.
Support us with a link or a share
- Size
- —
- Keys
- —
- Not in JSON
- —
- Depth
- —
Parsed, not run — there is no eval here.
Nothing at the counter yet. Paste a JavaScript object, drop a .js file on the panel, or press Use an example.
Source order keeps the file diffable against the original.
Most converters solve this by running your code
Turning a JavaScript object into JSON is a one-line job if you are allowed to cheat.
Evaluate the text, hand the resulting value to JSON.stringify, print what
comes back. It handles comments, single quotes, unquoted keys, trailing commas and every
other convenience of the language, because the language itself is doing the reading. A
surprising number of online converters do exactly this, and it works right up until it
does not.
The problem is that a JavaScript object literal is not a passive thing. Anywhere a value
can appear, an expression can appear, and an expression can call a function. Paste
{ total: getTotal() } into an evaluating converter and
getTotal runs. Paste an immediately-invoked function and it runs too, with
whatever the page can reach — network access included. This matters because of where these
snippets come from: a colleague's message, a bug report, a Stack Overflow answer, a
minified bundle you are trying to understand. You are pasting it precisely because you do
not yet know what it does. A tool that answers that question by running it has the order
backwards.
This one reads the text character by character and builds a value from what it finds.
There is no eval, no new Function, and no worker that imports
your snippet as a script. A function in the input is recognized as a function and reported
as one; it is never called. That is a smaller promise than "your data never leaves the
browser" — which is also true here — but it is the one that actually protects you, because
code that runs locally still runs.
If your input is a complete program and the goal is a smaller delivery artifact rather than JSON data, use the JavaScript minifier. It keeps Script and Module grammar explicit and runs a printer-only, independently parsed workflow; it does not evaluate the program or reuse this data-literal conversion path.
What a JavaScript object to JSON conversion cannot carry
JSON has exactly six kinds of value: object, array, string, number, boolean and null. A
JavaScript object can contain far more than that, and everything outside those six has
nowhere to go. The usual behavior, and what JSON.stringify itself does, is to
silently discard it — a key whose value is undefined disappears from the
output, a function disappears, and you find out later when something downstream reads a
field that is not there.
Nothing here disappears without a line about it. Every value that cannot cross is listed
with the path it sat at — settings.retry.onError, not just "a function" — plus
the line, the column, and the source text as you wrote it. Alongside each one is what to
substitute: a function becomes the value it returns, an uncalled expression becomes the
value it produces, a regular expression becomes its pattern as a string, and
undefined becomes null if the key should survive at all. Inside
an array the slot becomes null so the indexes do not shift; inside an object
the key is removed. Both of those match what JavaScript does. The difference is that you
are told which one happened and where.
NaN and Infinity get their own treatment: they become
null with a warning, because JSON genuinely has no notation for either and
null is the only defensible substitute. A key that appears twice keeps its last value, as
the language would, and a warning names the key and its line — a duplicate key is nearly
always a merge accident, and the value you see first in the file is not the one you get.
The syntax it accepts
Everything JSON5 allows, plus the shapes people actually paste. Line and block comments.
Single quotes and backticks as well as double. Property names written bare, quoted, or as
numbers, including Unicode names. Trailing commas in objects and arrays. Hexadecimal,
binary, modern octal and legacy octal numbers, numeric separators like
1_000_000, a leading plus sign, and numbers with a leading or trailing decimal
point. BigInt literals keep their numeric spelling but carry a warning because JSON cannot
preserve the BigInt type. Empty slots in an array.
It also strips the wrapper. Real snippets rarely start at the opening brace — they start at
const settings = {, or export default {, or
module.exports = {, and a converter that demands you delete the left-hand
side first is making you do the tedious part of its job. Paste the whole line, semicolon
included. What it will not accept is a second value after the first: JSON holds one
document, so two objects in a row is an error rather than a guess about which one you
meant.
When the input cannot be parsed at all, the message says what was wrong in words. An
unterminated string, an unclosed block comment, a missing colon after a property name and a
missing comma between two values each have their own explanation, and all of them come with
a line number, a column, the surrounding source and a caret under the exact character. This
is the same error reporting as the JSON formatter, for the
same reason: Unexpected token } tells you nothing you did not already
know.
Which direction do you actually want?
The two conversions are not symmetric, and it is worth knowing which side of the asymmetry you are on. JSON to a JavaScript object can always succeed, because everything JSON can express is expressible in JavaScript; the only thing that tool has to be careful about is quoting the property names that need quotes. Coming back the other way is lossy by nature, which is why this page spends most of its effort on telling you what was lost.
If the thing you are converting is a single string value rather than a document — a path, a certificate, a template with line breaks in it — then neither converter is what you want either: the JSON escaper spells one string for a JSON payload and reads that spelling back, which is the smaller and more exact question.
If what you have is already valid JSON and you only want it tidied or sorted, neither tool is the shortest path — the formatter does that without changing the format, and if the question is whether it is valid at all, the JSON validator names the dialect and the character that decided it. And if the destination is a spreadsheet rather than a program, JSON to CSV is the one that flattens the nesting and lets you decide what happens to the arrays.
Nothing leaves this tab
The parser is a few kilobytes of JavaScript running in the page you are reading. There is no upload endpoint, so there is nowhere for your snippet to go. Open your browser's Network tab and paste something in: no request appears. Combined with the fact that nothing you paste is executed, that gives you both halves of the guarantee — the code does not leave, and the code does not run.
Questions
Does this run the JavaScript I paste?
No. The input is read by a parser that walks the text character by character and builds a value from it. There is no eval, no new Function, and no Web Worker that imports your snippet as a script. This matters more than it sounds: several well-known converters do evaluate the input, which means a snippet a colleague sent you, or one copied out of a bug report, executes the moment you paste it in to look at it. In those tools an expression like (() => fetch("https://example.com"))() is not data — it is code that runs. Here it is text that gets reported as unsupported and skipped.
What happens to functions, undefined and dates?
They are reported, never dropped in silence. JSON has exactly six kinds of value — object, array, string, number, boolean and null — so a function, an undefined, a regular expression, a bare variable name or a call like new Date() has nothing to become. The receipt lists each one with the path it sat at, the line and column, and the source text, so you can decide what to substitute. Inside an array the slot becomes null, which is what JSON.stringify does too; inside an object the key disappears, which is also what JSON.stringify does. The difference is that you are told.
Which non-JSON syntax is accepted?
Line and block comments, single quotes and backticks, Unicode or numeric unquoted keys, trailing commas, hexadecimal, binary, modern and legacy octal numbers, numeric separators like 1_000_000, a leading plus, numbers with a leading or trailing decimal point, BigInt literals, NaN and Infinity, and a wrapping declaration such as const data =, export default or module.exports =. That covers JSON5 plus the shapes people actually paste out of a console log or a config file. NaN and Infinity become null with a warning. A BigInt keeps its numeric spelling but gets a warning because JSON cannot keep its type.
What if the same key appears twice?
The last one wins, exactly as it does when JavaScript evaluates the literal, and a warning names the key with its line number. This is worth knowing because a duplicate key is almost always a merge accident, and the value you see first in the source is not the one you get. Plain JSON parsers behave the same way but say nothing about it, which is how a config file can quietly use a setting you thought you had overridden.