VCF to JSON Converter — vCard Contact Parser avatar

VCF to JSON Converter — vCard Contact Parser

Pricing

$20.00 / 1,000 parsed files

Go to Apify Store
VCF to JSON Converter — vCard Contact Parser

VCF to JSON Converter — vCard Contact Parser

Convert vCard 3.0/4.0 contact text to JSON for n8n, Make and agents. Keep multiple phones, emails and Apple labels. $0.02 per bundle, up to 500 contacts. Includes API and Python workflow examples.

Pricing

$20.00 / 1,000 parsed files

Rating

0.0

(0)

Developer

Stefan Schellen

Stefan Schellen

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

16 hours ago

Last modified

Categories

Share

Turn vCard 3.0/4.0 contact text into structured JSON for n8n, Make and AI agents. Keep multiple phone numbers, multiple emails and Apple labels, instead of flattening a contact to its first value.

$0.02 per successful bundle — up to 500 contacts and 1 MiB. No additional platform-usage charge. Rejected bundles produce no product event.

Try it in one minute

  1. Click Try for free and run the synthetic example using available Apify credit; otherwise the displayed price applies.
  2. Open the dataset: one result contains a contacts array.
  3. Use the API example below to connect your workflow. Review warnings before importing contacts anywhere.

When to use it

  • Prepare supported contact fields from a VCF export for your own import mapping.
  • Keep repeated emails/phones and labels when passing contacts between workflow steps.
  • Give an agent a deterministic parser with explicit limits and warnings.

Why pay instead of using a free library? Libraries such as vobject are a valid free option if you can host and maintain Python code. This Actor supplies a hosted API, bounded processing and a stable output envelope. It does not add contact enrichment or recover missing data.

Not suitable for: vCard 2.1, photos, lossless archival conversion or a ready-made CRM connector.

Input and output

Send a JSON object with exactly one field, vcard_text. Example:

{
"vcard_text": "BEGIN:VCARD\r\nVERSION:3.0\r\nFN:Zoë Example\r\nN:Example;Zoë;;;\r\nitem1.TEL;TYPE=CELL:+31001\r\nitem1.X-ABLabel:iPhone\r\nTEL;TYPE=WORK:+31002\r\nEMAIL;TYPE=HOME:personal@example.test\r\nEMAIL;TYPE=WORK:work@example.test\r\nEND:VCARD\r\n"
}

This example produces one contact with two phones, two emails and an iPhone label. A complete response is shown below.

The result contains schema_version, contact_count, and contacts. Each contact has these field collections:

CollectionValue
namesStructured family/given/additional/prefix/suffix
formatted_namesFull display name, without guessed splitting
organizationsOrdered organization components
titlesJob title text
phonesOriginal phone text or tel: URI
emailsOriginal email text
addressesStructured postal-address components

Each collection has present and items. Each item includes value, types, group, labels, and parameters. Repeated values are preserved, not deduplicated. Names and addresses may have repeated components represented as arrays. completeness reports missing, empty, or present; it is not a check of deliverability or identity.

One dataset item contains the entire result envelope. The same object is stored in key-value record OUTPUT. Split its contacts array in your workflow when you need one item per contact. This envelope makes one run easy to retrieve and avoids duplicated output on a run restart.

Scope and limits

  • Maximum 1 MiB UTF-8 input, 500 contacts, 256 properties/contact, 8 KiB unfolded line, 4 MiB compact JSON output.
  • Supports the documented contact fields in 3.0/4.0, folding, Unicode, escapes and Apple group labels. Not a full RFC conformance validator.
  • Version 2.1 and legacy CHARSET/ENCODING on supported fields are rejected. Convert those files elsewhere first.
  • Photos are omitted with PHOTO_OMITTED. Other fields such as NOTE, URL and birthday are omitted; their names appear in unmapped_properties with UNMAPPED_PROPERTIES.
  • No photo/URL fetching, OCR, contact enrichment, CRM updates or inferred first/last names. This is not a lossless conversion of every vCard property.
  • A malformed or over-limit bundle fails as a whole. Partial contacts are not returned or billed.

