# Excel XLSX to JSON and CSV Converter (`plainpipe/xlsx-to-json`) Actor

Convert Excel .xlsx workbooks to JSON rows keyed by the header row, plus a CSV per sheet. Use when you need spreadsheet data as JSON or CSV for code or an API.

- **URL**: https://apify.com/plainpipe/xlsx-to-json.md
- **Developed by:** [Plain Pipe](https://apify.com/plainpipe) (community)
- **Categories:** Developer tools, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.50 / 1,000 results

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

## Excel XLSX to JSON and CSV Converter

Convert Excel .xlsx workbooks to JSON: one row per spreadsheet row keyed by the header row, with sheet and row numbers, plus a CSV file of every sheet.

**Use this when:** you have an .xlsx file (link or upload) and need its rows as JSON objects or CSV, one record per spreadsheet row.

### Why this one

- $0.50 per 1,000 results, one result per spreadsheet row; the CSV files and the run summary are free.
- Every row includes `_file`, `_sheet` and `_rowNumber`, so each value traces back to its exact cell row in the workbook.
- Dates come out as ISO 8601 text (or raw serial numbers on request) and formulas return their calculated value; header row, sheet filter and empty-row skipping are configurable.
- No browser, no proxy, no Excel install. The prefilled example (17 rows) finishes in under 4 seconds in our test runs, and 7 edge-case inputs are checked before each release.

### What it does

Give it links to Excel workbooks or upload one. It opens each .xlsx file with the open-source exceljs library and returns one dataset result for every spreadsheet row. Column names come from the header row you choose, and each result also carries `_file` (the file name), `_sheet` (the sheet name) and `_rowNumber` (the row number as Excel shows it), so you can trace every value back to its cell. Formulas return their last calculated result, dates come out as ISO 8601 text or Excel serial numbers, and rich text and hyperlinks come out as plain text.

As a free extra, every converted sheet is also saved as a CSV file in the run's key-value store, and the `OUTPUT` record lists each file, sheet, column list, row count and CSV link.

### Use cases

- Load a spreadsheet that colleagues keep in Excel into a database, an API or a script as clean JSON.
- Turn every sheet of a workbook into a separate CSV file without opening Excel.
- Feed price lists, inventories or survey exports into no-code tools and LLM pipelines on a schedule.
- Convert one chosen sheet (for example `Orders`) from many workbooks into one dataset with the source file and row number on each row.

### How to use it

1. Paste .xlsx links into **Excel file URLs**, or upload a workbook in **Upload an Excel file**.
2. Optional: list the **Sheets** to convert and set the **Header row** if the column names are not on row 1.
3. Optional: choose the **Date format** and whether to **Keep value types**.
4. Set **Max results** and run the Actor.
5. Export the dataset as JSON, CSV or Excel, or read it through the Apify API. Per-sheet CSV files are in the key-value store, linked from the `OUTPUT` record.

### Input

| Field | What it does | Default | Example |
| --- | --- | --- | --- |
| `fileUrls` | Direct links to .xlsx workbooks | none | `["https://raw.githubusercontent.com/pandas-dev/pandas/main/pandas/tests/io/data/excel/test1.xlsx"]` |
| `excelFile` | One uploaded .xlsx workbook, instead of or in addition to links | none | an uploaded `sales-report.xlsx` |
| `sheets` | Names of the sheets to convert, not case sensitive; empty means every sheet | `[]` | `["Orders"]` |
| `headerRow` | Row number with the column names; rows above it are ignored; `0` means no header (columns `column_A`, `column_B`, ...) | `1` | `3` |
| `skipEmptyRows` | Leave out rows where every cell is empty (not charged) | `true` | `false` |
| `dateFormat` | `iso` for ISO 8601 text, `raw` for Excel serial numbers | `iso` | `raw` |
| `rawValues` | Keep numbers and booleans typed; off returns every value as text | `true` | `false` |
| `maxItems` | Stop after this many rows in total across all files and sheets | `100` | `50000` |

Blank header cells become `column_<letter>`. Repeated header names get `_2`, `_3` and so on, so no value is lost.

### Output

One result per spreadsheet row. Example from the prefilled input (a public test workbook from the pandas project):

```json
{
  "_file": "test1.xlsx",
  "_sheet": "Sheet1",
  "_rowNumber": 2,
  "column_A": "2000-01-03",
  "A": 0.980268513777,
  "B": 3.68573087906,
  "C": -0.364216805298,
  "D": -1.15973806169
}
```

| Field | Meaning |
| --- | --- |
| `_file` | File name of the workbook |
| `_sheet` | Sheet name |
| `_rowNumber` | Row number as Excel shows it |
| your columns | One field per column, named from the header row |

The `OUTPUT` record in the key-value store (not charged) looks like this:

```json
{
  "files": [
    {
      "source": "https://raw.githubusercontent.com/pandas-dev/pandas/main/pandas/tests/io/data/excel/test1.xlsx",
      "sheets": [
        { "name": "Sheet1", "columns": ["column_A", "A", "B", "C", "D"], "rows": 7, "rowsReturned": 7,
          "csvKey": "file1-Sheet1.csv", "csvUrl": "https://api.apify.com/v2/key-value-stores/.../records/file1-Sheet1.csv" }
      ]
    }
  ],
  "totalRows": 17,
  "maxItemsReached": false
}
```

### Pricing

Pay per result: **$0.50 per 1,000 results** ($0.0005 per result). One result is one spreadsheet row. You only pay for rows the Actor returns; the CSV files and the `OUTPUT` summary are free. Set a maximum total charge on the run to cap your spend.

### Limits

- Only .xlsx (Excel 2007 and newer). Old binary .xls, .ods, .csv and encrypted (protected) workbooks are skipped and not charged; save them as .xlsx first.
- Files up to 50 MB. Links must point straight at the file. Very large sheets need more memory; raise the run memory if a big workbook fails.
- Number formats are not applied: a cell shown as `12%` or `$1,200.00` in Excel comes out as `0.12` or `1200`. With `rawValues` off you get the same values as text.
- Formulas are not recalculated; the result saved in the file is returned. Files written by tools that do not store results give `null` for formula cells.
- Merged cells repeat the top-left value in each covered cell. Charts, images, comments and styles are not extracted.
- The CSV files hold every data row of each converted sheet; the dataset stops at `maxItems`.

### FAQ

**How much does it cost to convert a workbook?**
You pay per returned row: a sheet with 2,000 rows costs $1.00. Empty rows, the CSV files and the summary are free, and `maxItems` caps the total.

**Why was my file skipped?**
The run log gives the reason per file: the link returned a web page instead of the file, the file is an old .xls or a CSV, it is encrypted, or none of the requested sheet names exist (the log lists the sheet names it found).

**My column names are on row 3. What do I do?**
Set `headerRow` to `3`. Rows above it are ignored. Set it to `0` when the sheet has no header row at all.

**Can I merge the converted sheets or remove duplicates?**
Yes. Pass the per-sheet CSV links from `OUTPUT` to the Plain Pipe Actor **Merge CSV Files and Remove Duplicates**, or reshape the JSON rows with **JSON Transformer with jq Filters**.

**Can I run it on a schedule or from my own code?**
Yes. Use Apify Schedules to convert a workbook that is updated at the same link, or start runs and read the dataset through the Apify API, webhooks or integrations such as Make and Zapier.

### Legal and data

This Actor processes only what you give it or public, non-personal technical data. It does not log in anywhere, does not collect personal data, and does not bypass paywalls, CAPTCHAs or access controls. You are responsible for having the right to process the inputs you provide.

### Support

Open an issue on the Issues tab. Issues are answered within 14 days.

Built and maintained by Plain Pipe.

# Actor input Schema

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

Direct links to Excel .xlsx workbooks, one per line, e.g. https://raw.githubusercontent.com/pandas-dev/pandas/main/pandas/tests/io/data/excel/test1.xlsx. The link must return the file itself, not a web page that shows it.

## `excelFile` (type: `string`):

Or upload one .xlsx workbook here instead of (or in addition to) giving URLs. Example: a sales-report.xlsx from your computer.

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

Names of the sheets to convert, not case sensitive, e.g. Sheet1 or Orders. Leave empty (default) to convert every sheet.

## `headerRow` (type: `integer`):

Row number that holds the column names (default 1 = first row), e.g. 3 when the sheet starts with a title block. Rows above it are ignored. Use 0 when the sheet has no header row; columns are then named column_A, column_B and so on.

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

On (default): leave out rows where every cell is empty. Skipped rows are not returned and not charged.

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

iso (default): dates as ISO 8601 text, e.g. 2024-05-31 or 2024-05-31T14:30:00Z. raw: dates as Excel serial numbers (days since 1899-12-30), e.g. 45443.

## `rawValues` (type: `boolean`):

On (default): numbers stay numbers and TRUE/FALSE stay booleans, e.g. 0.98. Off: every cell value is returned as text, e.g. "0.98". Formulas always return their last calculated result.

## `maxItems` (type: `integer`):

Stop after this many spreadsheet rows in total across all files and sheets (default 100, e.g. 50000 for a large sheet). You are charged per returned row.

## Actor input object example

```json
{
  "fileUrls": [
    "https://raw.githubusercontent.com/pandas-dev/pandas/main/pandas/tests/io/data/excel/test1.xlsx"
  ],
  "sheets": [],
  "headerRow": 1,
  "skipEmptyRows": true,
  "dateFormat": "iso",
  "rawValues": true,
  "maxItems": 20
}
```

# Actor output Schema

## `results` (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/pandas-dev/pandas/main/pandas/tests/io/data/excel/test1.xlsx"
    ],
    "sheets": [],
    "headerRow": 1,
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("plainpipe/xlsx-to-json").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/pandas-dev/pandas/main/pandas/tests/io/data/excel/test1.xlsx"],
    "sheets": [],
    "headerRow": 1,
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("plainpipe/xlsx-to-json").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/pandas-dev/pandas/main/pandas/tests/io/data/excel/test1.xlsx"
  ],
  "sheets": [],
  "headerRow": 1,
  "maxItems": 20
}' |
apify call plainpipe/xlsx-to-json --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,plainpipe/xlsx-to-json"
        }
    }
}
```

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/KKJsE4i2FAu1iN2kr/builds/iRePrAZ9pWBd4t1kU/openapi.json
