This workflow corresponds to n8n.io template #13363 — we link there as the canonical source.
This workflow follows the Google Drive → Google Sheets recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "1l9SEOqC8LDKXgAM",
"name": "Generate and validate QR codes in bulk with Google Sheets and Google Drive",
"tags": [],
"nodes": [
{
"id": "adfa1fec-69d0-499d-a544-039ff540748a",
"name": "When clicking \u2018Execute workflow\u2019",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-1632,
136
],
"parameters": {},
"typeVersion": 1
},
{
"id": "fa465b9d-f404-4ece-8dbf-3eb736354aca",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1408,
560
],
"parameters": {
"color": 7,
"width": 360,
"height": 220,
"content": "Validate whether the scanned QR code is valid"
},
"typeVersion": 1
},
{
"id": "a80a4648-0e59-4728-82c7-ffeec8106288",
"name": "Not used?",
"type": "n8n-nodes-base.if",
"position": [
-720,
512
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "50546d87-ab37-4c8a-b835-e1a60f3aa0dc",
"operator": {
"type": "string",
"operation": "empty",
"singleValue": true
},
"leftValue": "={{ $json['status_qr'] }}",
"rightValue": ""
},
{
"id": "025a42b8-fb90-44a8-951a-0e321b42c3b9",
"operator": {
"type": "number",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $json.row_number }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "1741c140-8470-4a84-bced-1710f2a11b2a",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-960,
464
],
"parameters": {
"color": 7,
"width": 360,
"height": 220,
"content": "Check if ID is valid"
},
"typeVersion": 1
},
{
"id": "e7b9c024-bcb9-488c-a034-b3bf04546f35",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-544,
368
],
"parameters": {
"color": 7,
"width": 420,
"height": 220,
"content": "Update the QR status after it has been used"
},
"typeVersion": 1
},
{
"id": "8ad38195-9077-420e-b724-f18bc8e5c04d",
"name": "Upload file",
"type": "n8n-nodes-base.googleDrive",
"position": [
-512,
64
],
"parameters": {
"name": "={{ $('Loop Over Items').item.json.email }}",
"driveId": {
"__rl": true,
"mode": "list",
"value": "My Drive"
},
"options": {},
"folderId": {
"__rl": true,
"mode": "list",
"value": ""
}
},
"typeVersion": 3
},
{
"id": "9a2a2d6c-b69f-4693-bc32-e65617391bed",
"name": "Loop Over Items",
"type": "n8n-nodes-base.splitInBatches",
"position": [
-992,
48
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "23096106-7fe7-478e-8ded-9115a3a9bbf0",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1428,
76
],
"parameters": {
"color": 7,
"width": 360,
"height": 220,
"content": "Check whether a QR code has already been generated for this ID"
},
"typeVersion": 1
},
{
"id": "ee444bab-8a5c-4aea-a11c-771f984af2b7",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
-834,
4
],
"parameters": {
"color": 7,
"width": 516,
"height": 220,
"content": "Generate a QR code using the webhook validation URL and the unique ID"
},
"typeVersion": 1
},
{
"id": "35a79222-3544-4fb7-bcb6-fa80dd2cf450",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-288,
0
],
"parameters": {
"color": 7,
"width": 424,
"height": 220,
"content": "Update the status of the ID in Google Sheets"
},
"typeVersion": 1
},
{
"id": "4a979c76-2e9d-4fc6-a649-63c22b4139e3",
"name": "Not Valid",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
-944,
704
],
"parameters": {
"options": {
"responseCode": 200
},
"respondWith": "text",
"responseBody": "QR not valid"
},
"typeVersion": 1.1
},
{
"id": "b4bdf87c-a33c-4966-b10f-e1652d1a46fc",
"name": "QR Generator",
"type": "n8n-nodes-base.httpRequest",
"position": [
-736,
64
],
"parameters": {
"url": "=https://api.qrserver.com/v1/create-qr-code/?size=300x300&data={{ $env.WEBHOOK_URL }}/webhook/read-qr?id={{$json.email}}",
"options": {}
},
"typeVersion": 4.2
},
{
"id": "480aa947-8531-4087-92a7-83cef2f04658",
"name": "Update QR used",
"type": "n8n-nodes-base.googleSheets",
"position": [
-496,
416
],
"parameters": {
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": "list_user"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": ""
}
},
"typeVersion": 4.5
},
{
"id": "77d384fa-6330-4f71-a25f-b649e4ef2b81",
"name": "QR ID Already Used",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
-496,
608
],
"parameters": {
"options": {
"responseCode": 200
},
"respondWith": "text",
"responseBody": "QR ID Already Used"
},
"typeVersion": 1.1
},
{
"id": "01bf254f-ab08-4b90-94c0-707f27a0a459",
"name": "QR OK",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
-272,
416
],
"parameters": {
"options": {},
"respondWith": "text",
"responseBody": "QR Valid!"
},
"typeVersion": 1.1
},
{
"id": "ec24abba-fc81-4c35-bcbe-2286dc554566",
"name": "Get List",
"type": "n8n-nodes-base.googleSheets",
"position": [
-1408,
136
],
"parameters": {
"sheetName": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": ""
},
"documentId": {
"__rl": true,
"mode": "list",
"value": ""
}
},
"typeVersion": 4.7
},
{
"id": "7e4479a7-47a7-4f19-9d37-601e82d68893",
"name": "Get List ID",
"type": "n8n-nodes-base.googleSheets",
"position": [
-944,
512
],
"parameters": {
"sheetName": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": "list_user"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": ""
}
},
"typeVersion": 4.5
},
{
"id": "7059f2ea-1106-46b7-930a-b26a0a8a55e6",
"name": "Check is generated?",
"type": "n8n-nodes-base.if",
"position": [
-1184,
136
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "5a81e1a4-e6c9-4b00-b5d7-46021dffa930",
"operator": {
"type": "string",
"operation": "notEquals"
},
"leftValue": "={{ $json.status_qr }}",
"rightValue": "QR_GENERATED"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "4b9f83f3-673c-463c-9f39-4a8c87ceecbd",
"name": "Update Row Status QR Generated",
"type": "n8n-nodes-base.googleSheets",
"position": [
-32,
64
],
"parameters": {
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": "list_user"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": ""
}
},
"typeVersion": 4.7
},
{
"id": "7941fec2-ad64-44aa-92d6-b11286913eae",
"name": "Check ID Exists",
"type": "n8n-nodes-base.if",
"position": [
-1168,
608
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "430aee2d-a788-4d7c-ab64-880c900f0058",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $json.id }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "f3806868-fc58-4ef1-b43b-2eb126dd12a1",
"name": "QR Validation Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
-1616,
608
],
"parameters": {
"path": "read-qr",
"options": {},
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "faa5b030-7b26-4af8-a367-4fdfa5f1c4b5",
"name": "Extract ID from Webhook",
"type": "n8n-nodes-base.set",
"position": [
-1392,
608
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "4e9a4330-d654-410f-9b99-aa57545c2c80",
"name": "id",
"type": "string",
"value": "={{ $json.query.id }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "64a9eed4-b306-4def-9367-a6bd3292f6a2",
"name": "Prepare Status Update",
"type": "n8n-nodes-base.set",
"position": [
-256,
64
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "373e8180-bad8-49cc-a060-1e4a1c055384",
"name": "id",
"type": "string",
"value": "={{ $('Loop Over Items').item.json.email }}"
},
{
"id": "6c7206e9-500e-46ce-bf3f-fb062b59b293",
"name": "status",
"type": "string",
"value": "QR_GENERATED"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "9d5e4d7a-c3e5-4c7c-9afd-6bbbf50147e7",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2288,
-80
],
"parameters": {
"width": 576,
"height": 944,
"content": "## Generate and validate QR codes in bulk with Google Sheets and Google Drive\nThis workflow allows you to generate QR codes (Barcodes) in bulk from a Google Sheets file and store the generated QR images automatically in Google Drive. Each QR code contains a unique identifier (in this template, an email address) and is connected to a validation webhook.\n\nThe workflow is designed to be modular, easy to customize, and suitable for real-world implementation.\n\n\n## How it works\nThe workflow has two parts:\n\n### 1. QR Generation\n- Reads rows from Google Sheets\n- Checks whether a QR code has already been generated\n- Creates a QR code using a webhook validation URL\n- Uploads the QR image to Google Drive\n- Updates the status column to \"QR_GENERATED\"\n\n### 2. QR Validation\n- Triggered when a QR code is scanned\n- Extracts the ID from the URL\n- Verifies whether the ID exists\n- Checks whether it has already been used\n- Updates the status to \"QR_USED\"\n- Returns a validation response\n\n## Setup steps\n1. Connect your Google Sheets and Google Drive credentials.\n2. Select your spreadsheet and target Drive folder. Ensure your sheet contains email & status_qr columns.\n3. Replace the webhook base URL in the QR generator node with your production URL.\n4. Activate the workflow.\n\n### Need Help?\nContact me on [LinkedIn](https://www.linkedin.com/in/dwicahyas/)!\n"
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "b5d92c50-cfba-4c5a-966e-0d0cf395b7b4",
"connections": {
"Get List": {
"main": [
[
{
"node": "Check is generated?",
"type": "main",
"index": 0
}
]
]
},
"Not used?": {
"main": [
[
{
"node": "Update QR used",
"type": "main",
"index": 0
}
],
[
{
"node": "QR ID Already Used",
"type": "main",
"index": 0
}
]
]
},
"Get List ID": {
"main": [
[
{
"node": "Not used?",
"type": "main",
"index": 0
}
]
]
},
"Upload file": {
"main": [
[
{
"node": "Prepare Status Update",
"type": "main",
"index": 0
}
]
]
},
"QR Generator": {
"main": [
[
{
"node": "Upload file",
"type": "main",
"index": 0
}
]
]
},
"Update QR used": {
"main": [
[
{
"node": "QR OK",
"type": "main",
"index": 0
}
]
]
},
"Check ID Exists": {
"main": [
[
{
"node": "Get List ID",
"type": "main",
"index": 0
}
],
[
{
"node": "Not Valid",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Items": {
"main": [
[],
[
{
"node": "QR Generator",
"type": "main",
"index": 0
}
]
]
},
"Check is generated?": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Prepare Status Update": {
"main": [
[
{
"node": "Update Row Status QR Generated",
"type": "main",
"index": 0
}
]
]
},
"QR Validation Webhook": {
"main": [
[
{
"node": "Extract ID from Webhook",
"type": "main",
"index": 0
}
]
]
},
"Extract ID from Webhook": {
"main": [
[
{
"node": "Check ID Exists",
"type": "main",
"index": 0
}
]
]
},
"Update Row Status QR Generated": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"When clicking \u2018Execute workflow\u2019": {
"main": [
[
{
"node": "Get List",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow allows you to generate QR codes (Barcodes) in bulk from a Google Sheets file and store the generated QR images automatically in Google Drive. Each QR code contains a unique identifier (in this template, an email address) and is connected to a validation webhook.
Source: https://n8n.io/workflows/13363/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This n8n workflow fetches URLs from an RSS feed, checks which URLs have a valid RSS feed and if true, fetches the latest articles from those URLs. It then stores the article details, including the art
Automatically extracts all page URLs from website sitemaps, filters out unwanted sitemap links, and saves clean URLs to Google Sheets for SEO analysis and reporting.
Workflow Description Automate your candidate interview pipeline with precision. This powerful integration pulls booking data from Cal.com, extracts interview details (name, email, date & time), and sy
Validate and enrich phone numbers from Google Sheets using the [](https://rapidapi.com/skdeveloper/api/phone-number-validator11) API.
How it Works