iKit
Tutorial · 10 min read ·

Excel to JSON in the Browser: No Server Needed (2026)

Excel to JSON does not require uploading your spreadsheet anywhere. Here is the browser-only workflow, plus the date and precision traps that corrupt data.

Excel to JSON in the Browser: No Server Needed (2026)

Excel to JSON in the Browser: No Server Needed

Every "excel to json" search result asks you to upload the file first. That is a strange trade for a conversion your browser can already do — and a bad one when the sheet holds salaries, customer emails, or unreleased numbers. This guide covers the browser-only path from XLSX to JSON, the two-line code version, and the four traps that silently corrupt the output.

TL;DR

  • Excel to JSON needs no server: the parsing runs in your tab.
  • .xlsx is a ZIP of XML parts, readable by JavaScript with no backend.
  • Dates arrive as serial numbers, not strings — convert from 1899-12-30.
  • IDs longer than 15 digits lose precision before JSON ever sees them.
  • Export CSV UTF-8 for the fast path; read XLSX for types and multi-sheet.

How to convert Excel to JSON without uploading the file

The quickest reliable route has two steps, and neither of them involves a server.

Step 1: export the sheet as CSV UTF-8

In Excel, choose File → Save As and pick CSV UTF-8 (Comma delimited). The UTF-8 variant matters: the plain "CSV (Comma delimited)" option writes the legacy locale code page, which is how accented names and CJK text turn into mojibake three tools later. Excel only exports the active sheet, so repeat per sheet if you need more than one.

Step 2: convert the CSV to JSON in your browser

Drop the file into the iKit CSV ↔ JSON converter. It parses in the page — the file is never posted anywhere — and gives you an array of objects keyed by the header row. From there, JSON Decoder will pretty-print and validate the result, and the JSON ↔ YAML converter will turn it into a config file if that is where the data is heading.

When to skip CSV and read the .xlsx directly

CSV is a lossy intermediate. It flattens everything to text, drops all but one sheet, and throws away the cell type information that would have told you 00123 was a string. Read the workbook directly when any of these apply:

  • The workbook has more than one sheet you care about.
  • Columns contain real dates you want as ISO strings.
  • Cells hold leading-zero identifiers, phone numbers, or postcodes.
  • You need to know which cells were formulas versus literal values.

What is an .xlsx file, really?

Understanding the container explains why no server is required.

A ZIP archive of XML parts

An .xlsx file is a ZIP package following the Open Packaging Conventions, standardised as ECMA-376 Office Open XML in December 2006 and later as ISO/IEC 29500. Rename any workbook to .zip, unpack it, and you get a directory tree:

xl/workbook.xml        sheet names + order
xl/worksheets/sheet1.xml   the cells
xl/sharedStrings.xml   deduplicated text values
xl/styles.xml          number formats, incl. dates
[Content_Types].xml    part type map

Both ZIP and XML have had solid JavaScript implementations for over a decade. That is the whole reason browser-side conversion works: there is no proprietary binary blob that only Excel can open.

The shared strings table

Text cells usually do not store their own text. They store an index into sharedStrings.xml, so a column repeating "Active" 40,000 times costs one string plus 40,000 small integers. It is an effective compression trick and the main reason a naive XML-only parser produces a JSON file full of numbers where you expected words.

Why styles decide whether a number is a date

There is no date type in the sheet XML. A date cell is a plain number whose style points at a date number format in styles.xml. Strip the styles and 45292 is just forty-five thousand two hundred ninety-two. This single design choice is behind most Excel-to-JSON bug reports.

Why does my Excel date turn into a number like 45292?

Because that is genuinely how Excel stores it, and JSON has no date type to rescue you.

The 1900 serial date system

Excel counts days from an epoch, with serial 1 being 1 January 1900. Microsoft's Excel specifications and limits put the supported range at 1 January 1900 through 31 December 9999, with a separate 1904 system inherited from classic Mac Excel. Times are the fractional part: 45292.5 is noon on 1 January 2024.

The phantom 29 February 1900

Excel treats 1900 as a leap year. It was not — century years need to be divisible by 400. Microsoft documents the behaviour and explains it was inherited from Lotus 1-2-3 for serial-date compatibility, and that correcting it now would shift every date in every existing workbook by one day.

The practical consequence: the conversion offset differs for serials below 61. For every date after 28 February 1900 — which is every date you will ever actually process — use 30 December 1899 as the JavaScript epoch:

function excelSerialToISO(serial) {
  const EPOCH = Date.UTC(1899, 11, 30);
  const ms = EPOCH + Math.round(serial * 86400000);
  return new Date(ms).toISOString().slice(0, 10);
}

