DevToolBoxฟรี
บล็อก

QR Code Generator: Create QR Codes Online — Complete Guide

18 min readโดย DevToolBox

TL;DR

QR codes are two-dimensional matrix barcodes that encode data in a grid of black and white squares. Use error correction level M (15%) for most cases and level H (30%) when embedding a logo. Generate QR codes in JavaScript with the qrcode npm package or QRCode.toCanvas() in-browser. Use Python's qrcode[pil] library for server-side generation. Always export as SVG for print-quality output. WiFi codes use the WIFI:T:WPA;S:SSID;P:password;; format, and vCard codes use the standard vCard 3.0 schema. Try our free QR Code Generator to create codes instantly.

Key Takeaways

  • Finder patterns — three 7×7 corner squares — let scanners detect orientation instantly, regardless of rotation.
  • Timing patterns alternate black/white modules and help scanners determine module size and grid alignment.
  • Error correction uses Reed-Solomon codes: L (7%), M (15%), Q (25%), H (30%) — higher levels sacrifice capacity for resilience.
  • Browser QR generation: use qrcode npm package's QRCode.toCanvas() or QRCode.toDataURL().
  • Node.js terminal output: QRCode.toString(data, {type: 'terminal'}) prints a scannable code to stdout.
  • Python: pip install qrcode[pil] then qrcode.make(data).save('qr.png').
  • Logo overlay: always use level H error correction; keep the logo under 25% of QR code area.
  • WiFi QR syntax: WIFI:T:WPA;S:NetworkName;P:Password;; — smartphones auto-prompt to join.
  • vCard QR codes: encode the full vCard 3.0 string; cameras offer to save the contact directly.
  • Max capacity at level L: 7,089 numeric or 4,296 alphanumeric characters in a Version 40 (177×177) code.
  • SVG over PNG: SVG scales perfectly to any size; raster PNG should be generated at final target resolution.
  • Common use cases: URLs, payment links, restaurant menus, authentication (TOTP), event tickets, product packaging.

QR Code Structure: Finder Patterns, Timing, and Data Modules

Every QR code is a matrix of black and white squares called modules arranged on a square grid. The grid size ranges from 21×21 modules (Version 1) to 177×177 modules (Version 40). Within this grid, several functional regions work together to make the code scannable under real-world conditions.

Finder Patterns

The three large square patterns in the top-left, top-right, and bottom-left corners are called finder patterns. Each is a 7×7 module region: a solid 3×3 black square, surrounded by a 1-module white border, surrounded by a 1-module black ring. This distinctive nested-square appearance is uniquely recognizable by scanners and does not occur anywhere else in natural images.

Finder patterns serve three critical functions: (1) they tell the scanner that a QR code is present, (2) they provide three reference points that define the code's position and orientation — even if the code is upside-down or rotated — and (3) they enable perspective correction so that codes photographed at an angle can still be decoded. The deliberate absence of a finder pattern in the bottom-right corner tells the scanner which corner is which.

Separating each finder pattern from the data region is a 1-module-wide white separator. This white space prevents the finder pattern from blending into adjacent data modules.

Timing Patterns

Running horizontally between the top two finder patterns and vertically between the top-left and bottom-left finder patterns are the timing patterns: alternating single-module-wide rows and columns of black and white modules (black-white-black-white...). These patterns allow the scanner to determine the size of individual modules across the entire grid, compensating for variations in print quality, camera angle, or code size. Without timing patterns, the scanner would have to guess module boundaries.

Alignment Patterns

QR codes Version 2 and higher include alignment patterns — smaller 5×5 module squares (a 1×1 black center, white ring, black ring) placed at fixed positions throughout the code. Their role is to correct for perspective distortion when the QR code is on a curved or tilted surface. The number of alignment patterns grows with the version: Version 2 has one extra alignment pattern, while Version 40 has 46.

Format and Version Information

A 15-bit format information strip, stored redundantly in two locations near the finder patterns, encodes the error correction level and the mask pattern number. This strip is the first thing the scanner reads after locating the finder patterns.

QR codes Version 7 and above also contain 18-bit version information blocks near the top-right and bottom-left finder patterns. These tell the scanner the exact version number, which determines the grid dimensions and the positions of alignment patterns.

Data Modules and the Quiet Zone

The remaining area of the grid holds the actual data codewords and error correction codewords, arranged in an 8-module-wide zigzag pattern that avoids the fixed functional regions. A mask pattern (one of eight predefined patterns) is XOR-applied to the data modules to prevent large uniform regions of the same color, which confuse scanners.

