# Excel to JSON Converter: XLSX, XLS & CSV to JSON API (`data-done-right/excel-to-json-converter`) Actor

Excel to JSON converter API: XLSX to JSON, XLS to JSON, CSV to JSON and ODS to JSON from file URLs, uploaded files or pasted text. Detects headers, types, delimiter and encoding, reads every sheet, and returns one JSON row per source row with file, sheet and row details.

- **URL**: https://apify.com/data-done-right/excel-to-json-converter.md
- **Developed by:** [Data Done Right](https://apify.com/data-done-right) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.20 / 1,000 files

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Excel to JSON Converter: XLSX, XLS & CSV to JSON API

This **Excel to JSON** converter turns spreadsheets into clean JSON rows. Give it links to `.xlsx`, `.xlsm`, `.xls`, `.ods`, `.csv` or `.tsv` files, files you stored in a key-value store, or pasted CSV text. It finds the header row, converts numbers, booleans and dates, reads every sheet, and returns **one dataset row per source row**, with the file name, sheet name and row number on each row so you can trace it back. It works as an **Excel to JSON API** for apps, automations and AI agents, and the same run also does **CSV to JSON** and **XLSX to JSON**.

### Excel to JSON

Paste file URLs (or upload files to a key-value store) and run. For every sheet the Actor:

- **Finds the header.** Auto mode skips blank rows and title rows above the table. Or set the header row number, or turn the header off to get `column_1`, `column_2`, ...
- **Keeps real types.** Excel numbers, booleans and dates stay numbers, booleans and dates. Floating-point noise from Excel is cleaned (`0.1+0.2` reads as `0.3`).
- **Handles messy headers.** Blank headers become `column_N`, repeated names become `name`, `name_2`, `name_3`, and rows wider than the header keep their extra cells.
- **Reads every sheet** by default, or only the sheets you name or number.
- **Nests dotted headers** (`address.city`, `address.zip`) into objects when you turn on **Nest dotted column names**.
- **Skips what you do not need:** blank rows, trailing empty rows and whitespace (all adjustable).

### CSV to JSON

CSV and TSV need no setup:

- **Delimiter detection:** comma, semicolon, tab or pipe, chosen from the first lines. Files with decimal commas (`1,5;2,5`) are read correctly.
- **Encoding detection:** UTF-8 (with or without a byte order mark), UTF-16, Windows-1252 and Latin-1.
- **Type detection:** `42` becomes a number, `true`/`false` become booleans, ISO dates stay ISO. Ambiguous values stay text: `007`, `+15551234567`, `1e5` and 20-digit IDs are not turned into numbers.
- **Quoted fields** with embedded delimiters, quotes and line breaks are parsed properly.

### XLSX to JSON

- `.xlsx` and `.xlsm` files are streamed row by row, so large workbooks do not need much memory.
- Legacy **`.xls`** files and OpenDocument **`.ods`** files are supported too. `.xls` files are loaded into memory whole, so keep them well under the 50 MB default.
- **Formulas return the value Excel last saved (cached).** Nothing is calculated here. A file written by a library that never calculated its formulas has empty cells where the formulas are; open and save it in Excel first.
- **Merged cells are not interpreted.** In a merged range only the top-left cell has a value; the other cells are empty.
- **Charts, pictures, comments, filters and cell colors are ignored.**
- **Macros are never executed or read.** `.xlsm` files are read for their cell values only.
- Password-protected workbooks and binary `.xlsb` files are not supported, and the error says so.

### Excel to JSON API

Call the Actor from the Apify API, Python, JavaScript, Make, Zapier or n8n. Example with the Apify Python client:

```python
from apify_client import ApifyClient

client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("data-done-right/excel-to-json-converter").call(run_input={
    "fileUrls": ["https://example.com/reports/sales-2024.xlsx"],
    "sheets": ["Sales"],
    "headerRow": "auto",
    "jsonFile": True,
})
rows = client.dataset(run["defaultDatasetId"]).list_items().items
summary = client.key_value_store(run["defaultKeyValueStoreId"]).get_record("SUMMARY")["value"]
```

Upload a file first with `client.key_value_store(id).set_record("report.xlsx", data, content_type="application/octet-stream")` and pass `{"storeKeys": ["report.xlsx"], "storeId": id}` to convert files that are not on a public URL. Google Sheets links shared with "anyone with the link" are converted from their Excel export.

### Input example

```json
{
  "fileUrls": ["https://example.com/reports/sales-2024.xlsx", "https://example.com/data/customers.csv"],
  "inlineCsv": "name,plan,seats\nAda,pro,5\nGrace,team,12",
  "sheets": ["Sales", "3"],
  "headerRow": "auto",
  "inferTypes": true,
  "dateFormat": "iso",
  "outputShape": "objects",
  "flatten": false,
  "maxRows": 100000,
  "jsonFile": false
}
```

Main options: **File URLs**, **Files in a key-value store**, **Paste CSV / TSV text**, **Sheets to convert**, **Header row**, **Skip empty rows**, **Trim whitespace**, **Detect numbers, booleans and dates**, **Date format** (ISO, plain text, Unix milliseconds or Excel serial), **Output shape**, **Max rows per sheet**, **CSV delimiter**, **CSV text encoding**, **Nest dotted column names**, **Rename duplicate column names**, **Add \_file, \_sheet and \_row**, **Also save a JSON file** and **Max file size (MB)** (default 50).

### Output

One dataset item per source row:

```json
{
  "_file": "inline.csv", "_sheet": "csv", "_row": 2,
  "name": "Ada Lovelace", "email": "ada@example.com", "signup_date": "2024-01-15",
  "plan": "pro", "seats": 5, "active": true
}
```

- `_file`, `_sheet` and `_row` (the row number in the source sheet) can be switched off.
- **Output shape** "One array per row" gives `values: [...]` instead of named keys. "One object per sheet" gives one item per sheet with `columns`, `rowCount` and `rows` (about 9 MB per item at most, so use rows for big sheets).
- A **SUMMARY** record in the key-value store lists, per file: format, size, encoding and delimiter (CSV), every sheet with its header row, column names and row counts, warnings (duplicate headers, rows cut at **Max rows per sheet**, unknown sheet names) and any error.
- With **Also save a JSON file**, each file is also saved as `<name>.json` (`{"file": ..., "sheets": [{"name", "columns", "rows"}]}`) in the key-value store, with a public link in `SUMMARY`. It is included in the price. Files over 25 MB are served as `text/plain`.

### Use it in Claude, ChatGPT and Cursor

Connect Apify's MCP server (mcp.apify.com) and your AI assistant can read spreadsheets for you. For example: "convert this Excel file to JSON, only the Orders sheet, and tell me which columns have empty values". The main inputs are `fileUrls` (or `inlineCsv`), `sheets` and `headerRow`.

### Use cases

- **Spreadsheet to API data:** turn a partner's Excel export into JSON your app can ingest.
- **Automations:** feed Make, Zapier or n8n flows with rows from a CSV or XLSX attachment.
- **AI agents:** give an agent clean rows and types instead of raw spreadsheet bytes.
- **Data migration:** convert a folder of legacy `.xls` files in one run.
- **Quick checks:** paste CSV text and see how it parses (delimiter, encoding, types).

### How much does it cost

Pay per event: **$0.004 per file converted** (`file`) plus **$0.00006 per row delivered** (`row`, $0.06 per 1,000 rows). A 5-row CSV costs about $0.0043, a 1,000-row sheet about $0.064, and 100,000 rows about $6. **A file that fails costs nothing:** downloads that are blocked or too large, damaged or unsupported files, and files with no data rows are not charged, and the other files in the run still convert. Rows are charged once, as they are delivered; the JSON file option and the SUMMARY record are free. Paid Apify plans get 10% (Silver) to 20% (Gold and up) off. If you set a maximum spend per run, the Actor stops cleanly when it is reached and keeps the rows already delivered. **Max rows per sheet** and **Max file size (MB)** cap what a run can cost.

### Safe by design

- Links to localhost, internal names and private networks (including cloud-metadata addresses) are blocked, also after DNS lookup and on every redirect.
- Files are limited to 50 MB by default (up to 500 MB). Spreadsheet archives that expand to more than 1 GB, have an extreme compression ratio or hold an oversized text table are rejected before they are read.
- Formulas are never evaluated and macros are never run.

### FAQ

#### How do I convert an Excel file to JSON?

Paste the link to the `.xlsx` file in **File URLs** and run the Actor. Each row of every sheet becomes one dataset item. Download the result as JSON, CSV or Excel, read it through the API, or turn on **Also save a JSON file** to get one `.json` file per input file.

#### Does it keep numbers and dates as numbers and dates?

Yes. Excel cells keep their types. Dates become ISO text (`2024-01-15`, or `2024-01-15T10:30:00` with a time) unless you pick plain text, Unix milliseconds or Excel serial numbers. For CSV, numbers, booleans and ISO dates are detected when it is unambiguous, and you can turn that off to get every value as text.

#### Why are my formula cells empty?

The Actor reads the value Excel saved with the file. If the file was produced by a script that never calculated its formulas, there is no saved value. Open the file in Excel, save it and convert again. Formulas are never evaluated here.

#### What do error cells like #N/A look like?

They come through as that text (`"#N/A"`, `"#DIV/0!"`), because the Actor reads what Excel saved.

#### What about merged cells?

They are not interpreted. Only the top-left cell of a merged range has a value, so a merged header leaves blank headers (named `column_N`) next to it. Set **Header row** to the row that has the real column names.

#### Can it convert .xls, .ods, .xlsm and Google Sheets?

Yes to all four. `.xlsb` and password-protected workbooks are not supported. A Google Sheet must be shared with "anyone with the link".

#### How are CSV files with semicolons, tabs or accents handled?

The delimiter and the encoding are detected automatically. If a file is still read wrongly, set **CSV delimiter** or **CSV text encoding**.

#### What happens if one file fails?

It is reported in `SUMMARY` with the reason, it is not charged, and the other files still convert. The run only fails when no file could be converted.

#### Is there a size limit?

50 MB per file by default (up to 500 MB), 100,000 rows per sheet by default (up to 5,000,000), and about 9 MB per dataset item.

### Related tools

- **Merge Datasets & Dedupe: Combine, Filter, Export CSV & Excel**: combine the converted rows with other data and remove duplicates.
- **Google Sheets Import & Export: Apify Data, No Login**: send results to a Google Sheet.
- **HTTP Request Runner: Bulk API Calls, Retries, Proxies**: post the converted rows to your own API.

# Actor input Schema

## `fileUrls` (type: `array`):

Direct links to the files to convert: .xlsx, .xlsm, .xls, .ods, .csv or .tsv. Example: https://example.com/reports/sales-2024.xlsx. Google Sheets links shared with 'anyone with the link' also work (read as Excel). Up to 500 files per run. Private network addresses are blocked, and a file that cannot be read is skipped for free.

## `inlineCsv` (type: `string`):

Paste CSV or TSV text to convert it without a file (the delimiter is detected). The first row is the header unless you change Header row. This is converted as one file named inline.csv.

## `storeKeys` (type: `array`):

Keys of files already stored in a key-value store (for example uploaded with the Apify API or console), one per line. They are read from the store in 'Key-value store ID or name', or from this run's own store when that is empty. Example: monthly-report.xlsx.

## `storeId` (type: `string`):

The store that holds the files listed in 'Files in a key-value store'. Leave empty to use this run's default store. Example: my-uploads.

## `sheets` (type: `array`):

Sheet names or positions (1 is the first sheet), one per line. Leave empty or write all to convert every sheet. Example: Sales and 3. Ignored for CSV and TSV files.

## `headerRow` (type: `string`):

Where the column names are. Auto skips blank rows and title rows above the table. 'Row number' uses the row you set below. 'None' creates column_1, column_2, ... and treats every row as data.

## `headerRowNumber` (type: `integer`):

Row number of the header (1 is the first row of the sheet). Used only when Header row is set to Row number. Rows above it are skipped.

## `skipEmptyRows` (type: `boolean`):

Leave out rows where every cell is blank. Blank rows after the last data row are always dropped.

## `trim` (type: `boolean`):

Remove leading and trailing spaces from text cells and column names. Cells that end up empty become null.

## `inferTypes` (type: `boolean`):

Turn text in CSV files into numbers, true/false and ISO dates when that is unambiguous ('007', '+1555' and 20-digit IDs stay text). Excel cells already have types. Turning this off returns every value, Excel cells included, as text.

## `dateFormat` (type: `string`):

How date and time cells are written in the JSON. ISO gives 2024-01-15 for dates and 2024-01-15T10:30:00 for date-times.

## `outputShape` (type: `string`):

Rows as objects gives one dataset item per row with column names as keys. Rows as arrays gives the cell values as a list in values. One object per sheet gives one item per sheet with its columns and all rows (limited to about 9 MB per item).

## `maxRows` (type: `integer`):

Stops reading a sheet after this many data rows. Protects your budget on huge files.

## `delimiter` (type: `string`):

Field separator of CSV and TSV files. Auto-detect chooses between comma, semicolon, tab and pipe from the first lines.

## `encoding` (type: `string`):

Auto-detect reads a byte order mark, then tries UTF-8 and falls back to Windows-1252 (Latin-1 as a last resort). Pick one only if accents come out wrong.

## `flatten` (type: `boolean`):

Turn headers like address.city and address.zip into a nested object {"address": {"city": ..., "zip": ...}}. Headers that clash (a and a.b) stay as they are.

## `dedupeHeaders` (type: `boolean`):

Number repeated column names (name, name_2, name_3) so no column is lost. Off keeps the last column of the same name. Blank headers always become column_N.

## `includeMetadata` (type: `boolean`):

Add the source file name, sheet name and row number to every item so you can trace it back. Turn off for clean rows.

## `jsonFile` (type: `boolean`):

Save the full result of each file as one JSON file in the key-value store, with a public link in the SUMMARY record. Included in the price.

## `maxFileSizeMb` (type: `integer`):

Files larger than this are skipped for free. Spreadsheet archives that expand to more than 1 GB are always rejected.

## Actor input object example

```json
{
  "inlineCsv": "name,email,signup_date,plan,seats,active\nAda Lovelace,ada@example.com,2024-01-15,pro,5,true\nGrace Hopper,grace@example.com,2024-02-03,team,12,true\nAlan Turing,alan@example.com,2024-02-19,free,1,false\nKatherine Johnson,katherine@example.com,2024-03-08,pro,3,true\nLinus Torvalds,linus@example.com,2024-03-30,team,25,true\n",
  "headerRow": "auto",
  "headerRowNumber": 1,
  "skipEmptyRows": true,
  "trim": true,
  "inferTypes": true,
  "dateFormat": "iso",
  "outputShape": "objects",
  "maxRows": 100000,
  "delimiter": "auto",
  "encoding": "auto",
  "flatten": false,
  "dedupeHeaders": true,
  "includeMetadata": true,
  "jsonFile": false,
  "maxFileSizeMb": 50
}
```

# Actor output Schema

## `results` (type: `string`):

One item per source row (with \_file, \_sheet and \_row), all result items of this run as JSON, CSV, Excel and more.

## `records` (type: `string`):

Key-value store records: SUMMARY (files, sheets, rows and warnings per file) and, when the JSON file option is on, one JSON file per input file with a public link.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "inlineCsv": `name,email,signup_date,plan,seats,active
Ada Lovelace,ada@example.com,2024-01-15,pro,5,true
Grace Hopper,grace@example.com,2024-02-03,team,12,true
Alan Turing,alan@example.com,2024-02-19,free,1,false
Katherine Johnson,katherine@example.com,2024-03-08,pro,3,true
Linus Torvalds,linus@example.com,2024-03-30,team,25,true`
};

