Local browser utility · Examples and limits included

CSV to JSON

Convert CSV into JSON in your browser with correct handling of quoted fields, embedded commas and newlines, and a plain report of any malformed rows.

1. Paste your CSV data

Enter or paste your CSV data below. You can also drag and drop a .csv file.

2. CSV options

Choose the delimiter and parsing options.

Delimiter

Good to knowQuoted fields are parsed properly — a comma, a line break or a doubled quote inside "…" stays part of its field. Rows that do not fit the header are converted and listed, never dropped.

3. JSON output

Your JSON result appears here as you type.

Paste CSV on the left to see the JSON here.

What the result contains

What This Tool Provides

Convert CSV into JSON in your browser, with the quoting rules handled properly: a comma inside a quoted field stays part of that field, a line break inside quotes does not start a new row, and a doubled quote becomes one quote. Rows that do not fit the header are converted and listed with their line numbers rather than dropped, so a malformed file tells you what it did instead of quietly losing data.

  • An array of JSON objects keyed by the header row, or arrays when there is no header
  • Correct handling of quoted fields containing commas, line breaks, and escaped quotes
  • Optional conversion of numbers, booleans, and nulls to real JSON types
  • A per-line report of ragged rows, unterminated quotes, and duplicate headers

How to Use This Tool

  1. Paste the CSVDrop in the file contents. Comma, semicolon, tab, and pipe delimiters are all selectable.
  2. Set header and typingSay whether the first row names the columns, and whether numeric and boolean-looking fields should become real JSON types.
  3. Read the report, then copyCheck the list of rows that needed a decision, then copy the JSON.

How It Works

The parser is a character-by-character state machine rather than a split on commas, because CSV is not a delimited format in the simple sense — it is a quoted format with a delimiter. The scanner tracks whether it is currently inside a quoted field. Inside one, the delimiter and line breaks are literal text and a pair of double quotes means one escaped quote. Outside one, the delimiter ends the field and a newline ends the row, with CRLF, LF, and a lone CR all recognized. Once rows are separated, the first row becomes the object keys when the header option is on: blank names are filled in as column1, column2, and duplicated names get a numeric suffix so no column can silently overwrite another.

Worked Examples

A comma inside a quoted field

Input
name,city "Doe, Jane",Boston
Output
[ { "name": "Doe, Jane", "city": "Boston" } ]

Splitting this row on commas would produce three fields and shift every value one column left. The quotes keep the comma inside the name.

A line break and an escaped quote inside one field

Input
note "She said ""hello"" then left"
Output
[ { "note": "She said "hello" then left" } ]

The embedded newline does not start a new row, and the doubled quotes collapse to one. This is a single record with a single multi-line field.

A row with too few fields

Input
a,b,c 1,2
Output
[ { "a": 1, "b": 2, "c": null } ] Line 2: Expected 3 fields but found 2. Missing fields were set to null.

The row is still converted, the gap is filled with null rather than omitted, and the problem is reported with its line number so you can go and look at it.

Why Splitting on Commas Corrupts Data

Almost every quick CSV parser written in an afternoon splits each line on the delimiter, and almost every one is wrong in the same way. RFC 4180 allows a field to be wrapped in double quotes, and a quoted field may contain the delimiter itself, a line break, or a literal double quote written as two. Any real export — addresses, product descriptions, anything a human typed — will eventually contain one of the three.

What makes this worse than an ordinary bug is that it usually does not raise an error. A row containing "Doe, Jane" split naively yields one extra field, so every value after it shifts a column: the city ends up in the joined-date field and the date ends up nowhere. The output is well-formed JSON with plausible-looking keys and wrong values, which can travel a long way through a pipeline before anyone notices. A crash would be kinder.

The line-break case is the one that produces the strangest symptoms. A quoted field containing a newline is one field of one row, but a line-based parser sees two rows, the second of which has the wrong number of columns and starts mid-sentence. Files that "have a few bad rows near the middle" are very often files with one multi-line comment field near the top.

What Happens to a Malformed Row

Silence is the wrong response to input that does not fit, so nothing here is dropped without saying so. Every decision the parser had to make is listed under the output with the line number it happened on, and the row is still converted.

A row with fewer fields than the header gets the missing keys set to null rather than left absent, which keeps every object the same shape — code consuming the JSON can check for null without also checking whether the key exists. A row with more fields than the header keeps the surplus under extra_1, extra_2 and so on, because a value that exists in the source and vanishes in the output is precisely the outcome to avoid. A quoted field that is never closed means the remainder of the file is read as one field, and that is reported too, since it is nearly always a missing quote earlier in the file rather than a genuinely enormous value.

Duplicate and blank column names are handled the same way. Two columns called id become id and id_2 rather than one silently overwriting the other, and an unnamed column becomes column3 rather than an empty key that is awkward to reach in most languages.

How each kind of malformed input is handled
ProblemWhat the tool doesReported?
Row has fewer fields than the headerMissing keys set to nullYes, with line number
Row has more fields than the headerSurplus kept as extra_1, extra_2Yes, with line number
Quoted field never closedRest of the file read as one fieldYes, with the line it opened on
Quote inside an unquoted fieldCharacter kept literallyYes, with line number
Duplicate column nameSecond becomes name_2Yes
Blank column nameBecomes column1, column2, …Yes

