QR code to add contact to phone — the full guide
A QR code to add contact to phone uses the vCard format every modern device parses natively. The complete guide — fields, iPhone vs Android, print test.
A QR code to add contact to phone is the simplest way to hand someone your full contact card without typing, sharing a fragile link, or trusting that they will remember to "add you on LinkedIn later." They point a camera at the square, the phone recognises a contact card, the phone offers a single button that drops your name, number, email, and everything else straight into the address book. No app required on either side. No follow-up message. No typos.
The technology under it is older than every smartphone you have ever owned. It is the vCard format, defined by the IETF in the mid-90s, and every modern phone parses it natively because the contacts app on every modern phone exports its own data in that exact format. A QR code that encodes a vCard is just a printable, scannable wrapper around a file the phone already knew how to read.
This post is the complete guide. It covers what actually happens when someone scans your code, the vCard text the QR encodes (with the real syntax), every field worth including and the ones to avoid, the size problem that bites you when you try to embed a photo, the differences between how iPhone and Android handle the Save-Contact prompt, the print-test routine that catches design problems before you spend money on cards, and the common mistakes that turn a perfectly good code into a dead square of pixels. By the end you will have the model, the format, the tools, and the checklist to ship one that works.
What a QR code to add contact to phone actually does
When the phone camera lands on a QR code, the decoder runs almost immediately — a few hundred milliseconds on any device made in the last seven or eight years. The camera samples the modules, recovers the encoded text, and hands it to the operating system with a label saying "this looked like a QR code." The OS then inspects the text and routes it to the right handler. A https:// URL goes to the browser. A WIFI: block goes to the network settings. A BEGIN:VCARD block goes to the contacts app, which parses the vCard and shows a native sheet asking whether you want to save it.
That last step is the whole point. The user does not visit a webpage, does not download a file, does not install anything. They tap a single confirm button and the contact is in their phone, exactly as you formatted it, with all the fields you specified.
The behaviour is the same on every actively used phone in 2026. iOS picked up native QR scanning in iOS 11 (2017). Android picked it up across the major OEMs by Android 9 (2018). Older devices still work via third-party scanner apps, which all parse vCard. The market floor is high — almost no audience you target has a phone that fails this basic flow. The complete background on what a QR code is and how the camera reads one lives in what is a QR code if you want the full anatomy.
The vCard format you will encode
A vCard is a plain text file. Every line is a field. Every field is KEY:value with optional KEY;PARAM=...:value for typed fields like phone numbers. The whole thing sits between two markers — BEGIN:VCARD at the top, END:VCARD at the bottom — and a version line right after the start so parsers know which spec to apply.
A real, working vCard looks exactly like this:
BEGIN:VCARD
VERSION:3.0
N:Doe;Jane;;;
FN:Jane Doe
ORG:Linked.Codes
TITLE:Founder
TEL;TYPE=CELL:+62-812-3456-7890
TEL;TYPE=WORK:+62-21-555-1234
EMAIL:jane@linked.codes
URL:https://linked.codes
ADR:;;Jl. Sunset 12;Denpasar;Bali;80361;ID
NOTE:Best contact: WhatsApp during business hours
END:VCARD
That is the entire format. No XML, no JSON, no schema imports. Each line is line-terminated with CRLF (\r\n) per RFC 6350, though most modern parsers tolerate plain LF. Most generators handle the line endings for you; if you are rolling your own, do not skip them — strict parsers (a small handful of older Android contact apps, certain enterprise email gateways) do still enforce the spec.
A few things worth knowing about the structure before we walk the fields:
VERSION:3.0is the safe default. vCard 3.0 (RFC 2426) has been stable for two decades and every phone parses it. vCard 4.0 (RFC 6350) is newer, adds a few fields, but isn't supported as broadly on older Android. Use 3.0 unless you specifically need a 4.0-only field.N:andFN:are both required by Apple's parser.N:is the structured name (last;first;middle;prefix;suffix);FN:is the formatted display name. Android tolerates either alone; iOS expects both. Include both for safety.- Special characters need escaping. Commas, semicolons, colons, and backslashes inside a field value need a backslash in front.
TITLE:Founder, CEOshould beTITLE:Founder\, CEO. Most generators handle this; if you write the vCard yourself, do not skip it — unescaped commas insideADR:are the most common cause of garbled imports. - UTF-8 works for names. Modern parsers handle non-Latin characters in names, organisations, and notes. Older Android parsers (pre-Android 8) sometimes strip them. If your audience is global, plain Latin characters are the safest bet for compatibility.
The QR code encodes that whole text block — every line, every escape, every CRLF — into the modules. Decode the QR, you get the vCard back exactly as encoded. Hand it to the contacts app, you get a native save prompt with every field pre-filled.
Static vs dynamic — and why dynamic is the better default
There are two ways to put a vCard behind a QR code, and they look identical to the person scanning. The difference is what gets encoded.
A static vCard QR encodes the entire vCard text directly into the modules. Every character of the BEGIN:VCARD block lives in the printed pattern. Decode the modules, get the vCard, save the contact. No internet required, no server in the loop. The downside is final: change your phone number, your title, your employer, anything — and every printed code is wrong. The fix is a reprint.
A dynamic vCard QR encodes a short URL — something like lnks.work/k/jane-card. The phone follows the URL, the server returns the vCard text with a Content-Type: text/vcard header, the phone sees the response and pops the same Save Contact prompt. From the user's side the experience is indistinguishable. From your side the difference is the entire point: you can edit the hosted vCard whenever you want, and every printed code already in the wild quietly starts serving the updated contact.
For most use cases dynamic wins clearly. Five reasons in plain English:
- Edit forever. Phone, email, title, employer, photo — all editable through a dashboard, no reprint.
- Smaller QR. A dynamic QR encodes a 25-character URL; a static one encodes 200+ characters of vCard text. The dynamic version prints smaller and scans from further away.
- Track scans. A static vCard decodes on-device with no server hop, so you have no idea who scanned it. A dynamic one logs every scan — useful for measuring which conferences or campaigns produced contact saves.
- Recover from typos. Mistype your number on a static vCard and every card is wrong. Mistype it on a dynamic one and you fix it in the dashboard.
- Survive employer changes. When you switch jobs, a dynamic vCard managed by your old company stays under their control — useful for routing to a successor; useful for you if the vCard belongs to a personal account that travels with you.
The trade-off is real but narrow. Dynamic vCards need a network hop at scan time, so they fail in environments without signal (basements, tunnels, deliberately offline industrial settings). They also depend on the host staying online — pick a platform whose business model is self-sustaining, keep an export of every vCard you host, and prefer hosts that let you bring your own custom domain so you can move providers without breaking codes. We covered the deeper trade-off in static vs dynamic QR codes, and the editing flow in detail in dynamic vCard QR codes.
For a personal business card you reprint anyway every year or two, static is defensible. For company cards, conference badges, packaging, anything that might outlive a phone-number change or a job change, dynamic pays back the moment something needs to move.
Build one in under two minutes
The fastest path is to use a generator that writes the vCard text for you, validates the fields, and renders the QR at the right error correction level for the print context you specify. On Linked.Codes the steps are:
- Sign in and go to
/app/qrin the dashboard. - Hit New and pick Contact as the destination type.
- Fill the form — name, phone, email, organisation, title, and whatever else applies. The form generates the vCard text in the background as you type.
- Pick Dynamic if you want editable; Static if you want offline-capable and unchanging.
- Save. The QR is rendered in the preview at level Q error correction with round modules. Download as PNG or SVG, or share the editor link.
The whole process is a couple of minutes from cold start. The vCard text is correctly escaped, the phone numbers are validated for international format, and the QR is sized for the typical print contexts. If you want to verify the encoded text before you ship, the dashboard shows it under a "view source" toggle so you can copy-paste it into a text editor and confirm.
If you would rather hand-roll the vCard for a one-off use case, the format is plain enough that any text editor works. Save with extension .vcf, drop it into any free QR generator that accepts text input, and you get a working static contact-saving QR. The only thing the platform-built version gives you that the manual version does not is the ability to edit it after print.
Field-by-field — what to include, what to skip
vCard 3.0 supports dozens of fields. Most of them you will never use. Here is the practical short list, ordered by how often they actually show up in working business contacts.
Always include
N:— Structured name (last;first;middle;prefix;suffix). Apple's parser expects it; Android tolerates either. The trailing semicolons matter —N:Doe;Jane;;;is correct for first-and-last, with empty middle/prefix/suffix.FN:— Formatted display name. The string the contacts app shows in the list. Always include bothN:andFN:even when they encode the same name.TEL;TYPE=CELL:— Mobile phone in international format.+countrycode-area-numberworks everywhere; bare local numbers (0812345678) work on the scanning phone but break when the contact tries to call from another country.EMAIL:— Email address. No type modifier needed for the primary email; the contacts app labels it however the user has it configured.
Usually include
ORG:— Organisation name. The company, team, or brand. Some contacts apps display this prominently in the list; some hide it behind a tap.TITLE:— Job title. Free-form text; "Founder," "Senior Account Manager," "Lead Plumber" — all fine.URL:— Website. Use the full URL withhttps://prefix; bare domains (linked.codes) work in most parsers but fail in a few older Android builds.
Add when relevant
TEL;TYPE=WORK:— Office phone. Add a secondTELline below the cell line; same line format with a differentTYPE. Up to three or four phone numbers is comfortable; past that the QR gets dense.TEL;TYPE=FAX:— Fax. Yes, in 2026, still a thing in legal, healthcare, and government contexts. Skip it if you do not have one.ADR:— Physical address. Structured:ADR:po-box;extension;street;city;region;postcode;country. The seven-field structure is fixed by RFC; empty fields are just empty between semicolons. Most parsers accept partial addresses (city + country only, for instance).NOTE:— Free-text note. Useful for "Best contact: WhatsApp" or "Speaks English and Indonesian." Keep it short; it inflates the QR more than you would expect.BDAY:— Birthday. FormatYYYY-MM-DD. Personal contacts only — leaving this on a business card is unusual.
Photo — the special case
PHOTO:— Contact photo. Two encoding choices.PHOTO;ENCODING=b;TYPE=JPEG:<base64 blob>embeds the image directly in the vCard. The QR balloons immediately — even a small photo pushes the encoded text past 1,000 characters, which produces a QR too dense to print on a normal business card.PHOTO;VALUE=URI:https://linked.codes/photos/jane.jpgreferences the image at a URL. The contacts app fetches it on first save. Adds maybe 60 characters to the vCard. This is what you want for any QR you actually plan to print.
Social profiles
X-SOCIALPROFILE:is a non-standard extension. Some parsers respect it (Apple Contacts), most ignore it. The pragmatic alternative is to put the profile URL inURL:(for the primary one) or inNOTE:(for secondary ones). LinkedIn, X, GitHub — all of those work as plain URLs.
Skip these
LOGO:— Same size problem asPHOTO:, with worse compatibility. UseURL:for the company website instead and let the contacts app pick up the favicon.BDAY:for business contacts. Personal information that nobody asked for.ROLE:— Vague and inconsistent.TITLE:is what every contacts app actually displays.CATEGORIES:— Maybe useful in CRM imports; ignored in 95% of phone contacts apps.X-*extension fields beyondX-SOCIALPROFILE. Inconsistent across parsers, occasionally cause silent import failures.
The principle: every field you add makes the encoded text longer, which makes the QR denser. A vCard with eight sensible fields is sparse, prints small, scans easily. A vCard with everything from the spec is bloated, prints big, scans badly.
A live vCard builder
Type into the form below and watch the encoded vCard text update in real time. The character count and density indicator tell you whether the QR will print comfortably or whether you are pushing the size envelope.
The defaults give you a working vCard at around 180 characters — comfortably in the green band, prints small, scans from a metre away on a phone camera with no fuss. Add an address, a second phone number, or a long note and you will watch the count climb into the yellow zone within a few keystrokes. Past 400 characters you are in the red — the QR will print, but at sizes that compromise where you can put it.
Build a contact-saving QR you can edit forever — name, title, photo, all of it, with no reprint when something changes.
Start with Linked.CodesThe size problem nobody warns you about
The biggest practical trap with contact QRs is density. A QR code is a fixed-area grid; the more characters you encode, the more modules the spec needs to fit them, which means each module gets smaller at the same physical print size. Below roughly 0.5mm per module a phone camera starts dropping samples and the redundancy budget runs out. The encoded vCard length is what controls the module count, and most generators do not warn you when you cross the threshold.
The rough character budgets, assuming level Q error correction and arm's-length scanning at 30cm:
Two practical rules fall out of this:
- Skip the embedded photo. The base64 image alone is 800-2,000 characters depending on size and compression. Use a
PHOTO;VALUE=URI:line pointing at a hosted image instead. The contacts app fetches the photo on first save; the QR stays small. - Consider MECARD if you are ruthless about size. MECARD is a leaner contact format that some Asian-market generators (and the original DENSO Wave spec) support. It encodes the same basic fields in fewer characters —
MECARD:N:Doe,Jane;TEL:+62...;EMAIL:...;— but compatibility outside Japan and Korea is uneven. iOS handles MECARD; older Android sometimes does not. For a global audience vCard wins on compatibility; for a Japan-only deployment MECARD wins on density.
If the QR is dynamic — encoding a short URL to a hosted vCard — none of this matters. The encoded payload is always 25-30 characters regardless of how many fields you stuff into the hosted file. The size problem is exclusively a static-vCard problem.
iPhone vs Android — what is actually different
The Save Contact prompt looks similar on both platforms but the underlying flow is different in ways worth knowing.
iPhone (iOS 11+). The Camera app's QR scanner intercepts the vCard payload and shows a yellow notification banner across the top of the screen with the contact's name. Tap the banner and a system contact-card sheet slides up — every field pre-filled, an Add Contact button at the top right. Tap it once and the contact lives in the Contacts app. No browser tab opens; no app launches; the whole flow is system-level. Apple's Contacts framework documentation describes the underlying integration.
Android (9+). Behaviour varies a little by OEM and by which scanner the user has set as default (Google Lens, the OEM camera app, or a third-party scanner). The pattern is consistent though: the scanner detects the vCard, shows a preview with the contact's name and primary fields, and offers to open the file in the Contacts app's import handler. The Contacts app shows a similar pre-filled card with a Save button. Some older Android scanners (pre-2022) on cheaper devices do not auto-route vCards to Contacts — they show the raw decoded text and rely on the user to tap a "Add to contacts" link. If your audience skews towards budget Android, the dynamic-vCard pattern (encoding a URL) is more reliable because every Android scanner handles URLs cleanly, and the URL serves the vCard with the right MIME type.
WeChat in-app browser. The exception worth flagging if your audience is in China or any region where WeChat dominates. WeChat's in-app QR scanner sometimes fails to hand vCard payloads over to Contacts cleanly — it shows the raw text or treats the response as a downloadable file. The fix on a dynamic vCard is to detect the user-agent server-side and serve a small landing page with a Save Contact download button. Static vCards have no fix beyond instructing users to scan with the system camera instead.
Browsers and webviews. Anywhere a webview is intercepting the scan (LinkedIn's mobile app, Slack's link preview, an enterprise MDM scanner), behaviour is unpredictable. The reliable pattern is dynamic vCard with a fallback landing page — if the webview cannot parse the response cleanly, the user lands on a normal page with a download link instead of a broken state. This is exactly the integration pattern we covered in dynamic vCard QR codes.
The headline summary: across roughly 99% of consumer scans, a vCard QR feels identical on iPhone and Android. The 1% edge cases (in-app browsers, ancient scanner apps, regional variations) are where good platform engineering matters, and where dynamic vCards quietly outperform static ones.
Print-test it before you ship
The cheapest place to fix a contact QR is before any of it goes to a printer. The five-step pre-flight that catches every common failure:
- Print one proof at the actual final size. Not at A4. Not at the screen preview size. At the size it is going on the card or sticker. Most failures happen because the screen preview at 200×200 pixels looked fine and the printed 18mm version did not.
- Scan from the actual final distance on three phones. A new iPhone, an older Android, and one budget device under £150 (or whatever the equivalent is in your market). If any of the three fails on first try, the design is not ready.
- Worst-light test. Take the print outside, into a fluorescent-lit office, and into a dim restaurant. The QR has to scan in all three. Phone cameras adapt their exposure to ambient light; a code that scans cleanly under noon daylight sometimes fails under restaurant tea lights.
- Smallest-size test. Reduce the print size by 20% and scan again. If it still scans, you have safety margin. If it just barely scans at the planned size, any minor printing variation (lighter ink, slightly off-register) will push it over the edge in production.
- Damage-tolerance test. Take a fresh proof, smudge a corner with a finger, and scan again. The error correction level has to absorb the damage. If it fails after a tiny smudge, bump the error correction level up before the print run. The full picker is in QR error correction levels.
A useful supplement is the test-grid pattern: print the same QR at four different sizes (12mm, 18mm, 24mm, 32mm) on the same proof sheet and scan each one in sequence. The smallest size that scans first try across all three phones is your floor; the size you actually ship at should be at least 30% above that floor. Anything below the floor is a gamble you will lose at scale.
If a code fails the pre-flight, the failure mode tells you exactly what to fix. Walk the six causes in QR code not scanning — six fixes before assuming the spec is broken or the camera is broken — it almost never is. It is contrast, size, error correction, glare, damage, or payload, in roughly that order of frequency.
Common mistakes that kill contact QRs
Five mistakes that turn a good-looking QR into a dead one. Every one is a one-line fix in the encoded text.
Wrong line endings. Strict parsers expect CRLF (\r\n) per RFC 6350. A vCard with bare LF endings (\n) works on iOS and modern Android but fails silently on certain enterprise contact systems and older Android builds. Most generators handle this for you; if you write the vCard manually, do not skip it.
Missing END:VCARD. The terminator line is mandatory. A vCard without it is "open" and parsers either reject it or import an empty contact. Easy mistake when you copy-paste a vCard from one generator and edit it manually — make sure the END line survives.
Unescaped commas in addresses. ADR:;;Jl. Sunset, Block C;Denpasar;Bali;80361;ID is broken — the Sunset, Block C has an unescaped comma that the parser reads as a field separator, splitting your street address across two slots. The fix is ADR:;;Jl. Sunset\, Block C;Denpasar;Bali;80361;ID with the backslash. Same trap for semicolons and colons inside any field value.
Photo URL behind authentication. A PHOTO;VALUE=URI: field that points at an image requiring a login (a Google Drive link, a Notion attachment, a private CDN bucket) breaks for the receiving phone. The contacts app cannot authenticate; the photo silently fails to load. Use a public URL on a CDN you control, or skip the photo.
Local-format phone numbers. TEL:0812345678 works on the scanning phone today and breaks the day someone tries to call from another country. TEL:+628123456789 works everywhere. The international format is a tiny formatting cost for permanent compatibility — never skip the country code.
Smart quotes from a word processor. Pasting a vCard you wrote in Word or Pages drops curly quotes (" and ") into the field values. Some parsers handle them; some choke. If the encoded vCard contains a quoted name or a quoted note, retype the quotes in a plain-text editor first.
The whole list adds up to one principle: vCards are forgiving but not infinitely forgiving, and the small number of strict parsers in the wild are the ones that will quietly reject your contact card without telling you. Test on at least two phones with different operating systems before you commit to a print run.
FAQ
Related reading
- vCard QR codes — the modern business card — the broader case for vCard-encoded QRs.
- Dynamic vCard QR codes — when you want to update the contact card without reprinting.
- QR codes — platform docs — how the dashboard wires every QR type, including vCard.
Do iPhones automatically save the contact?
No — they prompt. The Camera app shows a yellow notification banner with the contact's name, and a tap opens a system contact-card sheet with every field pre-filled. The user has to confirm with Add Contact. There is no silent-save flow on iOS for security reasons; same goes for Android. Any QR that claims to "auto-save" is encoding a deeplink that opens a contact-edit screen and still requires user confirmation.
What is the difference between MECARD and vCard?
MECARD is a leaner contact format invented for Japanese phones in the early 2000s. It encodes the same basic fields (name, phone, email, organisation) in roughly half the characters of a vCard, which produces a smaller QR. The trade-off is compatibility — iOS handles it, but older Android and most enterprise contact systems do not. For global audiences, vCard is the safer default. For a Japan-only deployment where size matters more than compatibility, MECARD is defensible.
Why does my QR code show as a long string instead of a contact?
The decoder read the QR fine, but something about the payload is preventing the OS from routing it to Contacts. Three usual suspects: (1) the QR is wrapped in a URL that points at a webpage instead of serving the vCard with a text/vcard MIME header, (2) the vCard text is malformed (missing END:VCARD, wrong VERSION line, smart quotes from a word processor), or (3) the scanner app is one of the older budget-Android ones that does not auto-route vCards. Test the encoded text in a vCard validator first; if it is clean, switch to a system camera scanner.
Can I include a photo?
Yes, two ways. Embed the image as base64 in a PHOTO;ENCODING=b field — works on every modern phone but balloons the QR to roughly 1,000-2,000 characters, which is unprintably dense at business-card sizes. Or reference the image at a URL with PHOTO;VALUE=URI: — the contacts app fetches it on first save, the vCard stays small, and you can update the photo later by replacing the image at the URL. The URL form is what you want for any QR you actually plan to print.
Will the QR still work after I update my number?
Only if it is a dynamic vCard QR. A static QR has the entire contact text baked into the modules — change anything and every printed code is wrong, and the only fix is reprint. A dynamic QR encodes a short URL pointing at a hosted vCard file; you edit the file and every existing code starts serving the new contact details on the next scan. For anything you are printing in volume, dynamic is worth the small infrastructure cost.
How big should I print it?
Minimum side length in mm equals scan distance in mm divided by 30. Arm's length scanning at 30cm needs at least 10mm of side, with 18mm being the comfortable floor. On a business card, 20-25mm is sensible. On a poster scanned from 2m, 70mm minimum, 90mm comfortable. Always print one proof and field-test before the full run — screen previews lie about printed scan behaviour.
Related reading
If you are building any structured-payload QR (contact, calendar, WiFi, payment), the principles are similar across formats. A few posts that connect:
- vCard QR codes — the digital business card — the format primer; the field reference and the static-vs-dynamic decision in more depth.
- Dynamic vCard QR codes — why most generators skip them — the editing-flow walkthrough; how the redirect-to-vcf pattern actually works under the hood.
- QR code not scanning? Six fixes that solve 95% of cases — the full diagnostic for any code that scans cleanly in preview and fails in the wild.
- Static vs dynamic QR codes — the editing-vs-permanence trade-off applied across all QR types, not just contact cards.
- QR error correction levels — picking the right level for your print context, especially if the code is going on packaging or signage.
- Dynamic QR types by default — why the dynamic pattern beats static for almost every commercial use case.
- WiFi QR codes — share without sharing — the sister "structured data in a QR" format. Same RFC-era approach, different payload.
Sourcesshow citations
- IETF RFC 6350: vCard Format Specification (vCard 4.0) — https://www.rfc-editor.org/rfc/rfc6350
- IETF RFC 2426: vCard MIME Directory Profile (vCard 3.0) — https://www.rfc-editor.org/rfc/rfc2426
- IANA media type registry — text/vcard — https://www.iana.org/assignments/media-types/text/vcard
- Wikipedia: vCard — https://en.wikipedia.org/wiki/VCard
- Wikipedia: QR code — https://en.wikipedia.org/wiki/QR_code
- ISO/IEC 18004:2024 QR code bar code symbology specification — https://www.iso.org/standard/83389.html
- Apple Developer: Contacts framework — https://developer.apple.com/documentation/contacts
- Wikipedia: MECARD — https://en.wikipedia.org/wiki/MeCard_(QR_code)
Try it on your own domain
Branded short links and dynamic QR codes, on your subdomain or your own domain. One-time purchase, no per-click fees.