The parser worker has a 5-second wall timeout. On Linux it also has a 4-second CPU limit and 160 MiB address-space limit. The deployed Actor allocation is 256 MiB and 20 seconds total. Normal Linux cloud runs and build-time adversarial checks of memory, CPU and parent wall timeout passed.

Errors

Failed runs have a fixed status code and, for rejected input, an ERROR record. Common codes: UNSUPPORTED_VERSION, INPUT_LIMIT, LINE_LIMIT, CONTACT_LIMIT, PROPERTY_LIMIT, OUTPUT_LIMIT, UNTERMINATED_CARD, MALFORMED_PROPERTY, PARSE_ERROR, LEGACY_ENCODING_UNSUPPORTED, PROCESSING_TIMEOUT. Values from the submitted contact are not included in those errors.

Workflow integration

Use Apify's synchronous dataset endpoint:

POST https://api.apify.com/v2/acts/creatieve_naald~vcard-to-json/run-sync-get-dataset-items?memory=256&timeout=20&maxTotalChargeUsd=0.02

Authenticate using an Authorization: Bearer … header stored in your workflow's credentials. Do not put tokens in query strings, shared workflow exports or contact data. The JSON body is the input object. The HTTP result is an array containing one result envelope; iterate over its contacts array.

For n8n, use an HTTP Request node with POST, a stored Header Auth credential and JSON body {{ {vcard_text: $json.vcard_text} }}. Set a 30-second request timeout. Disable automatic retries that start a fresh run. Then use Split Out on contacts. The equivalent authenticated HTTP roundtrip has been tested. These n8n settings are a configuration recipe; a full n8n workflow import has not been verified.

For Make, use HTTP → Make a request, POST, the same URL and a stored Bearer credential. Build the body with JSON → Create JSON so line breaks and quotes are escaped correctly; map the text into vcard_text. Parse the response, then iterate the first envelope's contacts. This is a configuration recipe, not a tested Make blueprint.

For an agent, call the same HTTP endpoint with structured JSON input. Do not ask an LLM to reconstruct missing names. Inspect warnings before using the result.

A new API call is a new job and can be billed again. On a network timeout, inspect/retrieve the existing run before starting another. Automatic resumption of the same run uses its stored result and billing state.

Price and data handling

Price: $0.02 per successfully processed file/bundle, independent of contact count within the limits. One parsed-file event; no automatic start/dataset charges or additional platform-usage charge. A rejected bundle produces no product event. The minimum permitted maximum charge per run is $0.02.

Apify receives input and stores the run's input/output and dataset according to account/platform settings. This is not a zero-retention service. The parser subprocess receives no account credentials and does not fetch external resources. Application status messages contain counts/codes only. Console retention is 7 days for unnamed storage/other runs, with the latest 10 runs retained for 4 months. An unauthenticated dataset request returned 403; unauthenticated INPUT, OUTPUT and JOB_STATE requests also returned 403. Anyone holding a valid signed sharing link may still access its target; do not share those links.

Copyable Python workflow: VCF to contact rows

The example below calls Apify once and keeps every phone/email in arrays. Read a UTF-8 file locally; the Actor takes text, not a file URL. Set APIFY_TOKEN through your secret manager. Python 3 standard library only. The mapping and HTTP request construction were tested locally against saved acceptance output; this is not a verified n8n/Make import.

