← Back to Blog

How to Generate a QR Code Business Card in Python

Prabhu Kumar Dasari
Prabhu Kumar Dasari
Senior XR Developer Β· 13+ Years Β· allinoneaicenter.com
πŸ“… May 18, 2026 ⏱ 12 min read 🐍 Python 3.9+
QR codes on business cards are not a gimmick. When someone scans yours, their phone opens a contact prompt with your name, email, phone, website and job title pre-filled β€” one tap to save, no typing. In this tutorial I will show you how to generate that exact QR code in Python, starting from a one-liner all the way to a polished business card generator script that produces the same vCard format powering the live QR generator on this site.

Prerequisites & Installation

You need Python 3.9 or newer. Check your version first:

bash
python --version
# Python 3.12.x  ← anything 3.9+ is fine

The main library is qrcode. The [pil] extra pulls in Pillow for PNG/JPEG image output β€” you almost always want this:

bash
pip install "qrcode[pil]"

To also export as SVG (ideal for business card print files), add:

bash
pip install "qrcode[pil]" svglib
πŸ’‘ Tip β€” virtual environment

Always install into a virtual environment: python -m venv venv && source venv/bin/activate (or venv\Scripts\activate on Windows). This keeps your global Python clean.

Step 1 β€” Your First QR Code (URL)

Before building the full business card version, let us make sure everything works with the simplest possible case β€” a URL QR code:

python β€” basic_qr.py
import qrcode

img = qrcode.make("https://allinoneaicenter.com")
img.save("basic_qr.png")
print("βœ… basic_qr.png saved")

Run it with python basic_qr.py and a 290 Γ— 290 pixel PNG appears in your folder. Scan it β€” it opens your URL. That is the whole library in two lines.

πŸ“ What qrcode.make() does

It is a convenience wrapper that uses default settings: error correction M (15% recovery), box size 10px, border 4 modules, black on white. For business cards we will override all of these.

Step 2 β€” Encode a vCard (the Business Card Standard)

A URL QR code only opens a webpage. A vCard QR code tells the phone to save a contact β€” name, title, email, phone, website and address all land directly in the address book. This is what makes a QR code genuinely useful on a business card.

The vCard 3.0 format is plain text with one field per line. Here is the exact format that works on both iOS and Android:

python β€” build_vcard.py
def build_vcard(
    name:  str,
    title: str = "",
    email: str = "",
    url:   str = "",
    phone: str = "",
    city:  str = "",
) -> str:
    """Return a vCard 3.0 string ready to encode into a QR code."""
    parts = name.strip().rsplit(" ", 1)
    last  = parts[-1] if len(parts) > 1 else ""
    first = parts[0]  if len(parts) > 1 else name

    lines = [
        "BEGIN:VCARD",
        "VERSION:3.0",
        f"N:{last};{first};;;",
        f"FN:{name}",
    ]
    if title: lines.append(f"TITLE:{title}")
    if email: lines.append(f"EMAIL:{email}")
    if url:
        full_url = url if url.startswith("http") else f"https://{url}"
        lines.append(f"URL:{full_url}")
    if phone: lines.append(f"TEL:{phone}")
    if city:  lines.append(f"ADR:;;{city};;;;")
    lines.append("END:VCARD")
    return "\n".join(lines)


# ── Your details ───────────────────────────────────────────────
vcard = build_vcard(
    name  = "Prabhu Kumar Dasari",
    title = "AI & XR Architect",
    email = "allinoneaicenter@gmail.com",
    url   = "allinoneaicenter.com",
    phone = "+91 00000 00000",
    city  = "Hyderabad, India",
)
print(vcard)

Running the snippet prints something like this β€” the exact text that gets encoded into the QR code:

output
BEGIN:VCARD
VERSION:3.0
N:Dasari;Prabhu Kumar;;;
FN:Prabhu Kumar Dasari
TITLE:AI & XR Architect
EMAIL:allinoneaicenter@gmail.com
URL:https://allinoneaicenter.com
TEL:+91 00000 00000
ADR:;;Hyderabad, India;;;;
END:VCARD
⚠️ Do not use CRLF line endings

Some old vCard specs say \r\n but Android and iOS scanners both handle \n fine. Avoid Windows-style \r\n β€” it adds garbage characters that can corrupt the parsed contact.

Step 3 β€” Generate the QR Code from vCard

Now we feed the vCard string into the QR encoder. The key difference from Step 1 is that we use the QRCode class directly so we can control the error correction level:

python β€” vcard_qr.py
import qrcode
from qrcode.constants import ERROR_CORRECT_H

