# VCF to CSV Converter (`automation-lab/vcf-to-csv-converter`) Actor

Convert pasted vCard text or public VCF files into normalized, CSV-ready contact rows while preserving repeated phones, emails, addresses, and custom fields.

- **URL**: https://apify.com/automation-lab/vcf-to-csv-converter.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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 web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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

## VCF to CSV Converter

Convert vCard files into normalized contact rows that can be downloaded as CSV, JSON, Excel, XML, or another Apify dataset format.

VCF to CSV Converter accepts pasted VCF text, public `.vcf` URLs, or both. It creates one row per card and keeps repeated phones, emails, addresses, organizations, URLs, notes, and custom fields instead of silently dropping extra values.

### What does VCF to CSV Converter do?

This Actor turns common vCard 2.1, 3.0, and 4.0 contact exports into a stable tabular contract.

It can:

- parse one or many `BEGIN:VCARD` blocks;
- fetch public VCF files over HTTP or HTTPS;
- normalize names into structured components;
- retain every phone, email, address, organization, title, role, and URL;
- preserve type labels such as `work`, `home`, `cell`, and `voice`;
- identify preferred values;
- unfold wrapped vCard lines;
- decode escaped delimiters, newlines, and quoted-printable text;
- retain unknown `X-` fields in `customProperties`;
- stop cleanly at a user-defined contact limit.

The result is CSV-ready: Apify serializes arrays and nested objects into cells when you download the default dataset as CSV.

### Who is it for?

**CRM migration teams** can normalize address-book exports before importing contacts into a new CRM.

**Data operations teams** can combine regularly delivered VCF files with ETL, deduplication, and validation pipelines.

**Developers** can replace one-off local conversion scripts with a repeatable API endpoint.

**Sales and support operations** can inspect repeated phone numbers and email addresses that basic converters often flatten to a single value.

**Privacy and compliance teams** can run a bounded conversion job without sending contact files to an unrelated browser-based converter.

The Actor processes only the data supplied by the user. It does not discover, enrich, validate, or contact people.

### Why use an Apify Actor for VCF to CSV?

A desktop converter is useful for a one-time file. An Actor is more useful when the conversion belongs in an automated workflow.

You can:

1. call the same conversion contract from an API;
2. schedule recurring runs;
3. download results in several dataset formats;
4. connect results to webhooks, Google Sheets, Make, Zapier, or your own code;
5. retain run logs and source labels for troubleshooting;
6. cap output with `maxContacts` before processing a large export.

No browser, proxy, account, or third-party conversion service is required.

### Supported VCF input

The parser supports the contact fields most commonly found in vCard 2.1, 3.0, and 4.0 exports.

| Input feature | Behavior |
| --- | --- |
| Multiple cards | Produces one dataset row per complete card |
| Folded lines | Joins continuation lines beginning with a space or tab |
| Quoted-printable | Decodes common `ENCODING=QUOTED-PRINTABLE` values |
| Escaping | Decodes escaped comma, semicolon, colon, slash, and newline values |
| Repeated fields | Keeps all values in arrays |
| Grouped fields | Accepts names such as `item1.EMAIL` |
| Type parameters | Preserves labels in lower case |
| Preferred values | Maps `PREF=1`, `TYPE=PREF`, and equivalent forms |
| Extension fields | Groups unknown and `X-` properties in `customProperties` |
| Public URLs | Fetches HTTP(S) text with safe redirects and network checks |

Binary photos, logos, certificates, and attachments are not downloaded into the dataset. Their textual property values may remain outside the normalized contact fields.

### Input parameters

#### `vcfText`

Paste one or more complete vCards as a string.

The inline source is labeled `inline-vcf` in output.

The maximum inline source size is 10 MB.

#### `vcfUrls`

Provide up to 20 public HTTP(S) URLs.

Each response may be up to 10 MB. URLs that resolve to private, loopback, link-local, or reserved network addresses are rejected. Redirect destinations receive the same validation.

#### `maxContacts`

Set the maximum number of contact rows across every source.

The default is `10000`; the accepted range is 1 to 100000.

The combined downloaded and pasted input limit is 20 MB per run.

At least one of `vcfText` or `vcfUrls` is required.

### Getting started

1. Open the Actor input page.
2. Paste VCF text or add one or more public VCF URLs.
3. Keep `maxContacts` small for an initial check.
4. Click **Start**.
5. Open the **Contact rows** dataset after the run succeeds.
6. Choose **Export** and select CSV, JSON, Excel, XML, or another available format.