Surrounding the entire QR code is the mandatory quiet zone — at least 4 modules of blank (white) space on every side. This border is the most frequently overlooked requirement: cropping or reducing the quiet zone is the single most common cause of scan failures in printed QR codes.

QR Code Module Layout (simplified, Version 1 — 21×21):

┌─────────────────────────────────┐   ← quiet zone (min 4 modules)
│  ┌───────┐  timing  ┌───────┐  │
│  │ FP 1  │──────────│ FP 2  │  │   FP = Finder Pattern (7×7)
│  └───────┘          └───────┘  │
│      │                         │   timing = alternating black/white
│      │         DATA REGION     │
│      │                         │
│  ┌───────┐                     │
│  │ FP 3  │                     │
│  └───────┘                     │
└─────────────────────────────────┘

Version → Module grid → Typical data (Level M)
  1     →  21 × 21    →  up to 14 alphanumeric chars
  3     →  29 × 29    →  up to 47 alphanumeric chars  (short URL)
  5     →  37 × 37    →  up to 90 alphanumeric chars  (standard URL)
  10    →  57 × 57    →  up to 219 alphanumeric chars (full vCard)
  40    → 177 × 177   →  up to 4296 alphanumeric chars (max)

Error Correction Levels: L, M, Q, and H Explained

QR codes use Reed-Solomon error correction, a mathematical technique that allows a scanner to reconstruct data even when part of the code is damaged, obscured, or poorly printed. The QR standard defines four error correction levels, each identified by a letter:

LevelNameRecovery CapacityRecommended Use
LLowUp to 7% of codewordsMaximum data capacity; clean digital display only
MMediumUp to 15% of codewordsDefault for most use cases: print, web, packaging
QQuartileUp to 25% of codewordsIndustrial environments, outdoor signage, labels
HHighUp to 30% of codewordsRequired when embedding a logo over the QR code

Higher error correction levels work by adding more redundant codewords to the data. These extra codewords take up modules that would otherwise hold data, so the trade-off is reduced data capacity for the same version, or a larger version required to hold the same amount of data. For example, a Version 5 QR code at level L stores up to 109 alphanumeric characters, but at level H stores only 45.

Choosing the right level: For digital display (screens, PDFs, emails), level M is sufficient. For printed materials that may experience wear — restaurant menus, business cards, event posters, product labels — use level M or Q. For QR codes printed on textured surfaces, applied as stickers, or used outdoors where dirt and UV damage are expected, use level Q or H. If you are embedding a logo, always use level H without exception.

JavaScript qrcode Library: Browser Generation

The most popular QR code library for browser JavaScript is qrcode.js (package name qrcode on npm). It works without a build step via CDN and supports all four error correction levels, custom colors, canvas rendering, and data URL output.

Via CDN (no build step)

<!-- Load from CDN -->
<script src="https://cdn.jsdelivr.net/npm/qrcode@1/build/qrcode.min.js"></script>

<canvas id="qr-canvas"></canvas>
<img id="qr-img" alt="QR Code" />

<script>
  const data = 'https://viadreams.cc/en/tools/qr-code-generator';

  // Render to canvas
  QRCode.toCanvas(
    document.getElementById('qr-canvas'),
    data,
    { errorCorrectionLevel: 'M', width: 300, margin: 4 },
    (err) => { if (err) console.error(err); }
  );

  // Or get a data URL for an <img> tag
  QRCode.toDataURL(data, { errorCorrectionLevel: 'M', width: 300 })
    .then(url => { document.getElementById('qr-img').src = url; })
    .catch(console.error);
</script>

Via npm (React / Next.js)

npm install qrcode
npm install --save-dev @types/qrcode  # TypeScript
'use client';
import { useEffect, useRef, useState } from 'react';
import QRCode from 'qrcode';

interface QrDisplayProps {
  data: string;
  errorLevel?: 'L' | 'M' | 'Q' | 'H';
  size?: number;
}

export default function QrDisplay({ data, errorLevel = 'M', size = 256 }: QrDisplayProps) {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const [dataUrl, setDataUrl] = useState<string>('');

  useEffect(() => {
    if (!canvasRef.current || !data) return;

    QRCode.toCanvas(canvasRef.current, data, {
      errorCorrectionLevel: errorLevel,
      width: size,
      margin: 4,
      color: { dark: '#000000', light: '#ffffff' },
    });

    // Also produce a data URL for download
    QRCode.toDataURL(data, { errorCorrectionLevel: errorLevel, width: size, type: 'image/png' })
      .then(setDataUrl);
  }, [data, errorLevel, size]);

  return (
    <div>
      <canvas ref={canvasRef} />
      {dataUrl && (
        <a href={dataUrl} download="qrcode.png">Download PNG</a>
      )}
    </div>
  );
}