excelSerialToISO(45292); // "2024-01-01"

Getting ISO dates without writing code

Two options. Select the date column in Excel, format it as Text (or add a helper column with =TEXT(A2,"yyyy-mm-dd")), then export — the CSV now carries real strings. Or, if you are reading the XLSX in JavaScript, ask the parser for formatted values instead of raw ones.

Excel to JSON in JavaScript with SheetJS

For anything scripted, SheetJS reads the workbook in the page with no upload step.

Reading the file the user picked

The browser's File API hands you the bytes directly from a file input or a drop target. Nothing crosses the network:

<input type="file" id="f" accept=".xlsx,.xls">
document.getElementById("f")
  .addEventListener("change", async (e) => {
    const file = e.target.files[0];
    const buf = await file.arrayBuffer();
    const wb = XLSX.read(buf);           // parse in-tab
    const ws = wb.Sheets[wb.SheetNames[0]];
    const rows = XLSX.utils.sheet_to_json(ws);
    console.log(JSON.stringify(rows, null, 2));
  });

sheet_to_json: objects versus arrays of arrays

Per the SheetJS array utilities documentation, sheet_to_json walks the sheet in row-major order. By default it reads the first row as headers and returns one object per data row. Pass header: 1 and you get an array of arrays instead, first row included — the right choice when your headers are duplicated, missing, or sitting on row 4.

Duplicate header labels are disambiguated by appending _1, _2, so three columns named foo become foo, foo_1, foo_2. Worth knowing before you wonder why a key vanished.

The four options that prevent bad output

Option Default What it fixes
raw: false true Returns Excel's displayed text, so dates come out formatted
defval: null skip Emits empty cells instead of omitting the key entirely
header: 1 Array of arrays when the header row is unreliable
blankrows varies Controls whether empty rows appear in the output

defval is the one that saves production code. Without it, a row with a blank column simply has no key for it, and downstream Object.keys() checks quietly disagree row to row.

The Excel-to-JSON traps that corrupt data silently

None of these throw an error. They just produce wrong JSON.

Leading zeros disappear from IDs and postcodes

Excel parses 01234 as the number 1234 the moment it is typed or imported, and the zero is gone before any converter sees the file. There is no recovery step downstream — the information is not in the cell. Format the column as Text before the data enters the sheet, or import via Data → From Text/CSV and set the column type explicitly.

Numbers longer than 15 digits get rounded

Excel's specifications cap number precision at 15 significant digits. A 16-digit order number or a bank account stored as a number becomes something ending in zeros:

Typed:  1234567890123456
Stored: 1234567890123450

Long identifiers belong in text columns. This is not a JSON problem; the damage happened in the spreadsheet.

Merged cells produce nulls, not repeats

A merged cell holds its value in the top-left position only. Every other cell in the merge is genuinely empty, so a merged category label spanning five rows yields one populated row and four with null. Un-merge and fill down before exporting, or forward-fill in code after conversion.

CSV encoding still needs a BOM

If you take the CSV route, Excel guesses the encoding from the first bytes on re-open. Without a UTF-8 byte order mark it falls back to a locale code page and non-ASCII text renders as mojibake. This is a round-trip problem more than an export problem, but it bites the moment someone opens your generated CSV again — the CSV edge cases guide covers the full set.

Why you don't need a server to convert a spreadsheet

The technical case is settled. The remaining argument is about what you hand over.

Spreadsheets are the most sensitive files most teams own

Payroll, customer lists, revenue by account, unreleased headcount plans — these live in XLSX far more often than in a database. Uploading one to a conversion site means an unknown party now holds a copy, subject to their retention policy, their breach history, and their jurisdiction. A client-side tool cannot retain what it never receives.

What each approach actually costs

Factor Upload-based converter Browser-only converter
Data leaves device Yes, full file No
Works offline No Yes, after first load
Time for a 5 MB file Upload + queue + download Under a second
Row cap Often gated behind a plan Tab memory only

The honest limits of the browser

Client-side is not unconditionally better. The whole file lands in memory, so a 200 MB export will stall a tab where a streaming Python or Node script would not. Scheduled or repeated conversions belong in a pipeline, not a browser tab. And if the transformation is genuinely complex — joins across sheets, business rules, validation — write the script. Use the browser for the case it wins outright: a human with one file who wants JSON in the next ten seconds.

For the reverse direction — a SQL dump or database export that needs to become a spreadsheet — the SQL to Excel converter handles CREATE/INSERT statements the same way, entirely in the page.

References

Related on iKit

Related posts