# Spreadsheet Converter: Excel to JSON and CSV (`maliksaid/spreadsheet-converter`) Actor

Convert Excel to JSON, CSV to JSON, JSON to CSV and Excel to CSV. Reads XLSX, XLS, ODS, CSV, TSV, JSON and Apify datasets. Writes CSV, XLSX, JSON, JSON Lines or dataset rows. Detects headers, numbers and dates, flattens nested JSON, picks sheets and removes duplicates.

- **URL**: https://apify.com/maliksaid/spreadsheet-converter.md
- **Developed by:** [Malik Said](https://apify.com/maliksaid) (community)
- **Categories:** Developer tools, Automation, Integrations
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.15 / 1,000 row converteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Spreadsheet Converter: Excel, CSV and JSON

Spreadsheet Converter turns spreadsheet and data files into the format you need. Convert Excel to JSON, CSV to JSON, JSON to CSV, Excel to CSV or CSV to Excel in one run. It also turns any Apify dataset into an Excel or CSV file. It finds the header row, reads numbers and dates, flattens nested JSON, and can merge many files into one.

### Spreadsheet converter: what it does

- Reads XLSX, XLS, ODS, XLSB, CSV, TSV, JSON, JSON Lines and Apify datasets.
- Writes dataset rows (JSON), CSV, TSV, XLSX, JSON or JSON Lines files.
- Converts every sheet of a workbook, or only the sheets you name.
- Finds the header row and skips title rows above it.
- Turns CSV text into numbers, true and false, and ISO dates. Codes such as `008` stay text.
- Converts Excel dates to ISO dates (`2026-01-31`), in UTC.
- Flattens nested JSON into `parent.child` columns for CSV and Excel.
- Keeps, orders and renames columns.
- Removes duplicate rows by one or more columns.
- Merges many files and sheets into one output with all columns.
- Detects the delimiter (comma, semicolon, tab or pipe) and the text encoding.

Files are converted inside the Actor. They go to no outside service.

### Input: URLs, your own files or datasets

You can give files in four ways:

1. **File URLs.** Paste links, one per line.
2. **Key-value store.** Upload files to one of your Apify key-value stores and pick it. The Actor only reads that store.
3. **Datasets.** Pick one or more Apify datasets, for example the results of another Actor. Each dataset becomes one file.
4. **Pasted data.** Paste CSV, TSV, JSON or JSON Lines text, or a base64 file such as an XLSX, into **Pasted data**. This suits API, n8n and Make users who hold the data in a variable. Up to 4 MB. For larger files, use a URL or a key-value store. The result row shows `source: "pasted"` and the file name you set, with the detected extension.

### How to convert Excel to JSON or CSV

1. Paste your file links in **File URLs**, or pick a key-value store or a dataset.
2. Pick the **Output format**. Dataset rows give you JSON you can also export from Apify as CSV, Excel or XML.
3. Optional: name the **Sheets**, pick **Keep only these columns**, set **Remove duplicates by**, keep only some rows with **Keep only rows that match**, or **Sort by** a column.
4. Click **Start**.
5. Open the **Converted files** tab for file outputs, or the dataset for rows.

### Output

**Dataset rows.** With the default output format, every row of your file becomes one dataset item, with your column names as fields. Row from a test run (the ISO 4217 currency list):

```json
{
    "Entity": "AFGHANISTAN",
    "Currency": "Afghani",
    "AlphabeticCode": "AFN",
    "NumericCode": "971",
    "MinorUnit": 2,
    "WithdrawalDate": null
}
```

`NumericCode` stays text because the same column holds codes with a leading zero, such as `008`.

**Files.** With CSV, TSV, XLSX, JSON or JSON Lines, the converted files go to the run's key-value store. The dataset then holds one summary record per input file:

| Field | Meaning |
|---|---|
| `status`, `error` | `ok` or `failed`, and why it failed |
| `fileUrl`, `keyValueStoreKey`, `datasetId` | Where the file came from |
| `fileName`, `inputFormat`, `inputBytes` | The input file |
| `sheetsFound`, `sheets` | Every sheet name, and per converted sheet the header row, rows read and saved, empty rows and duplicates skipped |
| `rowsRead`, `rowsSaved`, `duplicatesRemoved`, `rowsFilteredOut` | Row counts for the file. Filtered rows are free |
| `columns`, `columnTypes` | Output columns and the type found in each: number, string, date, boolean, object, mixed or empty |
| `outputFiles` | Each output file: sheet, key, download URL, rows and bytes |
| `truncated` | True when a row limit or your maximum cost per run stopped the file early |

Summary record from a test run (the currency list, CSV to XLSX):

```json
{
    "status": "ok",
    "fileUrl": "https://raw.githubusercontent.com/datasets/currency-codes/main/data/codes-all.csv",
    "fileName": "codes-all.csv",
    "inputFormat": "csv",
    "inputBytes": 17853,
    "rowsRead": 449,
    "rowsSaved": 449,
    "duplicatesRemoved": 0,
    "rowsFilteredOut": 0,
    "columns": ["Entity", "Currency", "AlphabeticCode", "NumericCode", "MinorUnit", "WithdrawalDate"],
    "columnTypes": {
        "Entity": "string",
        "Currency": "string",
        "AlphabeticCode": "string",
        "NumericCode": "string",
        "MinorUnit": "mixed",
        "WithdrawalDate": "string"
    },
    "outputFormat": "xlsx",
    "outputFiles": [{ "sheet": "codes-all", "key": "codes-all.xlsx", "rows": 449, "bytes": 24476 }],
    "truncated": false,
    "processingMs": 705
}
```

The record also has `url` in each output file, plus `id`, `sheets`, `finalUrl` and `scrapedAt`. In every mode, the `SUMMARY` record of the key-value store lists the same summaries.

### Output files

| Output format | Files |
|---|---|
| CSV, TSV, JSON, JSON Lines | One file per sheet. A one-sheet file keeps its name: `report.csv`. Several sheets: `report-Sales.csv`, `report-Notes.csv` |
| XLSX | One workbook per input file, one worksheet per sheet. A sheet with more than 1,048,575 rows continues on a second worksheet |
| Merge on | One file, `merged.csv` or `merged.xlsx`, with every column of every input |

CSV files use a comma, UTF-8 and Windows line ends. Turn on **Add a byte order mark** when you open them in Excel and they hold accents, Arabic or Chinese.

### Input options

| Option | Default | Meaning |
|---|---|---|
| File URLs | One sample CSV | Links to the files |
| Key-value store, Record keys | None | Your store with files, and optionally which records |
| Datasets to convert | None | Apify datasets to turn into files |
| Pasted data, Pasted data file name | None, `pasted` | CSV, JSON or base64 file text pasted into the input |
| Output format | Dataset rows | Dataset rows, CSV, TSV, XLSX, JSON or JSON Lines |
| Merge all files into one output | Off | One output for the whole run |
| Maximum rows per file | 0 (all) | Stop each file after this many rows |
| Sheets | All | Sheet names or tab numbers |
| Header row | Auto-detect | Auto, first row, none, or a row number |
| Input format | Auto-detect | Force a format when auto-detection is wrong |
| CSV delimiter | Auto | Comma, semicolon, tab or pipe, or type your own |
| Text encoding | Auto | UTF-8, Latin-1 or UTF-16 |
| JSON path to the records | Empty | For example `data.items` |
| Detect numbers, dates and true/false | On | For CSV and TSV text |
| Numbers use a decimal comma | Off | For European files: `1.234,5` |
| Day and month order in text dates | Leave as text | Day first or month first |
| Keep only these columns | All | Names in the order you want |
| Rename columns | None | `{"old name": "new name"}` |
| Remove duplicates by | None | Column names, or `*` for whole rows |
| Keep only rows that match | None | One rule per line, such as `Price >= 10`, `Country = Jordan`, `Name contains ltd`, `Email is not empty` |
| Rows must match | All rules | All rules, or any one rule |
| Sort by | None | Column names; add ` desc` for largest first. Holds rows in memory (about 1,000,000 short rows at 512 MB) |
| Flatten nested JSON | Auto | Flattens for CSV, TSV and XLSX |
| Lists inside JSON records | Join | Join, one column per position, or JSON text |
| Skip empty rows, Trim spaces | On | Cleaning |
| Add source columns | Off | Adds `_file`, `_sheet` and `_row` |
| Maximum file size | 100 MB | Up to 500 MB |

### Limits and memory

- CSV, TSV, JSON Lines and XLSX are read as streams, one row at a time. A 105 MB CSV with 1.16 million rows converts in 512 MB.
- XLSX keeps its shared text in memory. At 512 MB that is about 500,000 distinct text values per workbook.
- XLS, ODS and XLSB are read whole. At 512 MB the limit is 2.5 MB for XLS and XLSB and 1.7 MB for ODS. Save bigger files as XLSX or CSV.
- JSON files are read whole. At 512 MB the limit is 8 MB. Use JSON Lines for bigger files.
- Formulas give their last saved result. The Actor does not recalculate them.
- Merged cells give their value in the first cell only.
- Password-protected workbooks are not supported.
- One run converts at most 1,000 files.

### Pricing

You pay per file converted and per row saved, plus a small fee per run. See the Pricing tab for current prices. Failed files cost nothing. A run stops when it reaches your maximum cost per run, and the last file then says `truncated: true`.

### Privacy and fair use

- The Actor only fetches the files you list.
- It reads robots.txt on each host and skips files that the host does not allow.
- It refuses local and private network addresses.
- It does not log in and does not get around access controls.
- Converted files stay in your own Apify storage.
- Use only files you have the right to process.

### FAQ

**Where are my files?** In the run's key-value store. Each summary record has a direct `url` for each output file.

**Why is a number column text?** At least one value in that column has a leading zero or more than 15 digits, so the column holds codes. Converting them to numbers would lose digits.

**Why are my dates text?** CSV dates such as `31/12/2026` stay text until you pick **Day and month order in text dates**. ISO dates such as `2026-12-31` are read as dates.

**Can I convert results of another Actor?** Yes. Pick its dataset in **Datasets to convert**.

### Other Actors by the same developer

- [Email Validator](https://apify.com/maliksaid/email-validator) checks email lists, for example a column of a converted file.
- [Technical SEO Audit](https://apify.com/maliksaid/technical-seo-audit) checks websites for SEO problems.

### Support

Report a problem in the Issues tab. Include the run link.

# Actor input Schema

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

Links to the files to convert, one per line. XLSX, XLS, ODS, XLSB, CSV, TSV, JSON and JSON Lines work. The Actor reads robots.txt on each host and skips files it does not allow. Leave empty to convert only the key-value store, datasets or pasted data below.

## `keyValueStoreId` (type: `string`):

Optional. Pick one of your key-value stores that holds uploaded spreadsheet files. The Actor only reads this store.

## `keyValueStoreKeys` (type: `array`):

Optional. Convert only these records of the store. Leave empty to convert every spreadsheet record in the store.

## `datasetIds` (type: `array`):

Optional. Pick Apify datasets, for example the results of another Actor. Each dataset becomes one CSV, XLSX, JSON or JSON Lines file.

## `pastedData` (type: `string`):

Optional. Paste CSV, TSV, JSON or JSON Lines text, or a base64 file of any supported format, for example from n8n, Make or an API call. Up to 4 MB. For larger files, use a URL or a key-value store. The format is detected like a downloaded file.

## `pastedFileName` (type: `string`):

Name for the pasted data in the results and output files. The Actor adds the detected extension.

## `outputFormat` (type: `string`):

Dataset rows: each row becomes one dataset item, which you can export from Apify in any format. The file formats save one file per sheet (XLSX: one workbook per input file) in the run's key-value store.

## `mergeIntoOneFile` (type: `boolean`):

Append the rows of every file and sheet into one output with the union of all columns. Turn on 'Add source columns' to see where each row came from.

## `csvBom` (type: `boolean`):

Turn on when you open the CSV in Excel and the file has accents or non-Latin text, such as Arabic or Chinese. Excel then reads it as UTF-8.

## `maxRowsPerFile` (type: `integer`):

Stop reading a file after this many saved rows. 0 means all rows.

## `maxFiles` (type: `integer`):

Convert at most this many files in one run. The Actor converts at most 1,000 files per run.

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

Sheet names or tab numbers (1 is the first tab) to convert. Leave empty to convert every sheet.

## `headerMode` (type: `string`):

Auto finds the first full row of text labels in the first 10 rows and skips title rows above it. First row uses row 1. None names columns column_1, column_2 and so on. Row number uses the row you set below.

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

Used only when Header row is 'Row number below'. Row 1 is the first row of the sheet.

## `inputFormat` (type: `string`):

Auto reads the file's first bytes, so a wrong file extension does not matter. Set a format only when auto-detection picks the wrong one.

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

Auto picks comma, semicolon, tab or pipe from the first lines. Type one character to force it. Type 'tab' for a tab.

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

For CSV and TSV files. Auto reads a byte order mark, then checks for UTF-8, then falls back to Latin-1.

## `jsonPath` (type: `string`):

For JSON files whose records sit inside an object, for example 'data.items'. Leave empty to use a top-level list or the first list inside the object.

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

Turn CSV text such as '12.5', '1,200' and 'true' into numbers and booleans, and ISO dates into dates. Codes with leading zeros, such as '008', stay text. Spreadsheet cells keep the type they have in the file.

## `decimalComma` (type: `boolean`):

Turn on for European CSV files where '1.234,5' means one thousand two hundred thirty-four and a half.

## `dateOrder` (type: `string`):

Convert text dates such as '03/04/2026' to ISO dates. Choose the order your file uses. 'Leave as text' keeps them unchanged.

## `columns` (type: `array`):

Column names to keep, in this order. Use the names in the file (nested JSON fields as 'parent.child'). Leave empty to keep every column.

## `renameColumns` (type: `object`):

Map old column names to new ones, for example {"Entity": "country"}.

## `dedupeBy` (type: `array`):

Keep only the first row for each value of these columns. Use \* to remove rows that are identical in every column. Leave empty to keep duplicates.

## `filters` (type: `array`):

Keep only rows that match. One rule per line: column, operator, value, for example "Price >= 10" or "Country = Jordan". Operators: =, !=, <, <=, >, >=, contains, starts with, is empty, is not empty. Numbers compare as numbers; text compares ignore case. Filtered rows are free.

## `filterMode` (type: `string`):

Keep a row when it matches all rules, or any one rule.

## `sortBy` (type: `array`):

Sort rows by these columns. Add " desc" after a name for largest first, for example "Price desc". Sorting holds the rows in memory: up to about 1,000,000 short rows at 512 MB. A row limit applies before sorting.

## `flattenNested` (type: `string`):

Turn nested objects into 'parent.child' columns. Auto flattens for CSV, TSV and XLSX outputs and keeps nesting for JSON, JSON Lines and dataset outputs.

## `arrayMode` (type: `string`):

How flattening handles lists. Join puts simple lists in one cell, separated by '; '. Index makes one column per position ('tags.0', 'tags.1'). JSON keeps the list as JSON text.

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

Drop rows where every cell is empty.

## `trimValues` (type: `boolean`):

Remove spaces at the start and end of text cells. Cells that become empty are saved as empty.

## `addSourceColumns` (type: `boolean`):

Add \_file, \_sheet and \_row to each row, so you can trace every row back to its file, sheet and row number.

## `maxFileMegabytes` (type: `integer`):

Skip files larger than this. CSV, TSV, JSON Lines and XLSX are read as streams. XLS, ODS, XLSB and JSON are read whole and have a lower limit that depends on the run memory (32 MB at 512 MB).

## Actor input object example

```json
{
  "fileUrls": [
    "https://raw.githubusercontent.com/datasets/currency-codes/main/data/codes-all.csv"
  ],
  "keyValueStoreKeys": [],
  "pastedFileName": "pasted",
  "outputFormat": "dataset",
  "mergeIntoOneFile": false,
  "csvBom": false,
  "maxRowsPerFile": 0,
  "maxFiles": 1000,
  "sheets": [],
  "headerMode": "auto",
  "headerRowNumber": 1,
  "inputFormat": "auto",
  "delimiter": "auto",
  "encoding": "auto",
  "jsonPath": "",
  "inferTypes": true,
  "decimalComma": false,
  "dateOrder": "none",
  "columns": [],
  "renameColumns": {},
  "dedupeBy": [],
  "filters": [],
  "filterMode": "all",
  "sortBy": [],
  "flattenNested": "auto",
  "arrayMode": "join",
  "skipEmptyRows": true,
  "trimValues": true,
  "addSourceColumns": false,
  "maxFileMegabytes": 100
}
```

# Actor output Schema

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

No description

## `files` (type: `string`):

No description

## `summary` (type: `string`):

No description

# 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 = {
    "fileUrls": [
        "https://raw.githubusercontent.com/datasets/currency-codes/main/data/codes-all.csv"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("maliksaid/spreadsheet-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 = { "fileUrls": ["https://raw.githubusercontent.com/datasets/currency-codes/main/data/codes-all.csv"] }

# Run the Actor and wait for it to finish
run = client.actor("maliksaid/spreadsheet-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 '{
  "fileUrls": [
    "https://raw.githubusercontent.com/datasets/currency-codes/main/data/codes-all.csv"
  ]
}' |
apify call maliksaid/spreadsheet-converter --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,maliksaid/spreadsheet-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/fBPvFK4ZfzuOix9uw/builds/TVjrT7Ph4KsbEp7Jf/openapi.json