SVG output in the browser

import QRCode from 'qrcode';

// Get SVG string
const svgString = await QRCode.toString('https://example.com', {
  type: 'svg',
  errorCorrectionLevel: 'M',
  margin: 4,
});

// Inject into DOM
document.getElementById('qr-container').innerHTML = svgString;

// Or create a downloadable SVG Blob
const blob = new Blob([svgString], { type: 'image/svg+xml' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'qrcode.svg';
link.click();

Node.js qrcode Package: Terminal and File Output

The same qrcode npm package works in Node.js for server-side generation, CLI tools, and build scripts. You can output QR codes directly to the terminal (useful for DevOps scripts), save as PNG files, or generate SVG strings to write to disk.

Terminal output (print to stdout)

// qr-terminal.mjs
import QRCode from 'qrcode';

const url = 'https://viadreams.cc/en/tools/qr-code-generator';

// Print as UTF-8 block characters (scannable in most terminals)
const terminalStr = await QRCode.toString(url, {
  type: 'terminal',
  small: true,           // uses half-block characters for smaller output
  errorCorrectionLevel: 'M',
});
console.log(terminalStr);

// Run: node qr-terminal.mjs

Save as PNG file

// save-qr.mjs
import QRCode from 'qrcode';
import { writeFileSync } from 'fs';

const data = 'https://viadreams.cc/en/tools/qr-code-generator';

// Save to PNG file
await QRCode.toFile('output.png', data, {
  errorCorrectionLevel: 'H',
  width: 1000,           // pixels — use large size for print quality
  margin: 4,
  color: {
    dark: '#000000',
    light: '#ffffff',
  },
});
console.log('QR code saved to output.png');

// Save as SVG
const svgString = await QRCode.toString(data, {
  type: 'svg',
  errorCorrectionLevel: 'M',
  margin: 4,
});
writeFileSync('output.svg', svgString);
console.log('QR code saved to output.svg');

Batch generation in a script

// batch-qr.mjs
import QRCode from 'qrcode';
import { mkdirSync } from 'fs';
import path from 'path';

const items = [
  { id: 'table-1', url: 'https://restaurant.com/menu?table=1' },
  { id: 'table-2', url: 'https://restaurant.com/menu?table=2' },
  { id: 'table-3', url: 'https://restaurant.com/menu?table=3' },
];

mkdirSync('./qr-codes', { recursive: true });

for (const item of items) {
  await QRCode.toFile(
    path.join('./qr-codes', `${item.id}.png`),
    item.url,
    { errorCorrectionLevel: 'M', width: 500 }
  );
  console.log(`Generated: ${item.id}.png`);
}
// Run: node batch-qr.mjs

Python qrcode Library: Complete Guide

The qrcode Python library is the standard tool for QR generation in Python projects. It requires Pillow (PIL) for PNG output, but can also generate SVG without Pillow.

Installation

# For PNG output (includes Pillow)
pip install qrcode[pil]

# For SVG output only (no Pillow required)
pip install qrcode

Basic usage

import qrcode
from qrcode.constants import ERROR_CORRECT_L, ERROR_CORRECT_M, ERROR_CORRECT_Q, ERROR_CORRECT_H

# Simple one-liner
img = qrcode.make('https://viadreams.cc/en/tools/qr-code-generator')
img.save('qr_simple.png')

# Full control with QRCode object
qr = qrcode.QRCode(
    version=None,              # None = auto-select minimum version
    error_correction=ERROR_CORRECT_M,
    box_size=10,               # pixels per module
    border=4,                  # quiet zone width in modules
)
qr.add_data('https://viadreams.cc/en/tools/qr-code-generator')
qr.make(fit=True)             # fit=True auto-adjusts version

img = qr.make_image(fill_color='black', back_color='white')
img.save('qr_full.png')
print(f'QR Version: {qr.version}, Data: {len(qr.data_list[0].data)} bytes')

SVG output (no Pillow needed)

import qrcode
import qrcode.image.svg

# SVG with rect elements (good for CSS styling)
factory = qrcode.image.svg.SvgPathImage   # or SvgImage, SvgFillImage

qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_M)
qr.add_data('https://viadreams.cc/en/tools/qr-code-generator')
qr.make(fit=True)

img = qr.make_image(image_factory=factory)
img.save('qr_code.svg')    # saves clean, scalable SVG

In-memory bytes (for web APIs / Flask / Django)

import qrcode
import io
from flask import Flask, Response, request

app = Flask(__name__)

@app.route('/qr')
def generate_qr():
    data = request.args.get('data', 'https://example.com')

    qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_M)
    qr.add_data(data)
    qr.make(fit=True)
    img = qr.make_image(fill_color='black', back_color='white')

    buf = io.BytesIO()
    img.save(buf, format='PNG')
    buf.seek(0)
    return Response(buf.getvalue(), mimetype='image/png')

