DEV Community

Pirate Prentice
Pirate Prentice

Posted on

n8n QR Code Node: Generate QR Codes in Your Workflows (Free Workflow JSON)

The n8n QR Code node lets you generate QR codes programmatically inside any workflow — no external API key, no third-party service, no per-scan fee. Drop in a URL, a vCard string, or any plain text and the node outputs a PNG binary you can email, upload to S3, embed in a PDF, or write to disk.

This guide covers every option the node exposes, the gotchas that trip people up, three production-ready patterns, and a free workflow JSON you can import today.


What the QR Code node does

The node has a single operation: Generate. You give it a string and it returns a binary PNG file. That's it — deliberately minimal, zero credentials required, and fast enough to use in real-time webhook flows.

Setting Options Notes
Text Any string (URL, text, vCard…) Expression-supported — reference upstream data
Width Integer (px) Default 200. 300–600 for print; 150 for email thumbnails
Margin Integer (quiet zone) Default 4. QR spec requires ≥ 4; scanners may fail below that
Type png Only PNG is supported
Error Correction Level L / M / Q / H Higher = survives more damage; also makes the QR denser
Output binary property Field name Default data. Change if you're chaining to another binary node

Error correction levels

Level Recovery capacity Use when
L (Low) ~7% Clean digital environments (email, screen)
M (Medium) ~15% Most print use cases — good default
Q (Quartile) ~25% Outdoor signage, slightly dirty surfaces
H (High) ~30% Logos overlaid on the QR, damaged/worn labels

Common gotchas

1. The output is a binary item — not a base64 string
The node writes to the binary property (default data). If a downstream node expects a string URL, use a Code node or $binary.data.data to extract the base64 representation. For most cases (email attachment, S3 upload, Write to Disk) the binary output works directly.

2. Margin below 4 breaks some scanners
The QR specification mandates a quiet zone of at least 4 modules. Aggressive cropping (margin 0–2) causes iOS Camera and many enterprise scanners to fail. Keep margin ≥ 4 unless you're adding your own padding in a downstream image-processing step.

3. Width is the total image width, not the module size
A 200 px image with a 40-character URL will have tiny modules. If you're generating codes destined for print, use 600–1000 px and let the printer scale down — never scale up a small QR code.

4. Very long strings reduce scan reliability
QR codes encode the string literally. A 500-character JSON payload technically fits but produces a dense grid that cheap scanners fail on. For data payloads, encode a short lookup key and resolve on the back-end.

5. Chaining with Convert to File / Move Binary Data
If you rename the binary property or use Move Binary Data, make sure the downstream node references the new property name — not the default data.


Three production patterns

Pattern 1 — Ticket QR code emailer

A customer purchases a ticket via a Stripe webhook. Generate a unique QR code embedding the order ID, attach it to a confirmation email, and upload a copy to Google Drive.

Webhook (Stripe checkout.session.completed)
  → Set node (extract customer email, order ID, event name)
  → QR Code node (text: {{ $json.orderId }}, width: 400, error correction: M)
  → Gmail node (attach $binary.data as ticket-qr.png)
  → Google Drive node (upload binary → /tickets/{{ $json.orderId }}.png)
Enter fullscreen mode Exit fullscreen mode

Free workflow JSON below — swap in your Stripe webhook URL and Gmail credential.

Pattern 2 — Bulk product label generator

A Google Sheets row-per-product feed triggers the workflow. For each product, generate a QR code pointing to https://yoursite.com/products/{SKU}, then write the PNG to a local folder (self-hosted) or upload to S3.

Schedule Trigger (daily 02:00)
  → Google Sheets (read all rows from "Products" sheet)
  → QR Code node (text: https://yoursite.com/products/{{ $json.SKU }}, width: 600, margin: 6)
  → Write Binary File / S3 node (filename: {{ $json.SKU }}.png)
Enter fullscreen mode Exit fullscreen mode

Set error correction to Q or H if labels go on physical packaging — print processes and warehouse environments are rough on quiet zones.

Pattern 3 — vCard QR code for business cards

Accept a webhook POST with contact fields, generate a vCard-formatted QR code, and return it as a binary response. Useful for conference badge printing flows or "share my contact" mini-apps.

Webhook (POST /generate-vcard-qr)
  → Code node (build vCard string from request body)
  → QR Code node (text: {{ $json.vcard }}, width: 500, errorCorrectionLevel: M)
  → Respond to Webhook node (binary response, Content-Type: image/png)
Enter fullscreen mode Exit fullscreen mode

vCard format:

BEGIN:VCARD
VERSION:3.0
FN:Jane Smith
ORG:Acme Corp
TEL:+15550001234
EMAIL:jane@acme.com
URL:https://acme.com
END:VCARD
Enter fullscreen mode Exit fullscreen mode

Free workflow JSON

Import this into n8n (Settings → Import Workflow) to get the ticket QR emailer starter:

{
  "name": "QR Code Ticket Emailer (Starter)",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "qr-ticket",
        "responseMode": "lastNode"
      },
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [240, 300]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            { "name": "orderId", "value": "={{ $json.body.orderId }}", "type": "string" },
            { "name": "customerEmail", "value": "={{ $json.body.email }}", "type": "string" },
            { "name": "eventName", "value": "={{ $json.body.eventName }}", "type": "string" }
          ]
        }
      },
      "name": "Set Fields",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3,
      "position": [460, 300]
    },
    {
      "parameters": {
        "text": "={{ $json.orderId }}",
        "width": 400,
        "margin": 4,
        "errorCorrectionLevel": "M"
      },
      "name": "QR Code",
      "type": "n8n-nodes-base.qrCode",
      "typeVersion": 1,
      "position": [680, 300]
    },
    {
      "parameters": {
        "respondWith": "binary",
        "options": {}
      },
      "name": "Respond to Webhook",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [900, 300]
    }
  ],
  "connections": {
    "Webhook": { "main": [[{ "node": "Set Fields", "type": "main", "index": 0 }]] },
    "Set Fields": { "main": [[{ "node": "QR Code", "type": "main", "index": 0 }]] },
    "QR Code": { "main": [[{ "node": "Respond to Webhook", "type": "main", "index": 0 }]] }
  }
}
Enter fullscreen mode Exit fullscreen mode

Quick reference

Goal Setting
High-resolution print label Width 800+, margin 6, error correction Q
Email thumbnail Width 150–200, margin 4, error correction L
Logo overlay Error correction H (30% recovery)
Outdoor signage Error correction Q or H, width 600+
Real-time webhook response Default settings (fast, small)
Chain to Gmail attachment Output binary property → attach in Gmail node as-is

What to build next

The QR Code node pairs naturally with:

  • Google Sheets — generate codes in bulk from a sheet of SKUs or URLs
  • Respond to Webhook — return a QR PNG in real time from a REST endpoint
  • Gmail / Send Email — embed codes as inline images or attachments
  • Write Binary File — dump codes to a local folder for batch printing (self-hosted)
  • S3 / Google Drive — persist codes for later retrieval

If you want a pre-built workflow that handles the full ticket flow (Stripe → QR → Gmail → Drive), the n8n Workflow Starter Pack includes this pattern and 9 others — grab it for $29.


Questions? Drop them in the comments — what are you generating QR codes for?

Top comments (1)

Collapse
 
pirateprentice profile image
Pirate Prentice

Are you using the QR Code node to generate ticket QR codes, bulk SKU labels, or vCard contacts? Drop your use case below — curious what people are encoding in n8n.