qr = qrcode.QRCode(
    error_correction=ERROR_CORRECT_H,  # H = 30% recovery β€” best for print
    box_size=10,                        # pixels per module (square dot)
    border=4,                           # quiet zone β€” 4 modules minimum (spec)
)

qr.add_data(vcard)   # vcard string from Step 2
qr.make(fit=True)   # auto-select the smallest QR version that fits

img = qr.make_image(fill_color="black", back_color="white")
img.save("vcard_qr.png")
print(f"βœ… Saved  {img.pixel_size}Γ—{img.pixel_size}px  β†’  vcard_qr.png")
i

Why ERROR_CORRECT_H?

Business cards get folded, scratched and printed at small sizes. Level H recovers up to 30% of damaged data. Levels L/M/Q recover 7%/15%/25% respectively. The trade-off is a slightly denser (more modules) QR code β€” use a box_size of 10+ to keep it scannable.

Step 4 β€” Custom Colours & Size

The default black-on-white works fine, but matching your brand colours makes the card look intentional. Pass hex values to make_image():

python β€” coloured_qr.py
from qrcode.image.styledpil import StyledPilImage
from qrcode.image.styles.moduledrawers import RoundedModuleDrawer

img = qr.make_image(
    image_factory=StyledPilImage,
    module_drawer=RoundedModuleDrawer(),  # rounded dots β€” modern look
    fill_color="#1a2744",                 # dark navy β€” your brand colour
    back_color="white",
)
img.save("branded_qr.png")

Available module drawers in qrcode.image.styles.moduledrawers:

DrawerLookBest for
SquareModuleDrawerDefault square dotsMinimal / technical
RoundedModuleDrawerRounded square dotsBusiness cards βœ“
CircleModuleDrawerCircular dotsCreative / playful
GappedSquareModuleDrawerSquares with gapsAiry / open design
HorizontalBarsDrawerHorizontal bar styleMinimalist
VerticalBarsDrawerVertical bar styleMinimalist
⚠️ Colour contrast matters

Keep at least 4:1 contrast between fill and background. Light grey on white, or yellow on white, will cause scan failures. Dark colour on white or white on very dark background are the safest combinations.

This is the part most tutorials skip. A centred logo turns a generic QR into something people actually stop and scan. The trick is to paste the logo after generation β€” and to use ERROR_CORRECT_H from Step 3 so the covered modules are recoverable:

python β€” logo_qr.py
from PIL import Image

# 1. Generate the base QR image (PIL Image object)
qr_img = qr.make_image(fill_color="#1a2744", back_color="white").convert("RGBA")

# 2. Open logo β€” PNG with transparency preferred
logo = Image.open("logo.png").convert("RGBA")

# 3. Resize logo to ~25% of QR width (safe for H-level error correction)
qr_w, qr_h = qr_img.size
logo_max    = qr_w // 4
logo.thumbnail((logo_max, logo_max), Image.LANCZOS)