# GET /qr?data=https://viadreams.cc → returns PNG

Adding a Logo to the Center of a QR Code

Embedding a brand logo in the center of a QR code is a popular design technique. It works because the error correction system can reconstruct the obscured data — but only if the logo covers less area than the recovery capacity of the error correction level. Always use level H (30% recovery).

The rule: Keep the logo under 25% of the total QR code area (to leave a safety margin below the 30% limit). For a 300×300 pixel QR code, the logo should be at most about 75×75 pixels, centered.

JavaScript / Canvas approach

import QRCode from 'qrcode';

async function generateQrWithLogo(
  data: string,
  logoSrc: string,
  canvasElement: HTMLCanvasElement,
  qrSize = 400
) {
  // Step 1: Generate QR at level H (required for logo overlay)
  await QRCode.toCanvas(canvasElement, data, {
    errorCorrectionLevel: 'H',   // MUST be H when adding a logo
    width: qrSize,
    margin: 4,
  });

  // Step 2: Load the logo image
  const logo = new Image();
  logo.src = logoSrc;
  await new Promise<void>((resolve) => { logo.onload = () => resolve(); });

  // Step 3: Draw logo over the center of the QR code
  const ctx = canvasElement.getContext('2d')!;
  const logoSize = Math.floor(qrSize * 0.22);   // 22% of QR code size (safe under 25%)
  const logoX = (qrSize - logoSize) / 2;
  const logoY = (qrSize - logoSize) / 2;

  // Optional: white rounded background behind logo for contrast
  ctx.fillStyle = '#ffffff';
  ctx.beginPath();
  ctx.roundRect(logoX - 6, logoY - 6, logoSize + 12, logoSize + 12, 8);
  ctx.fill();

  // Draw the logo
  ctx.drawImage(logo, logoX, logoY, logoSize, logoSize);
}

// Usage example
const canvas = document.getElementById('qr') as HTMLCanvasElement;
await generateQrWithLogo(
  'https://viadreams.cc/en/tools/qr-code-generator',
  '/logo.png',
  canvas,
  400
);

Python: logo overlay with Pillow

import qrcode
from PIL import Image

