Excel (XLSX) to JSON

Convert an Excel workbook into JSON. Drop the file in, pick a sheet, and get an array of objects with the header row as keys. Date cells come out as ISO 8601 strings such as 2026-01-14 instead of the serial numbers Excel stores.

Workbook

Drop a spreadsheet here

.xlsx, .xlsm, .xls or .ods

JSON Output

1 Example output

An array of objects, one per row

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[
  {
    "id": 1,
    "name": "Alex Morgan",
    "signed_up": "2026-01-14",
    "spent": 240000
  },
  {
    "id": 2,
    "name": "Sam Patel",
    "signed_up": "2026-02-03",
    "spent": 99500.5
  }
]

2 Excel stores dates as numbers

Excel stores a date as the number of days since 1 January 1900, plus a cell format that says to display it as a date. A naive conversion ignores the format, so 14 January 2026 arrives as 46036. This is the most common mistake when moving data out of a spreadsheet.

Keep Dates as ISO 8601 on unless you need the serial. With it on, any cell Excel formatted as a date comes out as 2026-01-14. Turn it off to get the raw serial number, which helps when you are reproducing a spreadsheet calculation. The 1900 epoch also counts a 29 February 1900 that never existed. Lotus 1-2-3 had the bug first, and Excel kept it for file compatibility.

3 Check formulas, merges and headers

Formulas

You get the last value Excel calculated, not the formula. A file written by a library that does not compute formulas can contain stale or empty cells.

Merged cells

A merged range keeps its value in the top-left cell and leaves the rest empty, so the JSON has gaps where the sheet looked full. Unmerge the cells before you convert.

__EMPTY headers

A blank cell in the header row has no name, so the column comes out as __EMPTY. Give every column a header, and delete any title rows that sit above the real one.

Nothing is uploaded

The file is read with FileReader and parsed by SheetJS in this tab, so a spreadsheet of customer data never leaves your machine. That matters when company policy rules out uploading to online converters.

How to use the Excel (XLSX) to JSON tool

  1. Drop a spreadsheet onto the Workbook panel, or click Choose a file. .xlsx, .xlsm, .xls and .ods all work.
  2. If the workbook has several sheets, pick the one you want from the Sheet dropdown.
  3. First row is the header uses row one as the JSON keys. Turn it off to get arrays instead of objects.
  4. Dates as ISO 8601 converts date cells to strings like 2026-01-14. Turn it off to see the raw Excel serial number.
  5. Click Copy Result or Download to take the JSON.

How to read a spreadsheet in code

JavaScript / Node.js (SheetJS)

// npm i xlsx
const XLSX = require("xlsx");

// cellDates gives you Date objects instead of serial numbers
const wb = XLSX.readFile("customers.xlsx", { cellDates: true });
const sheet = wb.Sheets[wb.SheetNames[0]];

// raw: true keeps numbers as numbers. With raw: false you get the
// *displayed* text, so ids become strings and dates become "1/14/26".
const rows = XLSX.utils.sheet_to_json(sheet, { raw: true, defval: null });

console.log(rows[0]);

Watch the raw flag. It looks like a formatting option, but it changes the type of every value in the output without any warning.

Python (pandas / openpyxl)

# pip install pandas openpyxl
import pandas as pd

df = pd.read_excel("customers.xlsx", sheet_name="Customers")

# dtype=str on the read if leading zeros matter:
#   pd.read_excel("f.xlsx", dtype={"zip": str})

df["signed_up"] = pd.to_datetime(df["signed_up"]).dt.strftime("%Y-%m-%d")
print(df.to_json(orient="records", indent=2))

# Every sheet at once
sheets = pd.read_excel("customers.xlsx", sheet_name=None)
print(list(sheets))

PHP

<?php
// composer require phpoffice/phpspreadsheet
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Shared\Date;

$sheet = IOFactory::load('customers.xlsx')->getActiveSheet();
$rows = $sheet->toArray(null, true, true, false);

$headers = array_shift($rows);
$out = array_map(fn($r) => array_combine($headers, $r), $rows);

// A date cell is a float until you convert it
// $date = Date::excelToDateTimeObject($value)->format('Y-m-d');

echo json_encode($out, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);

Common errors and how to fix them

Dates come out as 46036
That is the Excel serial number, counted in days since 1900. Read with cellDates: true in SheetJS, or convert with Date::excelToDateTimeObject in PHP.
Every value is a string
With raw: false, SheetJS returns the displayed text instead of the value. Use raw: true.
Columns are named __EMPTY, __EMPTY_1
The header row has blank cells, usually because a title row sits above the real headers. Delete those rows, or set the range option in SheetJS to start at the header row.
Some rows have gaps where the sheet looked full
Those are merged cells. The value lives in the top-left cell of the range and the other cells are empty. Unmerge them before exporting.
Formula cells are empty
You get the last calculated value, and a file written by a library instead of Excel may never have calculated one. Open and save it in Excel, or compute the value yourself.

Good to know

The 1900 epoch contains a leap day that never existed: Excel treats 29 February 1900 as a real date. Lotus 1-2-3 had the bug, and Excel copied it for file compatibility. It only affects dates before March 1900, so it rarely shows up in practice. However, Excel for Mac historically defaulted to a 1904 epoch, and a workbook that mixes the two systems shows dates shifted by 1,462 days (about four years).

Specifications and references

This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.

Frequently Asked Questions

Which file types can it read?

.xlsx and .xlsm from Excel 2007 onwards, the older .xls binary format, and .ods from LibreOffice. SheetJS parses the file in your browser tab, so a spreadsheet of customer data never leaves your machine.

What if the workbook has several sheets?

The Sheet dropdown lists every sheet, and you pick the one to convert. The output contains only the selected sheet.

How are dates handled?

Excel stores a date as a number of days since 1900, so a raw conversion gives you 45292 instead of 2024-01-01. With Dates as ISO 8601 on, the tool converts date-formatted cells to ISO 8601 strings. This is the most common mistake when exporting from Excel.

What happens to formulas?

You get the last calculated value, not the formula. That value dates from Excel's last recalculation, so a workbook saved by a library that does not compute formulas can contain stale or empty cells.

Are merged cells a problem?

They can be. A merged range holds its value in the top-left cell and leaves the rest empty, so the JSON has gaps where the spreadsheet looked full. Unmerge the cells before converting if the layout matters.

My headers came out as __EMPTY. Why?

The first row had blank cells, so those columns had no name. Give every column a header, or delete any title rows that sit above the real header row.

Going the other way

JSON to Excel builds a workbook from JSON. If the data is already a CSV export, CSV to JSON skips the spreadsheet step, and CSV to SQL turns it into INSERT statements.

More Data Converters

Browse all data converters

Copied to clipboard!