# CSV Combiner | 💾 Merge CSV Files with Custom Column Order (`amr-mando/csv-combiner`) Actor

Combine up to three CSV files into one. Columns are matched by header name, so data stays under the right column even when the files order their columns differently. You choose the output column order.

- **URL**: https://apify.com/amr-mando/csv-combiner.md
- **Developed by:** [Mando](https://apify.com/amr-mando) (community)
- **Categories:** Lead generation, E-commerce, Automation
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.10 / actor start

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## 🧩 CSV Combiner

Combine up to three CSV files into one. Columns are matched by their header name, so every value stays under the correct column even when the files list their columns in a different order. You decide the final column order.

---

### 📌 What it does

You have two or three CSV exports that hold the same kind of data but do not line up. One file has `Name, Email, Domain`, another has `Domain, Email, Name`, a third uses lowercase `email`. Pasting them together by hand mixes the data under the wrong headers.

This actor:

1. Reads each file by its **header names**, not by column position.
2. Matches columns across files (matching is **not case-sensitive**, so `Email`, `EMAIL`, and `email` are the same column).
3. Stacks every row into one combined CSV, each value placed under its correct header.
4. Writes the output in the **column order you choose**.

No row is removed. Every row from every file ends up in the output.

---

### 📥 Input

#### Input CSV Files

| Field | Required | Notes |
|-------|----------|-------|
| 📄 CSV 1 | Yes | The first file. |
| 📄 CSV 2 | No | Optional second file. |
| 📄 CSV 3 | No | Optional third file. |

You can run with 1, 2, or 3 files. Files do not need the same columns or the same column order.

#### 🧩 Output Column Order

A single dropdown controls the column order of the combined output:

- **📄 Use CSV 1 / 2 / 3 column order** - the output follows that file's header order. Any column that exists only in the other files is added at the end, with an `extra_` prefix on its name (for example `extra_Phone`). Nothing is dropped.
- **✍️ Custom order** - you type the exact column order you want in the text box below the dropdown.

#### ✍️ Custom Column Order

Used only when **Custom order** is selected. Write the column header names you want, **one per line** (press Enter between each, no commas):

````

Name
Email
Company
Domain

```

Rules for custom order:

- Order is exactly what you type, top to bottom.
- Matching is not case-sensitive. Typing `email` matches a `Email` column.
- The output keeps the original header casing from the file, not what you typed.
- Any combined column you do **not** list is **dropped** from the output.
- Any name you type that matches no column is skipped and reported in the log.

---

### 🔗 How columns are matched

Matching is by header name, lowercased and trimmed:

| CSV 1 header | CSV 2 header | Treated as |
|--------------|--------------|------------|
| `Email`      | `email`      | one column |
| `Domain `    | `domain`     | one column |
| `Job Title`  | `job title`  | one column |

When a file is missing a column that another file has, that cell is left blank for the rows from the file that lacks it.

---

### 📊 Log

The log opens with a short summary so you can see what happened before you download anything.

CSV 1 / 2 / 3 order:

```

📥 Loaded CSV files:
CSV 1: 500 rows, 12 columns
CSV 2: 320 rows, 10 columns
CSV 3: 150 rows, 14 columns

🧩 Combined rows: 970

📊 Column analysis (across all files):
Total unique columns: 20
Columns with data:    15
Empty columns:        5
Empty: Fax, Middle Name, Region, Notes, Suffix

📋 Output column order: CSV 1
12 columns from CSV 1, in its order

- 8 extra column(s) from the other files, appended with the "extra\_" prefix:
  extra\_Phone, extra\_LinkedIn, extra\_Title, ...

```

Custom order:

```

📊 Column analysis (across all files):
Total unique columns: 20
Columns with data:    15
Empty columns:        5

📋 Output column order: Custom (14 columns)
Order: Domain, Name, Email, Company, ...
⚠️ 1 name(s) in your list matched no column and were skipped: emial
❌ 6 column(s) dropped (not in your order): Fax, Region, Notes, Phone, Suffix, Middle Name
Of those, 1 held data: Phone

````

- **Total unique columns**: how many distinct columns exist once all files are combined.
- **Columns with data**: how many of those hold at least one non-empty value. The rest are blank in every row.
- **Dropped (custom order only)**: columns not in your list. The log also tells you how many of the dropped columns actually held data, so you know if you lost anything that mattered.

---

### 📤 Output

- **Dataset**: the combined rows, viewable as a table in the Apify console and available through the API.
- **Key-value store, key `OUTPUT`**: the combined CSV file, in the exact column order you chose, with original header casing. Download this for the clean file.

The output download link is shown on the run's Output tab.

---

### 📋 Example

**CSV 1** (`Name, Email, Company, Domain`)

| Name | Email | Company | Domain |
|------|-------|---------|--------|
| Alice | alice@acme.com | Acme | acme.com |

**CSV 2** (`Domain, Company, Email, Name, Phone`) - different order, extra `Phone`

| Domain | Company | Email | Name | Phone |
|--------|---------|-------|------|-------|
| globex.com | Globex | carol@globex.com | Carol | 555-0100 |

**CSV 3** (`email, name, title`) - lowercase headers, extra `title`, no company or domain

| email | name | title |
|-------|------|-------|
| eve@umbrella.com | Eve | CTO |

**Output column order: CSV 1**

| Name | Email | Company | Domain | extra_Phone | extra_title |
|------|-------|---------|--------|-------------|-------------|
| Alice | alice@acme.com | Acme | acme.com | | |
| Carol | carol@globex.com | Globex | globex.com | 555-0100 | |
| Eve | eve@umbrella.com | | | | CTO |

Carol's data came in as `Domain, Company, Email, Name, Phone` but still lands under the right headers. Eve's lowercase `email` matched `Email`, and her `title` was appended as `extra_title`.

---

### ⚠️ Notes

- Matching is case-insensitive and ignores leading and trailing spaces in headers.
- If two columns inside the **same** file share a header name, only one is kept for that file.
- No rows are removed. Duplicate rows across files are all kept.
- Empty CSVs, or files with no header row, are skipped with a warning. The run continues with the remaining files.

# Actor input Schema

## `csv1` (type: `string`):

Upload the first CSV file. This one is required. Columns are matched across files by their header name, so the column order inside this file does not need to match the others.
## `csv2` (type: `string`):

Upload the second CSV file. Optional. Its columns are matched to CSV 1 by header name. Any header it does not share with CSV 1 is still kept.
## `csv3` (type: `string`):

Upload the third CSV file. Optional. Its columns are matched to the other files by header name.
## `columnOrderSource` (type: `string`):

Choose which column order the combined CSV should follow. Pick one of the uploaded files to reuse its header order; columns that exist only in the other files are appended at the end with an "extra_" prefix so nothing is lost. Pick "Custom order" to type your own order in the field below, which also drops any column you leave out.
## `customColumnOrder` (type: `string`):

Only used when "Custom order" is selected above. Write the column header names in the order you want them, one per line (press Enter between each, no commas). Matching is not case-sensitive. Any combined column you do not list here is dropped from the output, and the log reports exactly what was dropped and whether it held data.

## Actor input object example

```json
{
  "columnOrderSource": "csv1",
  "customColumnOrder": "Name\nEmail\nCompany\nDomain"
}
````

# Actor output Schema

## `csvOutput` (type: `string`):

No description

## `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 = {
    "customColumnOrder": `Name
Email
Company
Domain`
};

// Run the Actor and wait for it to finish
const run = await client.actor("amr-mando/csv-combiner").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 = { "customColumnOrder": """Name
Email
Company
Domain""" }

# Run the Actor and wait for it to finish
run = client.actor("amr-mando/csv-combiner").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "customColumnOrder": "Name\\nEmail\\nCompany\\nDomain"
}' |
apify call amr-mando/csv-combiner --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=amr-mando/csv-combiner",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "CSV Combiner | 💾 Merge CSV Files with Custom Column Order",
        "description": "Combine up to three CSV files into one. Columns are matched by header name, so data stays under the right column even when the files order their columns differently. You choose the output column order.",
        "version": "0.1",
        "x-build-id": "McdO6PMXcAWXP4pz8"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/amr-mando~csv-combiner/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-amr-mando-csv-combiner",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/amr-mando~csv-combiner/runs": {
            "post": {
                "operationId": "runs-sync-amr-mando-csv-combiner",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/amr-mando~csv-combiner/run-sync": {
            "post": {
                "operationId": "run-sync-amr-mando-csv-combiner",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "csv1"
                ],
                "properties": {
                    "csv1": {
                        "title": "📄 CSV 1",
                        "type": "string",
                        "description": "Upload the first CSV file. This one is required. Columns are matched across files by their header name, so the column order inside this file does not need to match the others."
                    },
                    "csv2": {
                        "title": "📄 CSV 2 (optional)",
                        "type": "string",
                        "description": "Upload the second CSV file. Optional. Its columns are matched to CSV 1 by header name. Any header it does not share with CSV 1 is still kept."
                    },
                    "csv3": {
                        "title": "📄 CSV 3 (optional)",
                        "type": "string",
                        "description": "Upload the third CSV file. Optional. Its columns are matched to the other files by header name."
                    },
                    "columnOrderSource": {
                        "title": "🧭 Column Order Source",
                        "enum": [
                            "csv1",
                            "csv2",
                            "csv3",
                            "custom"
                        ],
                        "type": "string",
                        "description": "Choose which column order the combined CSV should follow. Pick one of the uploaded files to reuse its header order; columns that exist only in the other files are appended at the end with an \"extra_\" prefix so nothing is lost. Pick \"Custom order\" to type your own order in the field below, which also drops any column you leave out.",
                        "default": "csv1"
                    },
                    "customColumnOrder": {
                        "title": "✍️ Custom Column Order",
                        "type": "string",
                        "description": "Only used when \"Custom order\" is selected above. Write the column header names in the order you want them, one per line (press Enter between each, no commas). Matching is not case-sensitive. Any combined column you do not list here is dropped from the output, and the log reports exactly what was dropped and whether it held data."
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