A minimal input looks like this:

```json
{
  "vcfText": "BEGIN:VCARD\nVERSION:4.0\nFN:Simon Perreault\nN:Perreault;Simon;;;\nEMAIL;TYPE=work:simon.perreault@viagenie.ca\nEND:VCARD",
  "maxContacts": 10
}
```

To convert a public file:

```json
{
  "vcfUrls": [
    "https://raw.githubusercontent.com/mangstadt/ez-vcard/master/src/test/resources/ezvcard/io/text/rfc6350-example.vcf"
  ],
  "maxContacts": 100
}
```

### Output fields

| Field | Type | Meaning |
| --- | --- | --- |
| `source` | string | `inline-vcf` or the final fetched URL |
| `cardIndex` | number | One-based card position within that source |
| `version` | string or null | Declared vCard version |
| `fullName` | string or null | Formatted `FN` value |
| `name` | object or null | Prefix, given, additional, family, and suffix arrays |
| `nicknames` | array | All nicknames |
| `phones` | array | Phone value, types, and preferred flag |
| `emails` | array | Email value, types, and preferred flag |
| `addresses` | array | Structured and formatted postal addresses |
| `organizations` | array | Organization and unit paths |
| `titles` | array | Job titles |
| `roles` | array | Organizational roles |
| `urls` | array | Contact URLs with type metadata |
| `birthdays` | array | Birthday values from the card |
| `notes` | array | Decoded notes |
| `categories` | array | Category labels |
| `uid` | string or null | Contact UID |
| `customProperties` | object | Repeated unknown and extension values by property name |
| `convertedAt` | string | ISO timestamp for conversion |

### Example output

The public RFC 6350 conformance fixture produces a row shaped like this:

```json
{
  "source": "https://raw.githubusercontent.com/mangstadt/ez-vcard/master/src/test/resources/ezvcard/io/text/rfc6350-example.vcf",
  "cardIndex": 1,
  "version": "4.0",
  "fullName": "Simon Perreault",
  "name": {
    "prefixes": [],
    "givenNames": ["Simon"],
    "additionalNames": [],
    "familyNames": ["Perreault"],
    "suffixes": ["ing. jr", "M.Sc."]
  },
  "phones": [
    {
      "value": "tel:+1-418-656-9254;ext=102",
      "types": ["work", "voice"],
      "preferred": true
    }
  ],
  "emails": [
    {
      "value": "simon.perreault@viagenie.ca",
      "types": ["work"],
      "preferred": false
    }
  ],
  "organizations": ["Viagenie"],
  "convertedAt": "2026-01-15T12:00:00.000Z"
}
```

Fields not shown in this shortened example still appear with empty arrays, null values, or normalized content.

### How repeated values appear in CSV

The default dataset keeps repeated values as JSON arrays so no second email or phone is discarded.

When exported as CSV, a `phones` cell contains serialized data similar to:

```json
[{"value":"+1-202-555-0101","types":["work","voice"],"preferred":true},{"value":"+1-202-555-0102","types":["cell"],"preferred":false}]
```

If your destination requires separate `phone_1` and `phone_2` columns, flatten those arrays in a downstream spreadsheet, database transform, or code step. Keeping arrays in the source dataset avoids irreversible data loss.

### How much does it cost to convert VCF contacts?

The Actor uses pay-per-event pricing.

- A run emits one `start` event at **$0.005**.
- Each contact row emits one `item` event.
- The BRONZE item price is **$0.00402 per contact**, with lower unit prices on higher platform tiers.

At the BRONZE item rate, the event-price examples are:

| Contacts | Calculation at the BRONZE rate | Total event price |
| ---: | ---: | ---: |
| 1 | 0.005 + (1 × 0.00402) USD | 0.00902 USD |
| 100 | 0.005 + (100 × 0.00402) USD | 0.407 USD |
| 1,000 | 0.005 + (1,000 × 0.00402) USD | 4.025 USD |

Apify displays the exact active tier and price before a run. Platform compute charges and plan details are governed by your Apify account. No proxy traffic is used by this Actor.

### Scheduling and data pipelines

Use an Apify Task when the same public VCF URL is updated periodically.

A recurring workflow can:

1. run on a daily or weekly schedule;
2. convert the current file into stable rows;
3. send a webhook when the run finishes;
4. compare rows by `uid`, email, or a downstream key;
5. load new records into a CRM or warehouse.

This Actor does not itself compare runs, deduplicate people, or monitor changes. Those are downstream operations built on its normalized output.

### API usage with cURL

Start a synchronous run and return dataset items:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~vcf-to-csv-converter/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "vcfUrls": ["https://raw.githubusercontent.com/mangstadt/ez-vcard/master/src/test/resources/ezvcard/io/text/rfc6350-example.vcf"],
    "maxContacts": 100
  }'
```

For sensitive contact data, keep your API token in a secret manager and send input only over HTTPS.

### JavaScript API example

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/vcf-to-csv-converter').call({
  vcfText: process.env.VCARD_TEXT,
  maxContacts: 5000,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(`Converted ${items.length} contacts`);
```

Install the client with `npm install apify-client`.

### Python API example

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("automation-lab/vcf-to-csv-converter").call(
    run_input={
        "vcfUrls": [os.environ["PUBLIC_VCF_URL"]],
        "maxContacts": 5000,
    }
)

for contact in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(contact.get("fullName"), contact.get("emails"))
```

Install the client with `pip install apify-client`.

### Use with Apify MCP

Add this Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/vcf-to-csv-converter"
```

#### Claude Desktop, Cursor, and VS Code setup

Claude Desktop, Cursor, and VS Code can use this equivalent MCP configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/vcf-to-csv-converter"
    }
  }
}
```

Example prompts:

- "Convert this public VCF URL and summarize the contact count by organization."
- "Run VCF to CSV Converter on the pasted vCards and list contacts with more than one email."
- "Convert the address-book export, then show rows missing both phone and email values."

Do not place private contact data directly in a chat prompt unless that environment is approved for it.

### Limits and failure behavior

- At least one source is required.
- A source without complete `BEGIN:VCARD` and `END:VCARD` markers fails clearly.
- A nested or unterminated card fails rather than returning silently truncated output.
- URL requests time out after 30 seconds.
- A URL follows at most five redirects.
- Private-network URLs and embedded URL credentials are rejected.
- The maximum size is 10 MB per source and 20 MB combined.
- The parser does not evaluate JavaScript or render web pages.
- Binary media embedded in cards is not decoded into files.
- Character sets other than UTF-8 may require conversion before input.
- Highly vendor-specific fields remain under `customProperties` rather than receiving a guessed meaning.

If processing reaches `maxContacts`, remaining cards and sources are intentionally skipped.

### Troubleshooting

#### The run says no complete cards were found

Check that the input includes both `BEGIN:VCARD` and `END:VCARD`. A CSV file renamed to `.vcf` is not a vCard file.

#### A public URL is rejected

Confirm it uses HTTP or HTTPS, is reachable without a login, and does not resolve to localhost or a private network. Signed URLs are accepted only when their credentials are in the query string rather than the URL username/password fields; consider whether putting a signed URL in Actor input is appropriate for your security policy.

#### Accented characters look wrong

The parser expects UTF-8. Convert legacy Windows or ISO-8859 exports to UTF-8 first. Common quoted-printable UTF-8 values are decoded.

#### CSV contains JSON in some cells

That is expected for repeated fields. Use the JSON dataset or flatten those arrays downstream if your destination requires fixed numbered columns.

#### The source has contacts but output stops early

Increase `maxContacts`, up to 100000, and rerun.

### Legality and responsible use

VCF files often contain personal data.

Only process contact data that you are authorized to handle. Follow applicable privacy, employment, communications, retention, and security requirements.

Use private datasets and appropriate Apify access controls for confidential address books. Avoid public dataset sharing, public Task input, or log statements containing private contact data.

Public URL mode downloads exactly the URLs supplied by the user. The Actor does not bypass authentication, anti-bot controls, or access restrictions.

This documentation is operational guidance, not legal advice.

### Related Automation Lab Actors

- [JSON to CSV Converter](https://apify.com/automation-lab/json-to-csv-converter) converts JSON files and API responses into configurable flattened rows.
- [iCal Parser](https://apify.com/automation-lab/ical-parser) parses calendar data when your source is ICS/iCalendar rather than VCF/vCard.

Use VCF to CSV Converter for contacts. Use iCal Parser for calendar events, and JSON to CSV Converter when the source is JSON rather than vCard text.

### FAQ

#### Does this create a physical CSV file?

The Actor writes normalized rows to the default Apify dataset. Open **Export** and choose CSV to download a file, or request CSV through the dataset API.

#### Can I upload a local `.vcf` file?

Paste its UTF-8 text into `vcfText`. For unattended workflows, place the file at an authorized public HTTPS URL and use `vcfUrls`.

#### Are repeated phone numbers and emails preserved?

Yes. Repeated values remain ordered arrays with their type and preference metadata.

#### Does it validate phone numbers or email deliverability?

No. It converts the source faithfully; it does not call, message, normalize country codes, or verify deliverability.

#### Does it merge duplicate contacts?

No. Every complete card becomes one row. Deduplicate downstream using a UID, normalized email, phone number, or your own business rule.

#### Can it process vCard 2.1 files?

It supports common 2.1 syntax, including bare type parameters and quoted-printable text, but unusual vendor encodings may remain partially normalized. Test a representative export before a large migration.

#### Can I combine pasted text and URLs?

Yes. Inline cards are processed first, followed by URLs in their supplied order, until `maxContacts` is reached.

#### Is a proxy required?

No. Public URL fetches use direct HTTP(S). Protected URLs that require a login, browser session, or private network are outside the supported scope.

# Actor input Schema

## `vcfText` (type: `string`):

Paste one or more complete vCards. Supports common vCard 2.1, 3.0, and 4.0 fields, folded lines, escaping, repeated properties, and quoted-printable text. Maximum 10 MB.

## `vcfUrls` (type: `array`):

Public HTTP(S) URLs of .vcf or text files. Redirects are checked safely; private-network and credential-bearing URLs are rejected. Up to 20 URLs and 10 MB per source.

## `maxContacts` (type: `integer`):

Stop after this many normalized contact rows across all supplied sources.

## Actor input object example

```json
{
  "vcfText": "BEGIN:VCARD\nVERSION:4.0\nFN:Simon Perreault\nN:Perreault;Simon;;;\nORG;TYPE=work:Viagenie\nTEL;TYPE=work,voice;PREF=1:+1-418-656-9254\nEMAIL;TYPE=work:simon.perreault@viagenie.ca\nADR;TYPE=work:;;2875 Laurier;Quebec;QC;G1V 2M2;Canada\nURL;TYPE=home:http://nomis80.org\nEND:VCARD",
  "vcfUrls": [],
  "maxContacts": 10000
}
```

# Actor output Schema

## `dataset` (type: `string`):

Normalized contacts in the default dataset overview.

# 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 = {
    "vcfText": `BEGIN:VCARD