def generate_qr_with_logo(data: str, logo_path: str, output_path: str, qr_size: int = 600):
    # Step 1: Generate QR at level H
    qr = qrcode.QRCode(
        error_correction=qrcode.constants.ERROR_CORRECT_H,
        box_size=10,
        border=4,
    )
    qr.add_data(data)
    qr.make(fit=True)
    qr_img = qr.make_image(fill_color='black', back_color='white').convert('RGBA')
    qr_img = qr_img.resize((qr_size, qr_size), Image.LANCZOS)

    # Step 2: Open and resize logo to 22% of QR code size
    logo = Image.open(logo_path).convert('RGBA')
    logo_size = int(qr_size * 0.22)
    logo = logo.resize((logo_size, logo_size), Image.LANCZOS)

    # Step 3: Create white rounded background (optional but recommended)
    bg_size = logo_size + 20
    bg = Image.new('RGBA', (bg_size, bg_size), (255, 255, 255, 255))

    # Step 4: Paste logo onto white background, center on QR code
    bg.paste(logo, (10, 10), logo)
    pos = ((qr_size - bg_size) // 2, (qr_size - bg_size) // 2)
    qr_img.paste(bg, pos, bg)

    # Save final image
    qr_img.convert('RGB').save(output_path)
    print(f'Saved: {output_path}')

generate_qr_with_logo(
    'https://viadreams.cc/en/tools/qr-code-generator',
    'logo.png',
    'qr_with_logo.png'
)

Styling QR Codes: Colors and Rounded Corners

QR codes do not have to be black and white. You can use custom foreground and background colors, or even render rounded corners on modules for a softer look. There are two important constraints: maintain sufficient contrast ratio (dark modules on light background, never the reverse) and never use colors so similar that a scanner cannot distinguish dark from light.

Custom colors with qrcode npm

import QRCode from 'qrcode';

// Brand-colored QR code
await QRCode.toFile('branded.png', 'https://example.com', {
  errorCorrectionLevel: 'M',
  width: 500,
  margin: 4,
  color: {
    dark: '#1e3a5f',    // dark blue modules (must be darker than background)
    light: '#f0f9ff',   // light blue background
  },
});

// Transparent background (good for overlay on colored surfaces)
await QRCode.toFile('transparent.png', 'https://example.com', {
  errorCorrectionLevel: 'M',
  width: 500,
  color: {
    dark: '#000000',
    light: '#00000000',  // fully transparent background (alpha 00)
  },
});

Rounded corners with Canvas API

// Draw each module as a rounded rectangle using Canvas 2D API
import QRCode from 'qrcode';

async function roundedQR(data: string, canvas: HTMLCanvasElement) {
  // Get raw bit matrix
  const matrix = await QRCode.create(data, { errorCorrectionLevel: 'M' });
  const modules = matrix.modules;
  const size = modules.size;

  const moduleSize = canvas.width / (size + 8);  // 8 = 2 × 4 quiet zone modules
  canvas.height = canvas.width;
  const ctx = canvas.getContext('2d')!;

  ctx.fillStyle = '#ffffff';
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  const offset = 4 * moduleSize;  // quiet zone offset
  const radius = moduleSize * 0.3; // 30% rounding

  ctx.fillStyle = '#000000';
  for (let row = 0; row < size; row++) {
    for (let col = 0; col < size; col++) {
      if (modules.get(row, col)) {
        const x = offset + col * moduleSize;
        const y = offset + row * moduleSize;
        ctx.beginPath();
        ctx.roundRect(x + 1, y + 1, moduleSize - 2, moduleSize - 2, radius);
        ctx.fill();
      }
    }
  }
}

Color contrast rules

  • The dark modules must always be darker than the light modules. Never swap the colors (light modules on dark background can cause scan failures on some devices).
  • Maintain a minimum contrast ratio of 3:1 between dark and light areas (WCAG AA standard).
  • Avoid using red as the only differentiator — red and green look the same to color-blind users, and some camera algorithms are insensitive to red.
  • Test your styled QR code on multiple devices (iOS camera, Android camera, dedicated QR scanner apps) before deployment.

SVG vs PNG Output: When to Use Each

The choice between SVG and PNG output affects print quality, file size, browser performance, and use-case compatibility. Understanding the trade-offs helps you choose the right format for each context.

PropertySVGPNG
ScalingPerfect at any size (vector)Pixelates when enlarged
File sizeSmall (~5-20 KB)Larger at high resolution
Print qualityBest — crisp at any DPIGood only if generated large
Browser supportAll modern browsersUniversal
Email embeddingNot supported in most clientsWorks everywhere
CSS stylingSupported (fill, stroke, etc.)Not supported
Office docsLimited (Word, PowerPoint vary)Best compatibility
Recommended forWeb, print, master sourceSocial media, email, Office

Best practice workflow: Generate and save your QR code as SVG. Use the SVG directly in web pages. When you need PNG — for email newsletters, social media posts, or Word documents — export from the SVG at 1000×1000 pixels or larger. Never scale up a small PNG; always generate at the target size or above.

QR Codes for WiFi Networks: The WIFI: Protocol

The WiFi QR code format is a de facto standard supported by iOS 11+ and Android 10+ (Android 9 and earlier require a separate app). Scanning a WiFi QR code on a supported device shows a prompt asking whether to join the network — no typing required.

WiFi QR string format

WIFI:T:<encryption>;S:<SSID>;P:<password>;H:<hidden>;;

Field values:
  T  = WPA   (WPA/WPA2/WPA3 — most common)
       WEP   (legacy, insecure — avoid if possible)
       nopass (open network, no password)
  S  = network SSID (name), e.g. MyHomeNetwork
  P  = Wi-Fi password (omit field entirely for open networks)
  H  = true  (hidden SSID — network does not broadcast its name)
       false (or omit — standard visible network)

Examples:
  WPA network:   WIFI:T:WPA;S:HomeNetwork;P:MySecurePass123;;
  Open network:  WIFI:T:nopass;S:CafeGuest;;
  Hidden WPA:    WIFI:T:WPA;S:HiddenNet;P:pass123;H:true;;

Character escaping rules

If the SSID or password contains any of these characters: \ ; , " : — you must escape them with a backslash.

// Characters that must be escaped: \ ; , " :
// Example: SSID = "Cafe;Network" → escape semicolon
WIFI:T:WPA;S:Cafe\;Network;P:pass;;

// Password with backslash: "my\pass" → double the backslash
WIFI:T:WPA;S:MyNet;P:my\\pass;;

// JavaScript helper
function wifiQrString(ssid: string, password: string, encryption = 'WPA', hidden = false) {
  const escape = (s: string) => s.replace(/[\\;,"":]/g, c => '\\' + c);
  const T = encryption;
  const S = escape(ssid);
  const P = password ? `P:${escape(password)};` : '';
  const H = hidden ? 'H:true;' : '';
  return `WIFI:T:${T};S:${S};${P}${H};`;
}

console.log(wifiQrString('HomeNet', 'secret;pass'));
// → WIFI:T:WPA;S:HomeNet;P:secret\;pass;;

Generate WiFi QR in Python

import qrcode
import re

def wifi_qr_string(ssid: str, password: str, encryption: str = 'WPA', hidden: bool = False) -> str:
    def escape(s: str) -> str:
        return re.sub(r'([\\;,":?])', lambda m: '\\' + m.group(1), s)
    T = encryption
    S = escape(ssid)
    P = f'P:{escape(password)};' if password else ''
    H = 'H:true;' if hidden else ''
    return f'WIFI:T:{T};S:{S};{P}{H};'

wifi_string = wifi_qr_string('HomeNetwork', 'MyP@$$word!')
print(f'WiFi string: {wifi_string}')

qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_M)
qr.add_data(wifi_string)
qr.make(fit=True)
img = qr.make_image(fill_color='black', back_color='white')
img.save('wifi_qr.png')
print('WiFi QR saved to wifi_qr.png')

