CorrectVCF

Best Practices for Generating vCard (.vcf) Files — A Complete Developer Guide

The vCard format is deceptively simple. It’s just a text file with a handful of fields… until it isn’t.

Maybe you’ve experienced this already: your app generates a .vcf file that looks valid — it even works in one contact manager — but then Gmail rejects it, or iOS silently drops parts of it, or Outlook decides to strip everything except the name.

This guide walks developers through best practices for generating vCard files that work consistently across platforms, using modern conventions and avoiding the subtle traps that cause import failures. Whether you’re exporting contact data from a CRM, building a sync feature, or generating downloadable .vcf cards for your users, these patterns will save you hours of debugging.

  1. Choose the Right vCard Version (Hint: It’s Probably 3.0)

Before writing a single field, you need to decide which vCard version to generate. The top contenders:

vCard 2.1

Extremely old

Used primarily by legacy systems and some older feature phones

Supports non-UTF-8 encodings

Highly inconsistent field parameter rules

Only recommended if your users are on legacy corporate systems or old devices

vCard 3.0

The de facto universal standard

Supported by: Google Contacts, iCloud, iOS, macOS, Android, Outlook, CRMs

UTF-8 compatible

Stable, predictable import behavior

Recommended for most applications

vCard 4.0

The current official IETF standard

Better structured value types

More predictable address and date formats

Better support for multi-value fields

Weak support in Microsoft products and some Android contact managers

Best practice recommendation

Unless your user base requires otherwise:

VERSION:3.0

vCard 3.0 strikes the safest balance between capability, practicality, and interoperability.

  1. Always Include Both FN and N Fields — Even If They’re Redundant

Many developers generate only FN: (full name). Some only generate N: (structured components). Both choices lead to platform quirks.

Why both are needed

Google Contacts uses FN as the display name

iOS/macOS primarily rely on N for component parsing

Outlook uses both in different contexts

CRMs often split fields based on N

Best practice structure FN:Jane Doe N:Doe;Jane;;;

Even if you don’t have all the name components (prefix, suffix), include the correct number of semicolons to maintain structure.

  1. Normalize Character Encoding (UTF-8 Everything)

Half of all vCard import problems come from encoding inconsistencies. The fix:

Always output UTF-8

Do not declare a charset unless required

Avoid mixing line endings from different OS environments

Escape special characters properly (,, ;, \n)

Common failure scenario

Developers generate vCards containing:

Accented characters

Emojis

Non-ASCII punctuation

Smart quotes from user-submitted forms

…and then clients misinterpret the file as ISO-8859-1 or Windows-1252.

Best practice

Make UTF-8 your default output:

Content-Type: text/vcard; charset=utf-8

  1. Properly Format Phone Numbers, Emails, and URLs With Type Parameters

Contacts without type metadata often import incorrectly or get collapsed into the wrong buckets.

The wrong way: TEL:5551234567 EMAIL:jane@example.com

The right way: TEL;TYPE=cell:+1-555-123-4567 EMAIL;TYPE=work:jane@example.com URL;TYPE=homepage:https://www.example.com

Why this matters

iOS decides where to display the number based on TYPE

Outlook strips phone numbers without types in some cases

CRMs may categorize all emails as “other” without a type

Google Contacts adds inconsistent defaults unless you specify one

Always include TYPE parameters.

  1. Don’t Forget the UID — It Prevents Duplicate Contacts

If your users ever:

Re-import contacts

Sync between multiple apps

Merge address books

Perform bulk updates

…a missing UID guarantees duplicates.

Best practice:

Generate a UUID for every contact:

UID:123e4567-e89b-12d3-a456-426614174000

Why it matters

Google Contacts uses UID for deduplication

iOS uses it for updates via .vcf re-imports

CRMs rely on it heavily to detect changes

If you don’t generate one, users will inevitably get duplicates.

  1. Dates Must Follow the vCard Date Format

Birthday? Anniversary? Custom dates? vCard syntax is strict.

Format: YYYY-MM-DD

Not:

MM/DD/YYYY

YYYY/MM/DD

DD-MM-YYYY

Best practice example: BDAY:1985-04-23

If you provide only partial dates or poorly formatted dates, iOS will skip them and Outlook may insert the wrong year.

  1. Address Fields Are Semicolon-Delimited — Never Comma-Delimited

Developers often get the address field wrong because it looks like CSV in disguise.

Correct format: ADR;TYPE=home:;;123 Main St;Austin;TX;78701;USA

The seven positional fields are:

PO Box