# 4. Compute centred position
logo_w, logo_h = logo.size
pos = ((qr_w - logo_w) // 2, (qr_h - logo_h) // 2)

# 5. Add a white circular background behind the logo (cleaner look)
bg_size   = logo_max + 20
logo_bg   = Image.new("RGBA", (bg_size, bg_size), "white")
bg_pos    = ((qr_w - bg_size) // 2, (qr_h - bg_size) // 2)
qr_img.paste(logo_bg, bg_pos)

# 6. Paste the logo (use alpha channel as mask)
qr_img.paste(logo, pos, mask=logo)

# 7. Save
qr_img.convert("RGB").save("logo_qr.png", dpi=(300, 300))
print("βœ… logo_qr.png saved at 300 DPI")
i

Keep the logo under 30% of QR area

ERROR_CORRECT_H can recover up to 30% of the QR data. Covering more than that with a logo risks making the code unreadable. The 25% width rule above (β‰ˆ 6% of total area) gives comfortable headroom β€” the white background padding counts too.

Step 6 β€” Export as SVG (for Print)

PNG at 300 DPI is fine for most printers. But if your designer needs to scale the QR code up for a banner or poster, SVG is the right format β€” it is infinitely scalable with no pixelation. The qrcode library ships SVG factories out of the box:

python β€” svg_qr.py
import qrcode
import qrcode.image.svg
from qrcode.constants import ERROR_CORRECT_H

qr = qrcode.QRCode(error_correction=ERROR_CORRECT_H, border=4)
qr.add_data(vcard)
qr.make(fit=True)

# SvgFillImage β†’ solid filled squares (best for dark-on-white print)
svg_img = qr.make_image(image_factory=qrcode.image.svg.SvgFillImage)

with open("vcard_qr.svg", "wb") as f:
    svg_img.save(f)
print("βœ… vcard_qr.svg saved β€” scalable for print")
FactoryOutputUse when
SvgImageSVG with path outlinesLightweight, minimal SVG
SvgFillImageSVG with filled rectsPrint / design files βœ“
SvgPathImageSVG single compound pathIllustrator / Figma import

Complete Business Card Script

Here is the full, production-ready script that combines everything above. Edit the YOUR DETAILS section at the top and run it β€” it outputs both a PNG (for digital use) and an SVG (for print):

python β€” business_card_qr.py
"""
business_card_qr.py
Generates a vCard QR code for a business card.
Outputs:  business_card_qr.png  (300 DPI, with optional logo)
          business_card_qr.svg  (scalable, for print)

Requirements:
    pip install "qrcode[pil]"
"""

import qrcode
import qrcode.image.svg
from  qrcode.constants import ERROR_CORRECT_H
from  qrcode.image.styledpil import StyledPilImage
from  qrcode.image.styles.moduledrawers import RoundedModuleDrawer
from  pathlib import Path
from  PIL import Image

# ════════════════════════════════════════
#  YOUR DETAILS β€” edit these
# ════════════════════════════════════════
NAME    = "Prabhu Kumar Dasari"
TITLE   = "AI & XR Developer"
EMAIL   = "allinoneaicenter@gmail.com"
URL     = "allinoneaicenter.com"
PHONE   = "+91 00000 00000"
CITY    = "Hyderabad, India"

# Set to path of your logo PNG, or None to skip
LOGO_PATH = None   # e.g. Path("logo.png")

# Brand colours
FG_COLOUR = "#1a2744"   # dark navy
BG_COLOUR = "#ffffff"   # white

# ════════════════════════════════════════
#  BUILD vCARD
# ════════════════════════════════════════
def build_vcard(**kwargs) -> str:
    name  = kwargs.get("name",  "")
    parts = name.strip().rsplit(" ", 1)
    last  = parts[-1] if len(parts) > 1 else ""
    first = parts[0]  if len(parts) > 1 else name
    url   = kwargs.get("url", "")
    lines = [
        "BEGIN:VCARD", "VERSION:3.0",
        f"N:{last};{first};;;", f"FN:{name}",
    ]
    if kwargs.get("title"): lines.append(f"TITLE:{kwargs['title']}")
    if kwargs.get("email"): lines.append(f"EMAIL:{kwargs['email']}")
    if url:
        lines.append(f"URL:{url if url.startswith('http') else 'https://'+url}")
    if kwargs.get("phone"): lines.append(f"TEL:{kwargs['phone']}")
    if kwargs.get("city"):  lines.append(f"ADR:;;{kwargs['city']};;;;")
    lines.append("END:VCARD")
    return "\n".join(lines)

vcard = build_vcard(
    name=NAME, title=TITLE, email=EMAIL,
    url=URL, phone=PHONE, city=CITY
)

# ════════════════════════════════════════
#  GENERATE QR
# ════════════════════════════════════════
qr = qrcode.QRCode(
    error_correction=ERROR_CORRECT_H,
    box_size=12,
    border=4,
)
qr.add_data(vcard)
qr.make(fit=True)

# ── PNG (styled) ──────────────────────────────────────
png_img = qr.make_image(
    image_factory=StyledPilImage,
    module_drawer=RoundedModuleDrawer(),
    fill_color=FG_COLOUR,
    back_color=BG_COLOUR,
).convert("RGBA")

# ── Embed logo (optional) ────────────────────────────
if LOGO_PATH and Path(LOGO_PATH).exists():
    logo        = Image.open(LOGO_PATH).convert("RGBA")
    qr_w, qr_h = png_img.size
    logo_max    = qr_w // 4
    logo.thumbnail((logo_max, logo_max), Image.LANCZOS)
    logo_w, logo_h = logo.size
    bg_pad      = 16
    bg          = Image.new("RGBA", (logo_w+bg_pad, logo_h+bg_pad), "white")
    bg_x        = (qr_w - bg.width)  // 2
    bg_y        = (qr_h - bg.height) // 2
    png_img.paste(bg,   (bg_x, bg_y))
    png_img.paste(logo, (bg_x + bg_pad//2, bg_y + bg_pad//2), mask=logo)

png_img.convert("RGB").save("business_card_qr.png", dpi=(300, 300))
print("βœ… business_card_qr.png")

# ── SVG (for print / designers) ──────────────────────
svg_qr = qrcode.QRCode(
    error_correction=ERROR_CORRECT_H, border=4
)
svg_qr.add_data(vcard)
svg_qr.make(fit=True)
svg_img = svg_qr.make_image(image_factory=qrcode.image.svg.SvgFillImage)
with open("business_card_qr.svg", "wb") as f:
    svg_img.save(f)
print("βœ… business_card_qr.svg")

print("\nπŸŽ‰ Done! Scan business_card_qr.png to verify.")
βœ… What the script produces

business_card_qr.png β€” a 300 DPI PNG with rounded dark-navy dots on white, optionally with your logo centred. Send this to a print shop as-is or drop it into your card design in Canva / Figma.

business_card_qr.svg β€” a scalable vector file. Import into Illustrator, Figma, or Inkscape for print-ready business card layouts.

Try the Live Generator (No Python Needed)

If you just want a QR code right now β€” without setting up Python β€” use the interactive business card generator I built directly on this site. Fill in your name, email, website and phone, and the QR updates live. You can download the PNG instantly.

πŸ“±

Live QR Business Card Generator

Enter your contact details β†’ QR code updates instantly β†’ download PNG β€” free, no login

β†’

The live tool uses the same vCard 3.0 format and the same field structure as the Python script above, so the output is identical. The Python script is useful when you need to automate batch generation β€” for example, generating QR codes for every employee in a CSV, or regenerating your card programmatically whenever your details change.

Bonus β€” Batch Generation from a CSV

Here is how to extend the script to generate a QR code for every person in a spreadsheet. Useful for teams, events or conference badge printing:

python β€” batch_qr.py
"""
batch_qr.py
Reads contacts.csv and generates one QR PNG per row.

CSV columns: name, title, email, url, phone, city
"""

import csv, qrcode
from  qrcode.constants import ERROR_CORRECT_H
from  pathlib import Path

OUT_DIR = Path("qr_output")
OUT_DIR.mkdir(exist_ok=True)

with open("contacts.csv", newline="", encoding="utf-8") as f:
    reader = csv.DictReader(f)
    for i, row in enumerate(reader, start=1):
        vcard = build_vcard(**row)   # reuse function from above

        qr = qrcode.QRCode(error_correction=ERROR_CORRECT_H, box_size=10, border=4)
        qr.add_data(vcard)
        qr.make(fit=True)
        img = qr.make_image(fill_color="#1a2744", back_color="white")

        fname = row["name"].lower().replace(" ", "-") + ".png"
        img.save(OUT_DIR / fname)
        print(f"  [{i}] {fname}")

print(f"\nπŸŽ‰ All QR codes saved to ./{OUT_DIR}/")

Your contacts.csv should look like this:

csv β€” contacts.csv
name,title,email,url,phone,city
Prabhu Kumar Dasari,Senior XR Developer,prabhu@example.com,allinoneaicenter.com,+91 00000 00000,Hyderabad
Anjali Mehta,Product Manager,anjali@example.com,example.com,+91 11111 11111,Mumbai
Rohit Sharma,DevOps Engineer,rohit@example.com,example.com,+91 22222 22222,Bengaluru

Frequently Asked Questions

Which Python library is best for generating QR codes?

The qrcode library (pip install qrcode[pil]) is the most widely used. It supports PNG, SVG, coloured QR codes, rounded modules, and logo embedding. For headless scripts or servers where Pillow is too heavy, segno is a lighter alternative.

What is a vCard QR code?

A vCard QR code encodes contact information in the vCard 3.0 standard β€” name, title, email, phone, URL, and address. When scanned by a smartphone, it prompts the user to save the contact directly to their address book. No app is required; it works in the default camera app on both iOS and Android.

What size should a QR code be on a printed business card?

A minimum of 2 cm Γ— 2 cm (about 0.8 inches square) at the finished print size. Smaller than this and mid-range phone cameras will struggle. 2.5 cm is the safe sweet spot for a standard 3.5 Γ— 2 inch business card. Generate at 300 DPI β€” the PNG script above does this automatically.

How do I add a logo to a QR code without breaking it?

Keep the logo under 25–30% of the QR code's width and use ERROR_CORRECT_H. The error correction level determines how much of the data can be obscured β€” Level H allows 30% recovery. Add a white padding rectangle behind the logo so the adjacent modules remain clearly readable.

Can I generate QR codes as SVG in Python?

Yes. The qrcode library includes SVG factories built-in β€” no extra install needed beyond qrcode[pil]. Use SvgFillImage for solid print-ready output or SvgPathImage if your designer is importing into Illustrator or Figma.

What error correction level should I use?

ERROR_CORRECT_H for business cards (30% recovery). Cards get handled, scuffed, and printed small. H-level keeps your code scannable even when partially damaged. The trade-off is a denser QR code β€” compensate with a larger print size or higher box_size value.

πŸ’¬ Comments 0
Share your thoughts on this article
Loading comments…