QR Codes for vCards: Digital Business Cards

vCard QR codes let people scan a code and instantly save a contact to their phone's address book. iOS and Android both recognize the vCard format natively. The QR code encodes a vCard string that begins with BEGIN:VCARD and ends with END:VCARD.

vCard 3.0 format (most compatible)

BEGIN:VCARD
VERSION:3.0
FN:Jane Smith
N:Smith;Jane;;;
ORG:DevToolBox Inc.
TITLE:Senior Developer
TEL;TYPE=WORK,VOICE:+1-415-555-0123
TEL;TYPE=CELL,VOICE:+1-415-555-0456
EMAIL;TYPE=WORK:jane@devtoolbox.com
URL:https://viadreams.cc
ADR;TYPE=WORK:;;123 Main St;San Francisco;CA;94102;USA
END:VCARD

Generate vCard QR in JavaScript

import QRCode from 'qrcode';

interface VCardData {
  firstName: string;
  lastName: string;
  org?: string;
  title?: string;
  phone?: string;
  email?: string;
  url?: string;
  address?: string;
}

function buildVCard(data: VCardData): string {
  const lines = [
    'BEGIN:VCARD',
    'VERSION:3.0',
    `FN:${data.firstName} ${data.lastName}`,
    `N:${data.lastName};${data.firstName};;;`,
    data.org   && `ORG:${data.org}`,
    data.title && `TITLE:${data.title}`,
    data.phone && `TEL;TYPE=CELL,VOICE:${data.phone}`,
    data.email && `EMAIL;TYPE=WORK:${data.email}`,
    data.url   && `URL:${data.url}`,
    data.address && `ADR;TYPE=WORK:;;${data.address}`,
    'END:VCARD',
  ].filter(Boolean) as string[];

  return lines.join('\n');
}

const vCard = buildVCard({
  firstName: 'Jane',
  lastName: 'Smith',
  org: 'DevToolBox Inc.',
  title: 'Senior Developer',
  phone: '+1-415-555-0123',
  email: 'jane@devtoolbox.com',
  url: 'https://viadreams.cc',
});

// Use error correction M — level H if adding logo
const dataUrl = await QRCode.toDataURL(vCard, {
  errorCorrectionLevel: 'M',
  width: 400,
});
console.log('vCard QR data URL:', dataUrl.slice(0, 60), '...');

vCard size considerations

A minimal vCard (name, phone, email only) is typically 80-120 bytes — well within the capacity of a Version 3-4 QR code. A full vCard with address, title, URL, and multiple phone numbers can reach 300-400 bytes, requiring a Version 7-9 code. Keep vCard data minimal: scanners work most reliably at lower QR versions. Omit fields that are not critical for the contact.

QR Code Capacity and Data Limits

QR code capacity depends on three factors: the version (grid size), the error correction level, and the data mode (numeric, alphanumeric, binary, or Kanji). The four data modes offer different capacities for the same number of modules because they use different bit encodings.