VERSION:4.0
FN:Simon Perreault
N:Perreault;Simon;;;
ORG;TYPE=work:Viagenie
TEL;TYPE=work,voice;PREF=1:+1-418-656-9254
EMAIL;TYPE=work:simon.perreault@viagenie.ca
ADR;TYPE=work:;;2875 Laurier;Quebec;QC;G1V 2M2;Canada
URL;TYPE=home:http://nomis80.org
END:VCARD`
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/vcf-to-csv-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 = { "vcfText": """BEGIN:VCARD
VERSION:4.0
FN:Simon Perreault
N:Perreault;Simon;;;
ORG;TYPE=work:Viagenie
TEL;TYPE=work,voice;PREF=1:+1-418-656-9254
EMAIL;TYPE=work:simon.perreault@viagenie.ca
ADR;TYPE=work:;;2875 Laurier;Quebec;QC;G1V 2M2;Canada
URL;TYPE=home:http://nomis80.org
END:VCARD""" }

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/vcf-to-csv-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 '{
  "vcfText": "BEGIN:VCARD\\nVERSION:4.0\\nFN:Simon Perreault\\nN:Perreault;Simon;;;\\nORG;TYPE=work:Viagenie\\nTEL;TYPE=work,voice;PREF=1:+1-418-656-9254\\nEMAIL;TYPE=work:simon.perreault@viagenie.ca\\nADR;TYPE=work:;;2875 Laurier;Quebec;QC;G1V 2M2;Canada\\nURL;TYPE=home:http://nomis80.org\\nEND:VCARD"
}' |
apify call automation-lab/vcf-to-csv-converter --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/vcf-to-csv-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/xBE3nx1vJPDjmUwXe/builds/kvLCMxa4z4acs2KT2/openapi.json