// Run the Actor and wait for it to finish
const run = await client.actor("data-done-right/excel-to-json-converter").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "inlineCsv": """name,email,signup_date,plan,seats,active
Ada Lovelace,ada@example.com,2024-01-15,pro,5,true
Grace Hopper,grace@example.com,2024-02-03,team,12,true
Alan Turing,alan@example.com,2024-02-19,free,1,false
Katherine Johnson,katherine@example.com,2024-03-08,pro,3,true
Linus Torvalds,linus@example.com,2024-03-30,team,25,true
""" }

# Run the Actor and wait for it to finish
run = client.actor("data-done-right/excel-to-json-converter").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "inlineCsv": "name,email,signup_date,plan,seats,active\\nAda Lovelace,ada@example.com,2024-01-15,pro,5,true\\nGrace Hopper,grace@example.com,2024-02-03,team,12,true\\nAlan Turing,alan@example.com,2024-02-19,free,1,false\\nKatherine Johnson,katherine@example.com,2024-03-08,pro,3,true\\nLinus Torvalds,linus@example.com,2024-03-30,team,25,true\\n"
}' |
apify call data-done-right/excel-to-json-converter --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,data-done-right/excel-to-json-converter"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/7DLZn24ogBljmtJQp/builds/IZOcybYevnSGjE6Os/openapi.json