VersionModulesLevel L NumericLevel M AlphanumericLevel H Binary (bytes)
121×2141177
225×25773214
329×291275324
537×372209342
1057×57652271122
1577×771249512227
2097×972061843370
25117×11730111220532
40177×177708929531273

Data modes explained:

  • Numeric mode: digits 0-9 only. Most efficient at 3.33 bits per character. Use for product codes, phone numbers.
  • Alphanumeric mode: uppercase A-Z, digits 0-9, and a small set of symbols ($%*+-./: and space). Efficient at 5.5 bits per character. Automatically selected for uppercase URLs.
  • Binary/Byte mode: all 256 ISO-8859-1 characters (Latin-1). Used for lowercase URLs, UTF-8 text, vCards. 8 bits per character. Mixed-case URLs like https://example.com/Page?id=123 use binary mode and take up more space than purely uppercase content.
  • Kanji mode: double-byte characters from the Shift JIS encoding for Japanese text. 13 bits per character, more efficient than binary for Japanese.

Practical tips for maximizing capacity: Shorten URLs with a URL shortener (reduces characters from 80+ to under 25). Use uppercase-only alphanumeric characters in URLs where possible (switches from binary to alphanumeric mode, roughly doubling effective capacity). Remove UTM parameters from QR code URLs and track analytics via server-side redirect instead.

Common Use Cases: URLs, Payments, and Authentication

QR codes are used across dozens of industries. Understanding the specific data format for each use case helps you generate codes that work correctly with standard device apps.

URL / Website links

The most common use case. Simply encode the full URL including the protocol: https://example.com/page?utm_source=qr. Tip: use a URL shortener for long URLs to reduce module density and improve scan reliability at small print sizes.

Payment QR codes

Payment QR codes encode payment data in application-specific formats. Common standards include:

  • EMVCo (ISO 18004): Used by WeChat Pay, Alipay, and most Asian payment systems. Encodes a structured TLV (type-length-value) payload with merchant ID, amount, and currency.
  • Bitcoin / Crypto: Format is bitcoin:ADDRESS?amount=0.001&label=Payment. Most crypto wallets recognize the bitcoin: URI scheme natively.
  • PayPal.me / Stripe: Simply encode the payment URL, e.g. https://paypal.me/username/50USD.
  • UPI (India): Format is upi://pay?pa=VPA&pn=Name&am=Amount&cu=INR, recognized by BHIM, Google Pay, PhonePe.

Two-factor authentication (TOTP)

Authenticator apps (Google Authenticator, Authy, 1Password) use the otpauth:// URI format to configure TOTP secrets via QR code scanning. This is the standard way to set up 2FA for web applications.

// TOTP QR code format (RFC 6238 / Google Authenticator standard)
// otpauth://totp/LABEL?secret=SECRET&issuer=ISSUER&algorithm=SHA1&digits=6&period=30

const totpUri = encodeURI(
  'otpauth://totp/DevToolBox:jane@example.com' +
  '?secret=JBSWY3DPEHPK3PXP' +  // base32-encoded TOTP secret
  '&issuer=DevToolBox' +
  '&algorithm=SHA1' +
  '&digits=6' +
  '&period=30'
);

// Generate QR at level M (level H if adding logo to setup screen)
import QRCode from 'qrcode';
const qrDataUrl = await QRCode.toDataURL(totpUri, {
  errorCorrectionLevel: 'M',
  width: 300,
});

Restaurant menus and event tickets

Dynamic QR codes (redirect-URL codes) are ideal here because the destination can be changed without reprinting. Encode a short redirect URL, track scans per table or per ticket, and update the menu or event details at the redirect destination. For event tickets, QR codes typically encode a unique ticket ID that is validated against a database on scan — the QR code contains the token, not the ticket data itself.

Other common formats

// Email with subject and body pre-filled
mailto:contact@example.com?subject=QR%20Code%20Inquiry&body=Hello%2C

// SMS with pre-filled message
SMSTO:+15551234567:Hello from QR code

// Phone call
tel:+15551234567

// Map location (Google Maps)
https://www.google.com/maps?q=37.7749,-122.4194

// App Store / Play Store link
https://apps.apple.com/app/id123456789
https://play.google.com/store/apps/details?id=com.example.app

// Geo URI (lat/lng — supported by some apps)
geo:37.7749,-122.4194?q=37.7749,-122.4194(DevToolBox+HQ)

QR Code Best Practices and Troubleshooting