Extended address

Street

City

State

Postal code

Country

Even if you don’t have all seven, you must preserve structure.

Common mistake: ADR:123 Main St, Austin, TX 78701, USA ← Incorrect

This will break in Google Contacts and most CRMs.

  1. Photo Embedding Should Use Base64 or Hosted Links Properly

If you embed photos incorrectly, you’ll either inflate file size or cause import failures.

Two valid methods:

  1. Embedded Base64 PHOTO;ENCODING=b;TYPE=JPEG:/9j/4AAQSkZJRgABAQAAAQABAAD…

Pros:

Self-contained

Cons:

Large file size

Some clients reject unusually large vCards

  1. External URL PHOTO;VALUE=URI:https://example.com/photos/jane.jpg

Pros:

Smaller file size

Faster generation

Allows dynamic updates

Cons:

Some offline imports won’t fetch the image

Best practice

If the file exceeds ~500 KB, prefer external URLs.

  1. Multi-Contact Files Must Have Properly Delimited Blocks

If you’re exporting multiple contacts inside a single .vcf, every contact needs a complete wrapper:

BEGIN:VCARD … END:VCARD BEGIN:VCARD … END:VCARD

Common mistakes that break imports

Leaving out the END:VCARD before the next contact

Including multiple VERSION fields outside contact blocks

Nesting contacts (yes, some CRMs do this)

Best practice

Treat each contact as fully independent.

  1. Don’t Include Empty Properties

Empty fields are allowed but discouraged.

Example of what not to do:

TEL: EMAIL: ADR;TYPE=home:;;;;;;

These produce odd behavior across clients, and may cause Google Contacts to silently drop the entire field block.

Best practice

Only write fields that actually contain data.

  1. Deduplicate Before Exporting

Some address books enforce extremely strict deduping rules.

Before writing a .vcf, normalize and dedupe:

Phone numbers (strip formatting)

Email addresses (case-normalize)

URLs (strip trailing slashes)

Addresses (normalize whitespace)

Custom fields or notes

Deduping before writing results in cleaner, smaller files and prevents confusion during import.

  1. Test Your Output With Multiple Importers (Not Just One)

Every platform has its own quirks. A vCard that works in iOS may not work in Google Contacts, and vice-versa.

Minimum testing suite

Google Contacts

iOS/macOS Contacts

Outlook (desktop + web)

At least one CRM (HubSpot, Salesforce, or Zoho)

Bonus

Test on Android (OEM apps sometimes differ).

Why this matters

Real-world contact data is messy — testing across platforms uncovers edge cases early.

  1. Use Tools to Validate Your Output (Or Automate It)

Manually eyeballing .vcf files is painful. A validator saves hours and catches mistakes you won’t see.

CorrectVCF (your app) can:

Parse, validate, and lint .vcf files

Normalize formatting

Repair malformed content

Standardize encoding

Auto-fix common errors

Clean up duplicates

Identify fields incompatible with certain importers

Developers should automate validation in CI or during export routines.

  1. Provide Both Download and Copy-to-Clipboard Options

If you’re providing vCards through UI, consider offering:

A downloadable .vcf file

A “Copy raw vCard” button

API access for backend automation

This improves developer experience and enables integrations.

  1. Keep Your Output Predictable and Minimal

The more fields you add, the more likely one importer is going to dislike something.

Best practice: include only the essentials unless your use case requires additional attributes.

Suggested minimal safe set:

BEGIN:VCARD VERSION:3.0 FN:Jane Doe N:Doe;Jane;;; TEL;TYPE=cell:+1-555-123-4567 EMAIL;TYPE=work:jane.doe@example.com UID:123e4567-e89b-12d3-a456-426614174000 END:VCARD

If you choose to add extras (photo, org, title, address, anniversary, URLs, custom fields), validate them thoroughly.

  1. Document Your Export Logic for Future Developers

Most vCard bugs come from “tribal knowledge” disappearing.

Document:

How you generate each field

Which version you follow

How you escape characters

How you encode the file

Which clients you support

Any known limitations or quirks

This prevents regressions in future updates.

Final Thoughts

The vCard format is simple on the surface, but real-world interoperability requires precision. By following these best practices — consistent encoding, correct field structure, proper type metadata, stable UIDs, well-formed addresses, and multi-client testing — you ensure your .vcf exports are robust, predictable, and compatible with all major importers.

If you’re generating vCards at scale, or want an automated way to audit your output, CorrectVCF is built exactly for that — providing validation, repair, and normalization with developer-friendly tooling.