Runs on your device · Your file never leaves your device.
Drop a .json file or paste JSON straight from an API response and get a CSV you can open in Excel, Google Sheets or any import screen. A top-level list gives one row per item; otherwise the longest list of records in the document is used, so {"results": [...], "count": 2} gives one row per result; an object with no list in it becomes one row.
The rules are fixed so the result is predictable: nested objects become dot-separated columns (address.city), a list of plain values is joined with semicolons in one cell, and a list of objects inside a record gets numbered columns (items.0.name). The header row is the union of every key found, in the order they first appear, so records with missing fields simply leave a cell empty.
The CSV is written to RFC 4180 — fields with commas, quotes or line breaks are quoted properly — in UTF-8 with an optional byte-order mark so Excel shows every script, accent and symbol correctly. A cell that begins with =, +, - or @ gets an apostrophe in front, so a spreadsheet shows it as text instead of running it as a formula. You see the first 200 lines before downloading, and nothing leaves your device.
Not for: A deeply nested single object with no list inside — it converts, but as one very wide row rather than a table.
A top-level list is the rows. Otherwise the tool looks through the document, up to eight levels deep, for the longest list of objects. So {"response": {"data": {"items": [...]}}} and {"results": [...], "count": 2, "next": null} both give one row per item, and the line under the result names the list it used, such as results. Values beside that list, like count and next, are not part of any record and are left out.
Of two equally long lists, the one nearer the top wins. For a shorter list, copy it from its [ to its ] and paste only that. A document with no list of objects becomes one row, and wrappers with a single key are skipped, so {"order": {"id": 7, "total": 12}} gives the columns id and total.
Text is copied exactly, including dates, which stay in whatever form the JSON has them, such as 2024-01-05T10:00:00Z. true and false are written as words. null, an empty list and an empty object all become an empty cell, so in the CSV they look the same as a field that was missing.
A number is written exactly as the JSON has it: 1.0 stays 1.0, 1e21 stays 1e21, and an ID such as 12345678901234567890 keeps every digit even without quotes. An ordinary JSON reader would turn that ID into 12345678901234567000.
A list of lists is opened one level: "m": [[1, 2], [3]] gives a column m.0 holding 1;2 and a column m.1 holding 3. A list that mixes objects and plain values numbers every entry, so "x": [{"z": 1}, 2] gives x.0.z and x.1.
Column names are made by joining keys with dots, so a key that already contains a dot can meet a nested one: {"a.b": 1, "a": {"b": 2}} would make a.b twice. The second gets a suffix, so the columns are a.b and a.b_2 and both values are kept.
Comma is the usual choice. Semicolon suits a spreadsheet set to a language that writes decimals with a comma, where a comma-separated file often opens in a single column. Tab and pipe are for systems that ask for them. Whatever the separator, the file is named .csv.
A cell that begins with =, +, - or @ is a formula to a spreadsheet, which would run it on opening. Such a cell gets an apostrophe in front, the mark spreadsheets themselves use for "this is text", so =1+1 is written as '=1+1. Plain numbers such as -5 or +3.5 are left as they are.
This page in other languages: العربية · Deutsch · Français · Español · Русский · Português · 中文 · हिन्दी · Türkçe · עברית · فارسی · اردو · Bahasa Indonesia · বাংলা