This workflow corresponds to n8n.io template #13881 — we link there as the canonical source.
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 →
{
"name": "Generate images from Airtable records with Layerre",
"nodes": [
{
"id": "3e5aa464-ddf2-40e0-8d73-64cf45ba34bf",
"name": "When clicking \"Test\"",
"type": "n8n-nodes-base.manualTrigger",
"position": [
144,
416
],
"parameters": {},
"typeVersion": 1
},
{
"id": "f3f96264-e766-4ebd-888e-52c3e6282f4a",
"name": "Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
-400,
-128
],
"parameters": {
"width": 480,
"height": 820,
"content": "## Airtable \u2192 Layerre \u2192 Airtable\n\nGenerate images from Airtable records (e.g. leads, events, products) and write the rendered image URL back into your base.\n\n### How it works\n1. **Create Template**: One-time \u2013 create a Layerre template from your Canva design (run the Create Template node once, then disable it and set the template ID in the Create Variant node).\n2. **List Airtable records**: Read records from your base and table.\n3. **Create Variant**: For each record, create one image variant; map Airtable fields to your Canva layers.\n4. **Update Airtable**: Write the rendered image URL back to the same record.\n\n### Prerequisites\n- [Layerre account](https://layerre.com) with API key\n- Canva design with the layers you want to customize\n- Airtable base with a table and a column for the output URL\n\n### Customization\n- Map your field names in Create Variant (e.g. `$json.fields.Name`, `$json.fields['Image url']`).\n- In Update, use the record **id** from the List step and the image URL from the variant output (e.g. `$json.url`).\n- Add a Filter or Schedule trigger to run only for new or updated records.\n\n### Resources\n- [Layerre Documentation](https://layerre.com/docs)\n- [Layerre n8n Node](https://github.com/layerre/n8n-nodes-layerre)"
},
"typeVersion": 1
},
{
"id": "a8779b50-cf93-4bc3-b33c-bc50af5a4c8d",
"name": "Step 1 Instructions",
"type": "n8n-nodes-base.stickyNote",
"position": [
448,
112
],
"parameters": {
"color": 7,
"width": 320,
"height": 200,
"content": "## Step 1: Create Template (one-time)\n\nCreate a Layerre template from your Canva design. Run this node once with your Canva URL, then disable it and paste the template ID into the Create Variant node."
},
"typeVersion": 1
},
{
"id": "910d2fdb-0d36-44bc-831e-c892c221e4d3",
"name": "Create Template from Canva",
"type": "n8n-nodes-layerre.layerre",
"disabled": true,
"position": [
576,
416
],
"parameters": {
"canvaUrl": "",
"requestOptions": {}
},
"credentials": {},
"typeVersion": 1
},
{
"id": "a0617442-116e-48da-8d86-18a582c98f0c",
"name": "Step 2 Instructions",
"type": "n8n-nodes-base.stickyNote",
"position": [
912,
-48
],
"parameters": {
"color": 7,
"width": 360,
"height": 380,
"content": "## Step 2: List Airtable records\n\n1. Add Airtable credentials (Personal Access Token).\n2. Select your base and table.\n3. Optionally use **Filter By Formula** to limit records (e.g. only rows where the output URL is empty).\n4. Each record needs an **id**; the Update step uses it to write back to the correct row."
},
"typeVersion": 1
},
{
"id": "1b1bd407-7000-4280-9dfb-c66337db3e9f",
"name": "List Airtable records",
"type": "n8n-nodes-base.airtable",
"position": [
1024,
416
],
"parameters": {
"base": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": ""
},
"table": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": ""
},
"options": {},
"operation": "search"
},
"credentials": {},
"typeVersion": 2
},
{
"id": "7acebddd-7287-49c6-920b-d4db557446d7",
"name": "Step 3 Instructions",
"type": "n8n-nodes-base.stickyNote",
"position": [
1408,
0
],
"parameters": {
"color": 7,
"width": 360,
"height": 300,
"content": "## Step 3: Create Variant per record\n\nSet **Template ID** (from Step 1). Map Airtable fields to your Canva layers using `$json.fields['Field Name']` for field values. Each list item becomes one variant; the record **id** is passed through for the Update step."
},
"typeVersion": 1
},
{
"id": "b2631099-c38d-4a4a-972d-80b23593f4c1",
"name": "Step 4 Instructions",
"type": "n8n-nodes-base.stickyNote",
"position": [
1856,
32
],
"parameters": {
"color": 7,
"width": 376,
"height": 300,
"content": "## Step 4: Update Airtable with image URL\n\nWrite the rendered image URL back to the same record. Use the record **id** from the List step (e.g. `$('List Airtable records').item.json.id`) and the image URL from the variant output (e.g. `$json.url`) so each row is updated correctly."
},
"typeVersion": 1
},
{
"id": "196bbbd6-e1ed-414e-b7e4-687ac72a20c0",
"name": "Update Airtable record",
"type": "n8n-nodes-base.airtable",
"position": [
1968,
416
],
"parameters": {
"base": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": ""
},
"table": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": ""
},
"columns": {
"value": {
"id": "={{ $('List Airtable records').item.json.id }}",
"Generated url": "={{ $json.url }}"
},
"schema": [
{
"id": "id",
"type": "string",
"display": true,
"removed": false,
"readOnly": true,
"required": false,
"displayName": "id",
"defaultMatch": true
},
{
"id": "Generated url",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "Generated url",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"id"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "update"
},
"credentials": {},
"typeVersion": 2
},
{
"id": "87e4be2e-765a-49bf-a8a0-0d6adaa90c8d",
"name": "Create a variant",
"type": "n8n-nodes-layerre.layerre",
"position": [
1520,
416
],
"parameters": {
"resource": "variant",
"overrides": {
"override": [
{
"layerId": "",
"overrideOptions": {
"text": "={{ $json.fields.Name }}"
}
},
{
"layerId": "",
"overrideOptions": {
"imgUrl": "={{ $json.fields['Image url'] }}"
}
}
]
},
"templateId": "",
"requestOptions": {},
"variantDimensions": {}
},
"credentials": {},
"typeVersion": 1
}
],
"connections": {
"Create a variant": {
"main": [
[
{
"node": "Update Airtable record",
"type": "main",
"index": 0
}
]
]
},
"When clicking \"Test\"": {
"main": [
[
{
"node": "Create Template from Canva",
"type": "main",
"index": 0
}
]
]
},
"List Airtable records": {
"main": [
[
{
"node": "Create a variant",
"type": "main",
"index": 0
}
]
]
},
"Create Template from Canva": {
"main": [
[
{
"node": "List Airtable records",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
How it works
Source: https://n8n.io/workflows/13881/ — 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.
Lmchatopenai Workflow. Uses noOp, stickyNote, executeWorkflowTrigger, airtable. Event-driven trigger; 41 nodes.
This n8n workflow retrieves an Airtable record along with its related child records in a hierarchical structure. It can fetch up to 3 levels of linked records and assembles them into a comprehensive J
How it works
This workflow automatically pulls SERP rankings, competitor keywords, and related keyword ideas from DataForSEO and stores structured results in Airtable — making SEO tracking and keyword research str
d16-Web-Scraper-Data-Flow. Uses httpRequest, airtable, executeWorkflowTrigger. Event-driven trigger; 20 nodes.