Type Conversion, and the Zip Code Problem

CSV has no types. Every field is text, and turning 42 into a JSON number is a guess about intent — usually a good guess, occasionally a destructive one. The conversion here is deliberately conservative, and the reason is the single most common spreadsheet data loss there is: a value with a leading zero.

A zip code of 01234, a phone number, a product code, a bank sort code — all of them are strings that happen to contain only digits, and all of them are ruined by being read as numbers. So a field with a leading zero stays a string here. So does an integer too large to survive as an exact double, because a sixteen-digit account number silently rounded is worse than one left as text. Only unambiguous numbers, the words true and false, and the word null are converted; everything else is left exactly as it arrived.

When the data is going somewhere that has its own opinion about types, turning conversion off entirely and letting the destination cast is often the safer route. The switch is there for exactly that.

What Usually Happens Next

Converted JSON rarely stops here. If it is going into an API request or a fixture file, formatting and validating it confirms the structure matches what the endpoint expects before you spend time debugging a request that was malformed all along. If you are checking one export against another after a migration, diffing the two outputs line by line finds the changed record far faster than reading either of them.

When only part of a large export is interesting, a pattern is often the quickest filter — testing the expression against a sample first is worth the minute it takes, because a pattern that looks right against three rows and wrong against three thousand is the usual outcome. Just be careful about the direction of travel: a regex is fine for picking values out of the converted JSON, and a poor choice for parsing the CSV itself, for all the quoting reasons above.

The reverse trip is common enough to mention here: once the data has been cleaned or filtered as JSON, converting it back to CSV is what hands it to whoever asked for a spreadsheet. That round trip is not lossless — nesting becomes dotted column names and types are re-inferred — but for a flat table it is stable.

Two housekeeping steps come up often enough to mention. Exports assembled from several queries frequently repeat whole records, and removing the duplicate rows before converting is easier than de-duplicating objects afterwards. When a table is being loaded somewhere that needs a stable key the export does not carry, generating identifiers for the rows at this stage is simpler than retrofitting them later.

Two things worth watching for in exported data. A field arriving as an opaque blob is often Base64 rather than corrupted text, and decoding it usually reveals ordinary content. And an export of a user table that carries an API key or a password column is a live credential sitting in a file people email around: treat it as compromised the moment it leaves the database and generate a replacement rather than putting it back.

Important Edge Cases

  • A trailing newline at the end of the file does not create an empty final record, but a trailing delimiter on a row does create a genuine empty final field.
  • An empty quoted field, written "", is preserved as an empty string and is distinct from a missing field, which becomes null.
  • Tab-delimited files are supported by selecting the tab delimiter, but a tab inside an unquoted field will still split it.
  • Excel writes a byte order mark at the start of UTF-8 exports, which can attach itself to the first column name. Check the first key if it looks subtly wrong.
  • A field containing only whitespace is preserved as that whitespace, not trimmed to an empty string, because trailing spaces are sometimes significant.

Limitations

  • Input is capped at 2,000,000 characters, so a very large export is better handled by a script than by a browser tab.
  • The tool converts a flat table into flat objects. Nested JSON cannot be produced from CSV without a convention for expressing nesting in column names, which this does not implement.
  • Character encoding is whatever your browser decoded the pasted text as; a file saved in a legacy encoding may arrive with mangled accented characters before it ever reaches the parser.
  • Type conversion is a heuristic, not a schema. It cannot know that a column of ones and zeroes was meant to be boolean, or that an all-digit column is an identifier.
  • There is no column selection, filtering, or reordering — the whole table is converted as it stands.

Input handling

Private Browser Processing

The CSV you paste is parsed in your browser and never uploaded. No part of the file is sent to a server, stored, or logged, and you can confirm that in the network tab while converting.

Google Analytics records page visits and whether a tool finished or failed, but these tool implementations do not send field values, generated passwords, QR payloads, uploaded QR images, or camera frames to analytics or a Tiny Tiny Tools processing endpoint.

See the Privacy Policy for site-wide details.

Questions About This Tool

Does it handle commas inside quoted fields?

Yes. The parser tracks whether it is inside a quoted field, so a comma between quotes stays part of that field. It handles embedded line breaks and doubled quotes the same way, which is what RFC 4180 specifies.

What happens to a row with the wrong number of columns?

It is converted rather than dropped. Missing fields become null, surplus fields are kept as extra_1 and so on, and either way the row is listed under the output with its line number so you can check the source.

Why did my zip code stay a string?

Because it has a leading zero, and converting 01234 to the number 1234 destroys it. Values with leading zeros, and integers too large to hold exactly, are deliberately left as strings.

Can it produce nested JSON?

No. A CSV is a flat table, and turning one into nested objects requires a convention for encoding nesting in the column names. This tool converts the table as it stands.

Is my file uploaded to convert it?

No. The parsing happens in your browser. There is no upload, no server copy, and no request made while you convert — the network tab will show nothing.

My first column name looks odd — why?

Almost certainly a byte order mark. Excel writes one at the start of UTF-8 CSV exports, and it attaches to the first header name as an invisible character. Deleting the first character of that header in the source usually fixes it.