"""Two copyable workflow adapters. No network calls on import."""
import json, os, urllib.request
from pathlib import Path
def call_actor(slug, field, text, price):
url = f'https://api.apify.com/v2/acts/creatieve_naald~{slug}/run-sync-get-dataset-items?memory=256&timeout=20&maxTotalChargeUsd={price}'
request = urllib.request.Request(url, data=json.dumps({field: text}).encode(), headers={'Authorization': 'Bearer '+os.environ['APIFY_TOKEN'], 'Content-Type': 'application/json'}, method='POST')
# A timeout can mean the job ran. Never automatically start a replacement job.
with urllib.request.urlopen(request, timeout=35) as response:
rows = json.load(response)
if not isinstance(rows,list) or len(rows)!=1 or rows[0].get('schema_version')!='1.0':
raise ValueError('Unexpected response; inspect existing run before retrying')
return rows[0]
def contact_rows(envelope):
"""One row/contact, keeping every phone and email in arrays."""
return [{'name': [x['value'] for x in c['fields']['formatted_names']['items']],
'phones': [x['value'] for x in c['fields']['phones']['items']],
'emails': [x['value'] for x in c['fields']['emails']['items']],
'warnings': c['warnings'], 'original': c} for c in envelope['contacts']]
result = call_actor('vcard-to-json', 'vcard_text',
Path('contacts.vcf').read_text(encoding='utf-8'), '0.02')
rows = contact_rows(result)
# Send rows to your chosen destination after checking warnings.

Guide: preserve repeated contact values in your destination

Use the Python workflow above to produce one row per contact. Each row keeps phones and emails as arrays, plus warnings and the complete original contact. Review warnings before importing.

  1. Map arrays into a destination that supports multiple values, or keep a linked child table.
  2. Do not repeatedly overwrite one CRM phone field: the last assignment will erase earlier values even if parsing preserved them.
  3. Retain original when you need Apple labels or other source fields later.
  4. Test with synthetic contacts containing two phones, two emails and a label before using personal data.

Our offline fixture verifies those repeated values and the Apple label. Your CRM integration is not tested by this example. A timed-out API call may already have completed: inspect its existing run before retrying.

More bounded workflow tools: Agent Tools portfolio.

Frequently asked questions

Is the price per contact? No: one successful bundle of 1–500 contacts costs $0.02 within the documented limits. 100 successful bundles cost $2, before any applicable taxes or account-specific discounts.

Does it clean or verify addresses and emails? No. It parses supported fields and reports omissions; it does not verify deliverability or guess missing values.

Can it take a file URL? No. Read your UTF-8 VCF file in your workflow and submit its text as vcard_text.

Complete example response

The synchronous HTTP endpoint returns an array containing this envelope:

[
{
"schema_version": "1.0",
"contact_count": 1,
"contacts": [
{
"index": 1,
"version": "3.0",
"fields": {
"names": {
"present": true,
"items": [
{
"value": {
"family": "Example",
"given": "Zoë",
"additional": "",
"prefix": "",
"suffix": ""
},
"types": [],
"group": null,
"labels": [],
"parameters": {}
}
]
},
"formatted_names": {
"present": true,
"items": [
{
"value": "Zoë Example",
"types": [],
"group": null,
"labels": [],
"parameters": {}
}
]
},
"organizations": {
"present": false,
"items": []
},
"titles": {
"present": false,
"items": []
},
"phones": {
"present": true,
"items": [
{
"value": "+31001",
"types": [
"CELL"
],
"group": "item1",
"labels": [
"iPhone"
],
"parameters": {
"TYPE": [
"CELL"
]
}
},
{
"value": "+31002",
"types": [
"WORK"
],
"group": null,
"labels": [],
"parameters": {
"TYPE": [
"WORK"
]
}
}
]
},
"emails": {
"present": true,
"items": [
{
"value": "personal@example.test",
"types": [
"HOME"
],
"group": null,
"labels": [],
"parameters": {
"TYPE": [
"HOME"
]
}
},
{
"value": "work@example.test",
"types": [
"WORK"
],
"group": null,
"labels": [],
"parameters": {
"TYPE": [
"WORK"
]
}
}
]
},
"addresses": {
"present": false,
"items": []
}
},
"unmapped_properties": [],
"warnings": [],
"completeness": {
"names": "present",
"formatted_names": "present",
"organizations": "missing",
"titles": "missing",
"phones": "present",
"emails": "present",
"addresses": "missing"
}
}
]
}
]

Support

Report reproducible problems within the documented scope through this Actor's Apify Issues tab. Include only synthetic examples and remove contact details, API tokens and signed links. Custom CRM integrations, enrichment and vCard 2.1 conversion are outside the scope.