Static QR codes are easy. The hard part is generating a different QR code for every order, ticket, or customer, automatically, without opening a design tool each time.
In this tutorial we will build an n8n workflow that takes incoming data (a name and a link), and produces a finished, on-brand image with a QR code baked right into the design. No manual steps after setup.
We will use Templates On for the design and rendering, and n8n to wire it all together.
What you will need
- An n8n instance (cloud or self-hosted)
- A Templates On account on a paid plan (QR codes are a Pro feature)
- 10 minutes
That is it.
Step 1: Build a template with a QR field
Heads up: QR codes are part of the Pro plan. You can design and save the template on any plan, but rendering an image with a live QR code requires an active paid subscription. If you call the API without it, you will get a
403telling you the feature is not on your plan.
Log in to Templates On and create a new template. Design it however you like, then add a QR code element where you want the code to appear.
The important part: give the QR element a field name. This is the key n8n will send data to. Let’s call ours link.
Do the same for any text you want to be dynamic. We added a text field named name so each image can be personalized.
When you are done, save and publish the template (happens automatically), then copy its Template ID. You will need it in a moment.
(copy from the top right)
or
(find it in My Templates list in the Templates page)
Step 2: Get your API key
Go to your account settings and create an API key. Copy it somewhere safe, we will paste it into n8n next.
Step 3: Set up the trigger in n8n
Open n8n and create a new workflow. Start with whatever trigger fits your use case. A few common ones:
- Webhook if another app should fire this off
- Google Sheets to generate one image per row
- Manual trigger just to test
For this tutorial we will use a simple trigger that gives us a name and a link.
{
"parameters": {},
"name": "When clicking Test",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [240, 300]
}
{
"parameters": {
"assignments": {
"assignments": [
{ "id": "1", "name": "name", "value": "Alex Rivera", "type": "string" },
{ "id": "2", "name": "link", "value": "https://templateson.com/?utm_source=n8n-qr-tutorial", "type": "string" }
]
},
"options": {}
},
"name": "Set Data",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [460, 300]
}
(trigger node feeding name + link into the next step)
Step 4: Call the Templates On API
Add an HTTP Request node. This is the node that turns your data into a finished image.
Configure it like this:
- Method: POST
- URL:
https://templateson.com/api/v1/image - Authentication: Header Auth (or add the header manually)
- Header:
X-API-Keyset to your API key
Then send a JSON body with your template ID and your field values:
{
"template_id": "YOUR_TEMPLATE_ID",
"name": "{{ $json.name }}",
"link": "{{ $json.link }}"
}
Notice that link matches the QR field name from Step 1, and name matches our text field. Templates On reads the link value and turns it into a real QR code inside the design. Whatever URL you send becomes a scannable code.
{
"parameters": {
"method": "POST",
"url": "https://templateson.com/api/v1/image",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{ "name": "X-API-Key", "value": "YOUR_API_KEY" }
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"template_id\": \"YOUR_TEMPLATE_ID\",\n \"name\": \"{{ $json.name }}\",\n \"link\": \"{{ $json.link }}\"\n}",
"options": {}
},
"name": "Render Image",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [680, 300]
}
(HTTP Request node with method, URL, header and JSON body filled in)
Step 5: Get your image back
By default the API returns the raw PNG. If you would rather get a base64 string back as JSON (handy for passing to other nodes), add “format”: “json” to your body:
{
"template_id": "YOUR_TEMPLATE_ID",
"name": "{{ $json.name }}",
"link": "{{ $json.link }}",
"format": "json" // makes it return a base64 string
}
Run the workflow. You should get back a finished image with a working QR code that points to your link.
Step 6: Do something with it
Now connect the result to wherever it needs to go:
- Email it with the Gmail or SMTP node
- Save it to Google Drive or Dropbox
- Post it to Slack or Discord
- Send it back through your webhook response
{
"parameters": {
"resource": "message",
"operation": "post",
"select": "channel",
"text": "New QR image generated for {{ $json.name }}"
},
"name": "Send to Slack",
"type": "n8n-nodes-base.slack",
"typeVersion": 2.2,
"position": [900, 300],
"notesInFlow": true,
"notes": "Swap this for Gmail, Drive, or any output node"
}
[image output branching into slack]
Going further
Because every field is just a value in the request, you can drive this from anything:
- One row in a spreadsheet becomes one ticket
- A new signup becomes a personalized welcome card
- An order becomes a receipt with a QR code to track it
Swap the trigger, keep the rest, and you have an automated pipeline that produces a unique, designed QR image for every record.
Wrapping up
You now have a workflow that takes plain data and returns a finished, branded image with a live QR code, fully automated. The design lives in Templates On, the logic lives in n8n, and you never touch a design tool again after setup.
If you build something with this, I would love to see it.