Design and printing guidelines

  • Minimum print size: 1.5cm × 1.5cm (about 0.6 inches) for a simple URL at error correction level M. Complex codes with more data need to be larger.
  • Quiet zone: Always maintain at least 4 modules of white space on all four sides. This is where scanning most commonly fails.
  • Contrast: Dark modules on light background. Minimum contrast ratio of 3:1. Never dark-on-dark or light-on-light.
  • Avoid gradients: Gradients applied to QR codes can reduce contrast in some areas, causing scan failures. If using a gradient background, test thoroughly.
  • Resolution: For print, export PNG at minimum 300 DPI at the final print size. A 2cm × 2cm print at 300 DPI requires 236 × 236 pixels minimum.

Common scan failure causes

  • Cropped or insufficient quiet zone (most common)
  • Low contrast between modules and background
  • Overly distorted or skewed code (over 30-40 degrees of perspective angle)
  • Too much data for the physical size — use a URL shortener
  • PNG generated at low resolution and scaled up in layout software
  • Logo covering more than 25-30% of the code at level H
  • Glossy laminate creating glare that washes out module contrast

Testing checklist before deployment

  • Scan with iOS Camera app (native, no third-party app)
  • Scan with Android Camera app (Pixel and Samsung)
  • Scan with a dedicated QR app (QR Scanner, Barcode Scanner)
  • Test at the smallest planned print size
  • Test from the maximum expected scanning distance
  • Test at 45-degree angle to simulate realistic user behavior
  • Verify the decoded URL or data is correct
  • For WiFi codes: verify network join on both iOS and Android

Generate QR Codes Online — Free Tool

Use our free QR Code Generator to instantly create QR codes for URLs, WiFi, vCards, plain text, email, phone, and more. Supports all four error correction levels, custom colors, SVG and PNG download — no sign-up required.

Related tools: Base64 EncoderURL EncoderHash Generator

Frequently Asked Questions

What are the three finder patterns and why are they in three corners only?

Finder patterns are the three 7×7 corner squares that let scanners detect, orient, and decode a QR code from any angle. They are placed in exactly three corners (top-left, top-right, bottom-left) so that the scanner can determine the correct reading orientation. The absence of a finder pattern in the bottom-right corner is the cue that tells the scanner which corner is which.

What error correction level should I use by default?

Use level M (15%) as the default for almost all use cases — it balances capacity with reasonable resilience to minor damage or printing imperfections. Use level H only when embedding a logo. Use level L only when you need maximum data capacity in a constrained space and the code will always be displayed on a clean digital screen.

Why does my QR code not scan on some devices?

The most common causes are: insufficient quiet zone (less than 4 modules of white space on any side), low contrast between dark and light modules, code printed too small for the amount of data it contains, or a scaled-up low-resolution PNG. Start by checking the quiet zone and regenerating the code at a larger pixel size.

Can I change a QR code after printing?

Static QR codes (the kind generated by most free tools) cannot be changed — the data is baked into the module pattern. If you need to change the destination after printing, use a dynamic QR code service that encodes a short redirect URL. You can then update the redirect target at any time without reprinting the physical code.

Is there a license cost to use QR codes?

No. The QR code standard (ISO/IEC 18004) is open and royalty-free. Denso Wave, which invented the technology, holds the patent but has committed to never enforce it. You are free to generate, print, and use QR codes in commercial and personal projects without any licensing fees.

𝕏 Twitterin LinkedIn
บทความนี้มีประโยชน์ไหม?

อัปเดตข่าวสาร

รับเคล็ดลับการพัฒนาและเครื่องมือใหม่ทุกสัปดาห์

ไม่มีสแปม ยกเลิกได้ตลอดเวลา

ลองเครื่องมือที่เกี่ยวข้อง

B→Base64 Encoder

บทความที่เกี่ยวข้อง

QR Code Generator Online — Create Custom QR Codes Free

Complete guide to generating QR codes online. Learn about QR code structure, error correction levels, static vs dynamic codes, WiFi QR codes, and how to generate QR codes programmatically in JavaScript and Python.

ขนาด รูปแบบ และการแก้ไขข้อผิดพลาด QR Code: คู่มือปฏิบัติที่ดี

ทุกอย่างเกี่ยวกับขนาด รูปแบบ และระดับการแก้ไขข้อผิดพลาดของ QR code

Base64 Encoding ในทางปฏิบัติ: 7 การใช้งานจริงที่นักพัฒนาทุกคนควรรู้

ค้นพบ 7 การใช้งานจริงของ Base64 encoding: ฝังรูปภาพ, Kubernetes secrets, JWT tokens และ data URI