# CSV & Excel to Dataset: Convert XLSX, CSV & JSON Files to Rows (`charlesmarkette/csv-excel-to-dataset-xlsx-json-converter`) Actor

Turn public CSV, TSV, Excel (XLSX, XLSM, XLS) and JSON/JSONL files into dataset rows, one item per row with the column headers as keys. Works with Google Sheets, Google Drive and Dropbox share links. Chain the rows into other Actors or export them.

- **URL**: https://apify.com/charlesmarkette/csv-excel-to-dataset-xlsx-json-converter.md
- **Developed by:** [Charles Markette](https://apify.com/charlesmarkette) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $21.00 / 1,000 converted 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

## CSV & Excel to Dataset: Convert XLSX, CSV & JSON Files to Rows

**CSV & Excel to Dataset** turns public **CSV, TSV, Excel (XLSX, XLSM, XLS) and JSON / JSON Lines** files into an Apify dataset, **one item per row** with the **column headers as keys**. Paste file links, including **Google Sheets**, **Google Drive** and **Dropbox** share links, and you get clean rows you can chain into other Actors (filter, deduplicate, enrich, sync to Google Sheets) or export as JSON, CSV or Excel through the Apify API.

### Why this Actor

- **Every common format, detected from the content.** ZIP-based workbooks are read as XLSX/XLSM, OLE files as legacy XLS, files starting with `[` or `{` as JSON or JSON Lines, and everything else as delimited text. Links like `/download?id=42` or `/export` work without an extension.
- **Share links just work.** A Google Sheets edit or share link is turned into its export link (CSV for one tab, keeping the `#gid=` tab in the link, or XLSX when you ask for all sheets). Published-to-web sheets work too. Google Drive file links (`/file/d/…/view`) become direct downloads, and Dropbox `?dl=0` links become `?dl=1`.
- **Messy CSVs handled.** Comma, semicolon, tab or pipe delimiters are detected automatically (Excel's `sep=;` line is understood). Encodings are detected: UTF-8 with or without BOM, UTF-16 (Excel's "Unicode text"), then Windows-1252 for files saved by older Excel versions. Quoted line breaks, `"a", "b"` spacing, empty and duplicate headers (`name`, `name_2`) and rows with too many or too few cells are all handled.
- **Values stay exactly as written by default.** CSV values are text unless you turn on type conversion, so ZIP codes like `00123` keep their zeros. Excel cells keep their type: numbers, booleans, and dates as ISO 8601 (`2024-03-01`, `2024-03-01T14:30:00`).
- **Every sheet, or the ones you name.** Read the first sheet, all sheets, or a list of sheet names. Each row records its file, sheet and row number (`_file`, `_sheet`, `_row`), so you can trace any value back to the cell.
- **One bad file never stops the run.** A missing, private, oversized or unreadable file gets one error row that explains the problem, and that row is free.
- **Guards against risky links.** Downloads to private, loopback, link-local and cloud-metadata addresses are refused, on the first request and on every redirect (at most 5). The file size is capped while downloading. Workbooks that would unpack to an unsafe size (zip bombs) are refused before they are opened. Macros never run, and formulas are never calculated: you get the results last saved in the file.
- **Streams large files.** Rows are read and stored in batches of 500, so CSV files with millions of rows fit in the default 1 GB of memory. Very large Excel files can need 2–4 GB (see the limits below).

### Use cases

- **Import a spreadsheet into an Apify workflow:** a list of URLs, products, keywords or leads that someone keeps in Excel or Google Sheets becomes a dataset that a scraper or enrichment Actor can read.
- **Load open-data files:** government and research CSV, XLSX and JSON downloads as rows, ready to filter and export.
- **Combine many files:** convert a folder's worth of monthly CSV or Excel exports in one run, with `_file` and `_sheet` telling the rows apart, then deduplicate them.
- **Clean up JSON exports:** API dumps and JSON Lines logs become flat rows (nested objects are kept as they are).
- **Scheduled sync from a shared sheet:** run on a schedule against a published Google Sheet and send only the new rows onward with Merge & Deduplicate Datasets.

### How to use it

1. Add your **File URLs**, one per line. Google Sheets must be shared as "Anyone with the link" (or published to the web); Google Drive and Dropbox files must be shared by link.
2. For Excel files, choose **Which sheets**: first, all, or named. If the column names aren't in the first row, set **Header row number** (0 = no header row).
3. Optional: **Convert numbers and true/false in text files**, **Trim spaces around values**, a fixed **Delimiter** or **Text encoding**, a **JSON path** like `data.items`, and row limits.
4. Run it. Each row becomes one item in the dataset. A per-file summary is saved as `OUTPUT` in the key-value store.

**Input example**

```json
{
  "fileUrls": [
    "https://example.com/exports/customers.csv",
    "https://docs.google.com/spreadsheets/d/1AbC.../edit#gid=0",
    "https://www.dropbox.com/scl/fi/abc123/orders-2026.xlsx?rlkey=xyz&dl=0",
    "https://example.com/api/products.json"
  ],
  "sheets": "all",
  "headerRow": 1,
  "skipEmptyRows": true,
  "inferTypes": false,
  "addSourceFields": true,
  "maxFileSizeMb": 100
}
```

| Field | Notes |
|---|---|
| File URLs | Public links to CSV, TSV, TXT, XLSX, XLSM, XLS, JSON or JSON Lines files. Google Sheets, Google Drive and Dropbox share links are converted for you. |
| Which sheets | First sheet (default), all sheets, or only the sheets named under **Sheet names**. Applies to Excel files and Google Sheets. |
| Header row number | The row with the column names (default 1). Rows above it are skipped. 0 = no header: columns are `column1`, `column2`, … |
| Skip empty rows | On by default. |
| Trim spaces around values | Strips spaces at the start and end of text values. Column names stay exactly as written. |
| Convert numbers and true/false in text files | CSV/TSV only: `42` → 42, `TRUE` → true, empty → null. Leading-zero numbers, numbers over 15 digits and numbers with thousands separators stay text. |
| Delimiter / Text encoding | Auto by default. |
| JSON path | Dotted path to the list to read, e.g. `data.items` (numbers pick a list element, e.g. `results.0.rows`). |
| Add \_file, \_sheet and \_row | On by default. |
| Max rows per file / Max output rows | Optional caps. |
| Max file size (MB) | Default 100, up to 500. |

### Output example

A sheet like this:

| Name | Age | Joined | Active |
|---|---|---|---|
| Ada | 36 | 2024-03-01 | TRUE |

becomes:

```json
{
  "Name": "Ada",
  "Age": 36,
  "Joined": "2024-03-01",
  "Active": true,
  "_file": "https://example.com/team.xlsx",
  "_sheet": "People",
  "_row": 2
}
```

- `_row` is the row's number in the file or sheet as you'd see it in Excel, counting the header row (so the first data row is usually 2). `_sheet` is null for CSV and JSON files. For JSON, `_row` is the element's position in the list (or the line number in JSON Lines).
- Empty column names become `column{N}` (N = the column's position), repeated names become `name_2`, `name_3`, and cells beyond the last header become `column{N}`. Missing cells at the end of a short row are null.
- JSON arrays of objects become one item per object, nested values included; other elements become `{"value": …}`. An object with exactly one list of objects inside is read from that list.
- A file that fails gets one row with just `_file` and `error`, for example `{"_file": "https://docs.google.com/…", "error": "File isn't public: share it as 'Anyone with the link' or publish it"}`.

The key-value store record **`OUTPUT`** summarises the run:

```json
{
  "files": [
    {"url": "https://example.com/team.xlsx", "format": "xlsx", "sheets": [{"name": "People", "rows": 25000}], "rows": 25000,
     "rowBlocksCharged": 24, "formulaLikeCells": 0, "error": null, "charged": true, "fileSizeBytes": 812345},
    {"url": "https://example.com/missing.csv", "format": null, "rows": 0, "rowBlocksCharged": 0, "error": "HTTP 404 Not Found",
     "charged": false}
  ],
  "filesConverted": 1,
  "filesFailed": 1,
  "rows": 25000,
  "fileEventsCharged": 1,
  "rowBlocksCharged": 24,
  "formulaLikeCells": 0,
  "duplicateUrlsSkipped": 0,
  "filesNotProcessed": 0,
  "stoppedBy": null
}
```

CSV and JSON files also report the detected `encoding` and `delimiter`, and files cut short by **Max rows per file** have `truncated: true`.

### How much does it cost?

Pay per event, Apify platform usage included:

- **$0.03 per converted file** (`file-converted`): each file that was read successfully, with all the sheets you chose. It covers the file's first 1,000 rows.
- **$0.015 per 1,000 more rows** (`rows-1000`): each further started block of 1,000 rows from the same file (rows 1,001–2,000 are one block, 2,001–3,000 the next, and so on).

**Apify Store discounts:** the prices above are for Apify's Free plan. Paid plans pay less: per converted file $0.027 on Starter, $0.024 on Scale, $0.021 on Business; per 1,000 more rows $0.0135, $0.012 and $0.0105. The "from" price at the top of the Store page is the Business price.

- Rows are counted per file, after skipped empty rows and your row limits. Small files cost only the file price.
- Free: files that fail (not found, not public, too large, not a spreadsheet, damaged, blocked addresses, invalid URLs), files with no data rows, and repeats of a URL already in the list. The run start still applies to every run, even one where every file fails.

**Worked examples:**

*Examples use the Free-plan rate. Where an example doesn't add it, each run also has its run-start charge of $0.005 per GB of Actor memory (minimum one; at the default 1 GB that's $0.005 a run). Apify platform usage is included.*

- 10 CSV files of up to 1,000 rows each: 10 × $0.03 = **$0.30**.
- One file with 25,000 rows: $0.03 + 24 × $0.015 = **$0.39**.
- An Excel workbook with three sheets of 800 rows each, read with "All sheets" (2,400 rows): $0.03 + 2 × $0.015 = **$0.06**.
- 100 links where 20 return 404 and 80 are small CSVs: 80 × $0.03 = **$2.40**.

If you set a maximum cost per run, the Actor charges each file (and each further block of 1,000 rows) before storing its rows, and stops cleanly when the budget runs out. The Actor never outputs rows it hasn't charged for.

### FAQ and limits

#### My Google Sheet returns "File isn't public".

The Actor can only read files anyone can open, without a sign-in. In Google Sheets, click **Share → General access → Anyone with the link (Viewer)**, or use **File → Share → Publish to web**. Sheets restricted to your organisation can't be read. Very large Google Drive files show a "can't scan for viruses" page; the Actor then retries Google's direct download link once.

#### Is OneDrive or SharePoint supported?

No. Their share links need a sign-in or a browser. Download the file and share it from Google Drive or Dropbox, or host it at any public URL.

#### Do formulas work?

You get the **result that was last saved** in the file, as Excel shows it. Nothing is recalculated. Files generated by some tools (not by Excel or Google Sheets) never store formula results, and those cells come back as null. Macros (XLSM) are never run.

#### Why are my CSV numbers strings?

By default, values are kept exactly as they appear in the file, which protects IDs, phone numbers and ZIP codes. Turn on **Convert numbers and true/false in text files** to get numbers and booleans. Excel and JSON values always keep their own types.

#### How are dates returned?

Excel dates become ISO 8601 text: `2024-03-01` for a date, `2024-03-01T14:30:00` with a time. Spreadsheets don't store a time zone, so none is added. A Google Sheet read through its CSV export (the first sheet, or one tab) gives the values as displayed in the sheet; with "All sheets" it's read as XLSX and dates come back as ISO 8601.

#### What is `formulaLikeCells` in the summary?

The number of text values that start with `=`, `+`, `-` or `@` (not counting plain numbers like `-5`). They are stored as text, unchanged. If you export the dataset to CSV or Excel later and open it in a spreadsheet app, such values may be run as formulas, so check or escape them before sharing the export.

#### Can it open password-protected workbooks?

No. They return a free error row. Remove the password and share the file again.

#### Other limits

- Public URLs only (http and https); no logins, cookies or API keys.
- Up to 500 MB per file (default 100 MB). A single cell can be up to 10 MB, a single JSON element up to 64 MB, and JSON Lines lines that aren't valid JSON are skipped (counted in `skippedLines`).
- Not supported: XLSB, ODS, Numbers, Excel 2003 XML, HTML tables, PDFs, and compressed or archived files (.gz, .zip of CSVs).
- Apify stores items of up to 9 MB: an item with longer text is shortened and marked `_truncated: true` (an item that still can't fit, such as one huge nested JSON value, is skipped and counted in `skippedTooLarge`).
- Very large XLSX files with a lot of text keep their shared text table in memory. If a run runs out of memory, give it 2–4 GB.
- Very large files are charged per block of 1,000 rows (see pricing). Use **Max rows per file** to preview a big file cheaply.

### Related Actors

| Actor | Use it to |
|---|---|
| [Dataset Join & VLOOKUP](https://apify.com/charlesmarkette/dataset-join-vlookup-merge-by-key) | Match the converted rows against another dataset or file by a shared key. |
| [Merge & Deduplicate Datasets](https://apify.com/charlesmarkette/merge-deduplicate-datasets-only-new-items) | Combine the rows of several runs or files and remove duplicates, or keep only rows that are new since the last run. |
| [Dataset Filter & Transform](https://apify.com/charlesmarkette/dataset-filter-transform-rename-flatten-fields) | Filter rows, keep or rename columns, drop `_file`/`_sheet`/`_row`, or flatten nested JSON fields. |
| [Google Sheets Sync](https://apify.com/charlesmarkette/google-sheets-sync) | Append or upsert the converted rows into a Google Sheet. |
| [Dataset Delivery](https://apify.com/charlesmarkette/dataset-delivery-export-to-sftp-ftp-dropbox-google-drive) | Deliver the rows as a CSV, JSON or Excel file to SFTP, FTP, Dropbox or Google Drive. |
| [PDF & Image to Text](https://apify.com/charlesmarkette/pdf-image-to-text-markdown-ocr) | For PDFs and scans instead of spreadsheets: text, Markdown and tables, with OCR. |

Built with permissively licensed open-source software: [openpyxl](https://foss.heptapod.net/openpyxl/openpyxl) (MIT) for XLSX/XLSM, [xlrd](https://github.com/python-excel/xlrd) (BSD) for XLS, and [defusedxml](https://github.com/tiran/defusedxml) (PSF) to read workbook XML safely.

# Actor input Schema

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

One per line. Public links to CSV, TSV, TXT (delimited), Excel (XLSX, XLSM, XLS) or JSON / JSON Lines files. The format is detected from the file's content, so links without an extension work. Google Sheets and Google Drive links (shared as 'Anyone with the link') and Dropbox shared links are turned into download links for you. OneDrive and SharePoint links aren't supported.

## `sheets` (type: `string`):

First: only the first sheet (tab) of each workbook. All: every sheet, each row tagged with its sheet name in \_sheet. Named: only the sheets listed below. For a Google Sheets link with First, the tab in the link (#gid=…) is used.

## `sheetNames` (type: `array`):

Used with 'Only the sheets named below'. Exact names first, then ignoring upper/lower case and extra spaces.

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

The row that holds the column names (1 = the first row). Rows above it are skipped. 0 = the file has no header row: columns are named column1, column2, …

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

Leave out rows where every cell is empty.

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

Remove spaces, tabs and line breaks at the start and end of each text value. Column names are kept exactly as written.

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

Off: CSV/TSV values stay text exactly as in the file. On: numbers become numbers, true/false become booleans and empty cells become null. Numbers with leading zeros (ZIP codes, IDs), very long numbers and numbers with thousands separators stay text. Excel cells are always typed as in the workbook (numbers, booleans, dates as ISO 8601).

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

Auto detects comma, semicolon, tab or pipe from the start of the file (and honours Excel's sep= line).

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

auto: UTF-16 if the file starts with its byte-order mark, then UTF-8 (with or without BOM), then Windows-1252, then Latin-1. Or name one, e.g. utf-8, windows-1252, latin-1, iso-8859-2, windows-1251, shift_jis, gb18030.

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

Optional. For JSON files: the dotted path to the list to read, e.g. data.items or results. Without it, a top-level list is read, or the only list of objects inside a top-level object.

## `addSourceFields` (type: `boolean`):

Add the original URL (\_file), the sheet name (\_sheet, null for CSV and JSON) and the row's 1-based number in the file or sheet as you'd see it in Excel (\_row) to every row.

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

Optional. Read at most this many rows from each file (all chosen sheets together).

## `maxResults` (type: `integer`):

Optional. Stop the run after this many rows in total.

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

Bigger files are skipped with a free error row. Up to 500 MB.

## Actor input object example

```json
{
  "fileUrls": [
    "https://people.sc.fsu.edu/~jburkardt/data/csv/airtravel.csv"
  ],
  "sheets": "first",
  "headerRow": 1,
  "skipEmptyRows": true,
  "trimValues": false,
  "inferTypes": false,
  "delimiter": "auto",
  "encoding": "auto",
  "addSourceFields": true,
  "maxFileSizeMb": 100
}
```

# Actor output Schema

## `items` (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://people.sc.fsu.edu/~jburkardt/data/csv/airtravel.csv"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("charlesmarkette/csv-excel-to-dataset-xlsx-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 = { "fileUrls": ["https://people.sc.fsu.edu/~jburkardt/data/csv/airtravel.csv"] }

# Run the Actor and wait for it to finish
run = client.actor("charlesmarkette/csv-excel-to-dataset-xlsx-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 '{
  "fileUrls": [
    "https://people.sc.fsu.edu/~jburkardt/data/csv/airtravel.csv"
  ]
}' |
apify call charlesmarkette/csv-excel-to-dataset-xlsx-json-converter --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,charlesmarkette/csv-excel-to-dataset-xlsx-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/Tmq8m1glET9TPaVtM/builds/iDLjrmDseuppDl4Ra/openapi.json
