This workflow corresponds to n8n.io template #7303 — we link there as the canonical source.
This workflow follows the Facebookgraphapi → 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": "YoV79TLDcH5vXJBQ",
"name": "MetaAds Creative Insights researcher by videointelligence v_1.4",
"tags": [
{
"id": "8ZOxg8cY0fPL8g0s",
"name": "ReadyToUse",
"createdAt": "2025-07-10T04:08:19.089Z",
"updatedAt": "2025-07-10T04:08:19.089Z"
},
{
"id": "tITAFvUSOpVVIBvI",
"name": "MetaAds",
"createdAt": "2025-07-05T02:24:26.705Z",
"updatedAt": "2025-07-05T02:24:26.705Z"
},
{
"id": "3Kr9akgvGQXhCtQJ",
"name": "ForPublishing",
"createdAt": "2025-08-13T13:36:55.022Z",
"updatedAt": "2025-08-13T13:36:55.022Z"
}
],
"nodes": [
{
"id": "2e978712-7f3c-41f9-98ef-5485108d6115",
"name": "Run Daily at 9 AM",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-3232,
80
],
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 9
}
]
}
},
"typeVersion": 1.2
},
{
"id": "68355d2e-dca3-4fd8-822c-62f0448e4a92",
"name": "Get Active Ads",
"type": "n8n-nodes-base.facebookGraphApi",
"position": [
-2784,
80
],
"parameters": {
"edge": "ads",
"node": "={{ $json.campaign_id }}",
"options": {
"queryParameters": {
"parameter": [
{
"name": "fields",
"value": "=id,name,creative{id,object_type,thumbnail_url,image_url,object_story_spec{video_data{video_id,image_url}}}"
}
]
}
},
"graphApiVersion": "v22.0"
},
"credentials": {
"facebookGraphApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "854d454f-a888-4935-9f27-ea58802553c2",
"name": "Is it a Video?",
"type": "n8n-nodes-base.if",
"position": [
-2336,
80
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "4168e3d6-4171-460d-83b5-446736c04f32",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $json.data.creative.object_story_spec.video_data.video_id }}",
"rightValue": "VIDEO"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "23fbf5c4-827a-41f4-8b0b-d2316022ea22",
"name": "Get Video Source URL",
"type": "n8n-nodes-base.facebookGraphApi",
"position": [
-2112,
-112
],
"parameters": {
"node": "={{ $json.data.creative.object_story_spec.video_data.video_id }}",
"options": {
"queryParameters": {
"parameter": [
{
"name": "fields",
"value": "permalink_url,created_time,id,source"
}
]
}
},
"graphApiVersion": "v23.0"
},
"credentials": {
"facebookGraphApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "0042d4c3-8230-4a6e-ad3d-58737470e225",
"name": "Download Video File",
"type": "n8n-nodes-base.httpRequest",
"position": [
-1888,
-112
],
"parameters": {
"url": "={{ $json.source }}",
"options": {
"response": {
"response": {}
}
}
},
"typeVersion": 4.2
},
{
"id": "b747cea5-3573-429b-8f60-8a4753014ffc",
"name": "Set Campaign ID",
"type": "n8n-nodes-base.set",
"position": [
-3008,
80
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "da4b6ef7-7c06-40f7-8e3c-f69871311c7a",
"name": "campaign_id",
"type": "string",
"value": "campaign_id"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "a07e2fba-dbdc-45e5-a8f1-e98583b4c66f",
"name": "Split Out",
"type": "n8n-nodes-base.splitOut",
"position": [
-2560,
80
],
"parameters": {
"include": "allOtherFields",
"options": {},
"fieldToSplitOut": "data"
},
"typeVersion": 1
},
{
"id": "a522ff6d-b853-4508-81d2-6b077deeb4e9",
"name": "Start Video Annotation",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueErrorOutput",
"position": [
-1216,
-176
],
"parameters": {
"url": "https://videointelligence.googleapis.com/v1/videos:annotate",
"method": "POST",
"options": {},
"jsonBody": "={\n \"inputContent\": \"{{ $json.data }}\",\n \"features\": [\n \"LABEL_DETECTION\",\n \"SPEECH_TRANSCRIPTION\",\n \"TEXT_DETECTION\"\n ],\n \"locationId\": \"us-east1\"\n}",
"sendBody": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "googleApi"
},
"credentials": {
"googleApi": {
"name": "<your credential>"
}
},
"typeVersion": 3
},
{
"id": "01e9920b-101c-4363-a733-3f49a406f215",
"name": "If Ready",
"type": "n8n-nodes-base.if",
"position": [
-544,
-272
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "0b5230bd-b5d3-4421-9a9e-e97943c81ab2",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.done }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "ae707d17-a632-4895-9263-6e9263280332",
"name": "Parse data",
"type": "n8n-nodes-base.code",
"position": [
-96,
-320
],
"parameters": {
"jsCode": "// n8n Code node (JavaScript)\n// Mode: Run once for all items\n\nconst inputItems = $input.all();\n\nconst toSeconds = (v) => {\n if (v == null) return null;\n if (typeof v === 'number') return v;\n if (typeof v === 'string' && v.endsWith('s')) return parseFloat(v.slice(0, -1));\n const n = Number(v);\n return Number.isFinite(n) ? n : null;\n};\n\nconst nowUtc = () => new Date().toISOString();\n\nconst rows = [];\n\nfor (const item of inputItems) {\n const j = item.json || {};\n\n // Metadata from the Set node \u2014 keeping the names exactly as specified\n const meta = {\n source: j.source ?? null, // important: do not rename, as this field is needed by the next node\n campaign_id: j.campaign_id ?? null,\n ad_id: j.ad_id ?? null,\n creative_id: j.creative_id ?? null,\n video_id: j.video_id ?? null,\n file_name: j.file_name ?? null,\n image_url: j.image_url ?? null,\n };\n\n // If file_name was not set in the Set node \u2014 try to extract it from the VI response\n const resolvedFileName =\n meta.file_name ??\n (j.response?.annotationResults?.[0]?.inputUri\n ? j.response.annotationResults[0].inputUri.split('/').pop()\n : null) ??\n j.name ??\n 'unknown_file';\n\n const results = j.response?.annotationResults ?? [];\n for (const r of results) {\n // 1) Segment Labels\n for (const ann of (r.segmentLabelAnnotations ?? [])) {\n const cat = (ann.categoryEntities ?? [])\n .map(c => c?.description)\n .filter(Boolean)\n .join('|') || null;\n\n for (const s of (ann.segments ?? [])) {\n rows.push({\n ...meta,\n file_name: resolvedFileName,\n annotation_type: 'SegmentLabel',\n label_or_text: ann.entity?.description ?? null,\n full_transcript: null,\n category: cat,\n confidence: s.confidence ?? null,\n start_time_s: toSeconds(s.segment?.startTimeOffset),\n end_time_s: toSeconds(s.segment?.endTimeOffset),\n language_code: null,\n processed_at_utc: nowUtc(),\n });\n }\n }\n\n // 2) Shot Labels\n for (const ann of (r.shotLabelAnnotations ?? [])) {\n const cat = (ann.categoryEntities ?? [])\n .map(c => c?.description)\n .filter(Boolean)\n .join('|') || null;\n\n for (const s of (ann.segments ?? [])) {\n rows.push({\n ...meta,\n file_name: resolvedFileName,\n annotation_type: 'ShotLabel',\n label_or_text: ann.entity?.description ?? null,\n full_transcript: null,\n category: cat,\n confidence: s.confidence ?? null,\n start_time_s: toSeconds(s.segment?.startTimeOffset),\n end_time_s: toSeconds(s.segment?.endTimeOffset),\n language_code: null,\n processed_at_utc: nowUtc(),\n });\n }\n }\n\n // 3) Text Detection\n for (const t of (r.textAnnotations ?? [])) {\n for (const s of (t.segments ?? [])) {\n rows.push({\n ...meta,\n file_name: resolvedFileName,\n annotation_type: 'TextDetection',\n label_or_text: t.text ?? null,\n full_transcript: null,\n category: null,\n confidence: s.confidence ?? null,\n start_time_s: toSeconds(s.segment?.startTimeOffset),\n end_time_s: toSeconds(s.segment?.endTimeOffset),\n language_code: null,\n processed_at_utc: nowUtc(),\n });\n }\n }\n\n // 4) Speech Transcription (if enabled in VI)\n for (const st of (r.speechTranscriptions ?? [])) {\n for (const alt of (st.alternatives ?? [])) {\n const words = alt.words ?? [];\n const start = words[0]?.startTime ?? null;\n const end = words.length ? words[words.length - 1]?.endTime : null;\n\n rows.push({\n ...meta,\n file_name: resolvedFileName,\n annotation_type: 'SpeechTranscription',\n label_or_text: alt.transcript ?? null,\n full_transcript: alt.transcript ?? null,\n category: null,\n confidence: alt.confidence ?? null,\n start_time_s: toSeconds(start),\n end_time_s: toSeconds(end),\n language_code: st.languageCode ?? null,\n processed_at_utc: nowUtc(),\n });\n }\n }\n }\n}\n\n// Return a batch of items\nreturn rows.map(r => ({ json: r }));"
},
"typeVersion": 2
},
{
"id": "1f26ad56-9337-42c8-aab5-094e33022f74",
"name": "Download Image File",
"type": "n8n-nodes-base.httpRequest",
"position": [
-928,
576
],
"parameters": {
"url": "={{ $json.data.creative.image_url }}",
"options": {
"response": {
"response": {}
}
}
},
"typeVersion": 4.2
},
{
"id": "9d0c3096-2f81-4bf9-a37b-af604d3b4b6e",
"name": "Video to Base64 String",
"type": "n8n-nodes-base.extractFromFile",
"position": [
-1664,
-112
],
"parameters": {
"options": {},
"operation": "binaryToPropery"
},
"typeVersion": 1
},
{
"id": "0ad3c2a7-269f-4f5b-83f5-0fd39aee5bba",
"name": "Image to Base64 String",
"type": "n8n-nodes-base.extractFromFile",
"position": [
-704,
576
],
"parameters": {
"options": {},
"operation": "binaryToPropery"
},
"typeVersion": 1
},
{
"id": "c2d1bb24-2a65-4a80-af67-4e7c1e63716b",
"name": "Start Image Annotation",
"type": "n8n-nodes-base.httpRequest",
"position": [
-480,
576
],
"parameters": {
"url": "https://vision.googleapis.com/v1/images:annotate",
"method": "POST",
"options": {},
"jsonBody": "={\n \"requests\": [\n {\n \"image\": { \"content\": \"{{ $json.data }}\" },\n \"features\": [\n { \"type\": \"LABEL_DETECTION\", \"maxResults\": 50 },\n { \"type\": \"TEXT_DETECTION\", \"maxResults\": 50 },\n { \"type\": \"LOGO_DETECTION\", \"maxResults\": 50 },\n { \"type\": \"LANDMARK_DETECTION\", \"maxResults\": 50 },\n { \"type\": \"OBJECT_LOCALIZATION\", \"maxResults\": 50 },\n { \"type\": \"WEB_DETECTION\", \"maxResults\": 50 },\n { \"type\": \"SAFE_SEARCH_DETECTION\" }\n ]\n }\n ]\n}",
"sendBody": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "googleApi"
},
"credentials": {
"googleApi": {
"name": "<your credential>"
}
},
"typeVersion": 3
},
{
"id": "6ea1b33d-412f-4a0e-80ad-0c269717b167",
"name": "Set id data for Static",
"type": "n8n-nodes-base.set",
"position": [
-256,
576
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "919bc87d-275d-4cbd-bc1e-f16138f7c2f1",
"name": "campaign_id",
"type": "string",
"value": "={{ $('Set Campaign ID').item.json.campaign_id }}"
},
{
"id": "7a59b304-de21-4d19-93b7-086b30033884",
"name": "ad_id",
"type": "string",
"value": "={{ $('Is it a Video?').item.json.data.id }}"
},
{
"id": "9c755ff3-579e-469c-ba4e-77ce81243a41",
"name": "creative_id",
"type": "string",
"value": "={{ $('Is it a Video?').item.json.data.creative.id }}"
},
{
"id": "c5b65d23-521d-48d7-bf9b-b5d4f1387dce",
"name": "file_name",
"type": "string",
"value": "={{ $('Is it a Video?').item.json.data.name }}"
},
{
"id": "60954a83-3c70-40d5-afb5-d79f6948d4a2",
"name": "image_url",
"type": "string",
"value": "={{ $('Download Image File').item.json.data.creative.image_url }}"
}
]
},
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "a72dbc3d-2b86-4380-9ae6-56055412e08e",
"name": "Set id data for Video",
"type": "n8n-nodes-base.set",
"position": [
-320,
-320
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "919bc87d-275d-4cbd-bc1e-f16138f7c2f1",
"name": "campaign_id",
"type": "string",
"value": "={{ $('Set Campaign ID').item.json.campaign_id }}"
},
{
"id": "7a59b304-de21-4d19-93b7-086b30033884",
"name": "ad_id",
"type": "string",
"value": "={{ $('Is it a Video?').item.json.data.id }}"
},
{
"id": "9c755ff3-579e-469c-ba4e-77ce81243a41",
"name": "creative_id",
"type": "string",
"value": "={{ $('Is it a Video?').item.json.data.creative.id }}"
},
{
"id": "b68c42ea-dd28-46ca-8d83-a19fd4633c63",
"name": "video_id",
"type": "string",
"value": "={{ $('Is it a Video?').item.json.data.creative.object_story_spec.video_data.video_id }}"
},
{
"id": "c5b65d23-521d-48d7-bf9b-b5d4f1387dce",
"name": "file_name",
"type": "string",
"value": "={{ $('Is it a Video?').item.json.data.name }}"
},
{
"id": "60954a83-3c70-40d5-afb5-d79f6948d4a2",
"name": "image_url",
"type": "string",
"value": "={{ $('Is it a Video?').item.json.data.creative.object_story_spec.video_data.image_url }}"
},
{
"id": "5706a979-2b07-4546-9a07-deddbee6e343",
"name": "source",
"type": "string",
"value": "={{ $('Get Video Source URL').item.json.source }}"
}
]
},
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "77438f20-64ed-46d2-a467-2a7a9a209fc5",
"name": "Parse data from images",
"type": "n8n-nodes-base.code",
"position": [
-32,
576
],
"parameters": {
"jsCode": "// n8n Code node (JavaScript)\n// Mode: Run once for all items\n\nconst items = $input.all();\nconst nowUtc = () => new Date().toISOString();\n\nconst serializeBBox = (verts=[]) =>\n verts.map(v => `${(v.x ?? 0).toFixed(4)},${(v.y ?? 0).toFixed(4)}`).join('|');\n\nconst rows = [];\n\nfor (const it of items) {\n const j = it.json || {};\n\n // Metadata from the 'Set id data' node (trying to get image_url from several places)\n const resolvedImageUrl =\n j.image_url\n ?? j.data?.creative?.image_url\n ?? j.data?.creative?.thumbnail_url\n ?? null;\n\n const meta = {\n source: j.source ?? null,\n campaign_id: j.campaign_id ?? null,\n ad_id: j.ad_id ?? null,\n creative_id: j.creative_id ?? null,\n video_id: j.video_id ?? null,\n file_name: j.file_name ?? null,\n image_url: resolvedImageUrl,\n };\n\n // Cloud Vision response (supporting different wrappers)\n const resp = j.responses?.[0] || j.response?.responses?.[0] || j.response || {};\n\n // 1) LABELS\n for (const a of (resp.labelAnnotations ?? [])) {\n rows.push({\n ...meta,\n annotation_type: 'Label',\n label_or_text: a.description ?? null,\n full_transcript: null,\n category: null,\n confidence: a.score ?? null,\n start_time_s: null,\n end_time_s: null,\n language_code: null,\n processed_at_utc: nowUtc(),\n });\n }\n\n // 2) LOGOS\n for (const a of (resp.logoAnnotations ?? [])) {\n rows.push({\n ...meta,\n annotation_type: 'Logo',\n label_or_text: a.description ?? null,\n full_transcript: null,\n category: 'logo',\n confidence: a.score ?? null,\n start_time_s: null,\n end_time_s: null,\n language_code: null,\n processed_at_utc: nowUtc(),\n });\n }\n\n // 3) LANDMARKS\n for (const a of (resp.landmarkAnnotations ?? [])) {\n rows.push({\n ...meta,\n annotation_type: 'Landmark',\n label_or_text: a.description ?? null,\n full_transcript: null,\n category: null,\n confidence: a.score ?? null,\n start_time_s: null,\n end_time_s: null,\n language_code: null,\n processed_at_utc: nowUtc(),\n });\n }\n\n // 4) OBJECTS (bbox)\n for (const a of (resp.localizedObjectAnnotations ?? [])) {\n const bbox = serializeBBox(a.boundingPoly?.normalizedVertices ?? []);\n rows.push({\n ...meta,\n annotation_type: 'Object',\n label_or_text: a.name ?? null,\n full_transcript: null,\n category: bbox ? `bbox:${bbox}` : null,\n confidence: a.score ?? null,\n start_time_s: null,\n end_time_s: null,\n language_code: null,\n processed_at_utc: nowUtc(),\n });\n }\n\n // 5) WEB DETECTION\n const web = resp.webDetection || {};\n for (const e of (web.webEntities ?? [])) {\n if (!e.description) continue;\n rows.push({\n ...meta,\n annotation_type: 'WebEntity',\n label_or_text: e.description,\n full_transcript: null,\n category: null,\n confidence: e.score ?? null,\n start_time_s: null,\n end_time_s: null,\n language_code: null,\n processed_at_utc: nowUtc(),\n });\n }\n for (const b of (web.bestGuessLabels ?? [])) {\n rows.push({\n ...meta,\n annotation_type: 'BestGuess',\n label_or_text: b.label ?? null,\n full_transcript: null,\n category: null,\n confidence: null,\n start_time_s: null,\n end_time_s: null,\n language_code: null,\n processed_at_utc: nowUtc(),\n });\n }\n\n // 6) SAFE SEARCH\n if (resp.safeSearchAnnotation) {\n const s = resp.safeSearchAnnotation;\n for (const k of ['adult','medical','violence','spoof','racy']) {\n rows.push({\n ...meta,\n annotation_type: 'SafeSearch',\n label_or_text: `${k}:${s[k] ?? 'UNKNOWN'}`,\n full_transcript: null,\n category: null,\n confidence: null,\n start_time_s: null,\n end_time_s: null,\n language_code: null,\n processed_at_utc: nowUtc(),\n });\n }\n }\n\n // 7) TEXT\n const fta = resp.fullTextAnnotation;\n if (fta?.text) {\n rows.push({\n ...meta,\n annotation_type: 'Text',\n label_or_text: fta.text.slice(0, 1000),\n full_transcript: fta.text,\n category: 'fullText',\n confidence: null,\n start_time_s: null,\n end_time_s: null,\n language_code: null,\n processed_at_utc: nowUtc(),\n });\n } else {\n for (const t of (resp.textAnnotations ?? []).slice(0, 50)) {\n if (!t.description) continue;\n rows.push({\n ...meta,\n annotation_type: 'Text',\n label_or_text: t.description,\n full_transcript: null,\n category: 'snippet',\n confidence: null,\n start_time_s: null,\n end_time_s: null,\n language_code: null,\n processed_at_utc: nowUtc(),\n });\n }\n }\n}\n\nreturn rows.map(r => ({ json: r }));"
},
"typeVersion": 2
},
{
"id": "48761c30-7d32-40ad-855a-5362f12edbf1",
"name": "Has image_url?",
"type": "n8n-nodes-base.if",
"position": [
-1216,
368
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "12beb5b0-5438-4dd3-8161-7c8da1ba31c4",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $json.data.creative.image_url }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "dac450fb-80d6-4d07-b929-5bc132a8dea2",
"name": "Loop for videos",
"type": "n8n-nodes-base.splitInBatches",
"position": [
-1440,
-112
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "6dd566d0-2f05-495f-b1e6-8d9e58a116a6",
"name": "Add errors",
"type": "n8n-nodes-base.googleSheets",
"position": [
-768,
-32
],
"parameters": {
"columns": {
"value": {
"error_type": "={{ $json.error_type }}"
},
"schema": [
{
"id": "error_type",
"type": "string",
"display": true,
"required": false,
"displayName": "error_type",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "error_message",
"type": "string",
"display": true,
"required": false,
"displayName": "error_message",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "campaign_id",
"type": "string",
"display": true,
"required": false,
"displayName": "campaign_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ad_id",
"type": "string",
"display": true,
"required": false,
"displayName": "ad_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "creative_id",
"type": "string",
"display": true,
"required": false,
"displayName": "creative_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "video_id",
"type": "string",
"display": true,
"required": false,
"displayName": "video_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "file_name",
"type": "string",
"display": true,
"required": false,
"displayName": "file_name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "image_url",
"type": "string",
"display": true,
"required": false,
"displayName": "image_url",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "thumbnail_url",
"type": "string",
"display": true,
"required": false,
"displayName": "thumbnail_url",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "source",
"type": "string",
"display": true,
"required": false,
"displayName": "source",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "processed_at_utc",
"type": "string",
"display": true,
"required": false,
"displayName": "processed_at_utc",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "autoMapInputData",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 1828512644,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1XgMMxrnthHhy1jIaxCWNGHLZ50Z5mv4Be1RlwSpGcuA/edit#gid=1828512644",
"cachedResultName": "errors"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1XgMMxrnthHhy1jIaxCWNGHLZ50Z5mv4Be1RlwSpGcuA",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1XgMMxrnthHhy1jIaxCWNGHLZ50Z5mv4Be1RlwSpGcuA/edit?usp=drivesdk",
"cachedResultName": "MetaAds Creative Insights researcher by videointelligence v_1.1"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.6
},
{
"id": "6ed766ae-73a3-4f69-91f2-ca07d2c70e90",
"name": "Check Operation Status",
"type": "n8n-nodes-base.httpRequest",
"position": [
-768,
-352
],
"parameters": {
"url": "=https://videointelligence.googleapis.com/v1/{{ $('Start Video Annotation').item.json.name }}",
"options": {},
"authentication": "predefinedCredentialType",
"nodeCredentialType": "googleApi"
},
"credentials": {
"googleApi": {
"name": "<your credential>"
}
},
"typeVersion": 3
},
{
"id": "f7be8b28-9f68-4d36-bfd6-9d45ba55fd80",
"name": "Add Segments data",
"type": "n8n-nodes-base.googleSheets",
"position": [
128,
-16
],
"parameters": {
"columns": {
"value": {
"ad_id": "={{ $('Set id data for Video').item.json.ad_id }}",
"source": "={{ $('Set id data for Video').item.json.source }}",
"category": "={{ $json.category }}",
"video_id": "={{ $('Set id data for Video').item.json.video_id }}",
"file_name": "={{ $('Set id data for Video').item.json.file_name }}",
"image_url": "={{ $('Set id data for Video').item.json.image_url }}",
"confidence": "={{ $json.confidence }}",
"end_time_s": "={{ $json.end_time_s }}",
"campaign_id": "={{ $('Set id data for Video').item.json.campaign_id }}",
"creative_id": "={{ $('Set id data for Video').item.json.creative_id }}",
"start_time_s": "={{ $json.start_time_s }}",
"label_or_text": "={{ $json.label_or_text }}",
"language_code": "={{ $json.language_code }}",
"annotation_type": "={{ $json.annotation_type }}",
"full_transcript": "={{ $json.full_transcript }}",
"processed_at_utc": "={{ $json.processed_at_utc }}"
},
"schema": [
{
"id": "source",
"type": "string",
"display": true,
"required": false,
"displayName": "source",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "campaign_id",
"type": "string",
"display": true,
"required": false,
"displayName": "campaign_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ad_id",
"type": "string",
"display": true,
"required": false,
"displayName": "ad_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "creative_id",
"type": "string",
"display": true,
"required": false,
"displayName": "creative_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "video_id",
"type": "string",
"display": true,
"required": false,
"displayName": "video_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "file_name",
"type": "string",
"display": true,
"required": false,
"displayName": "file_name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "image_url",
"type": "string",
"display": true,
"required": false,
"displayName": "image_url",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "annotation_type",
"type": "string",
"display": true,
"required": false,
"displayName": "annotation_type",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "label_or_text",
"type": "string",
"display": true,
"required": false,
"displayName": "label_or_text",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "full_transcript",
"type": "string",
"display": true,
"required": false,
"displayName": "full_transcript",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "category",
"type": "string",
"display": true,
"required": false,
"displayName": "category",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "confidence",
"type": "string",
"display": true,
"required": false,
"displayName": "confidence",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "start_time_s",
"type": "string",
"display": true,
"required": false,
"displayName": "start_time_s",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "end_time_s",
"type": "string",
"display": true,
"required": false,
"displayName": "end_time_s",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "language_code",
"type": "string",
"display": true,
"required": false,
"displayName": "language_code",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "processed_at_utc",
"type": "string",
"display": true,
"required": false,
"displayName": "processed_at_utc",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "autoMapInputData",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1XgMMxrnthHhy1jIaxCWNGHLZ50Z5mv4Be1RlwSpGcuA/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1XgMMxrnthHhy1jIaxCWNGHLZ50Z5mv4Be1RlwSpGcuA",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1XgMMxrnthHhy1jIaxCWNGHLZ50Z5mv4Be1RlwSpGcuA/edit?usp=drivesdk",
"cachedResultName": "MetaAds Creative Insights researcher by videointelligence v_1.1"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.6,
"alwaysOutputData": false
},
{
"id": "c6ff4f8e-1a7f-4c23-839a-ec0b640393f0",
"name": "Set (Video Error Row)",
"type": "n8n-nodes-base.set",
"position": [
-992,
-32
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "cc622574-ba7c-4899-922f-1ea566b9d051",
"name": "error_type",
"type": "string",
"value": "VIDEO_ANNOTATION_FAILED"
},
{
"id": "215a5640-66ed-434d-8b71-708dc1171954",
"name": "error_message",
"type": "string",
"value": "{{ $json.error.message }}"
},
{
"id": "e303f282-9880-450f-b9a1-de04a79697ca",
"name": "campaign_id",
"type": "string",
"value": "={{ $('Set Campaign ID').item.json.campaign_id }}"
},
{
"id": "fd549b0b-67ba-4d81-a76a-c9766dfca013",
"name": "ad_id",
"type": "string",
"value": "={{ $json.data.id }}"
},
{
"id": "8a471e1d-bd4a-4a0c-b2de-6f92073b4545",
"name": "creative_id",
"type": "string",
"value": "={{ $json.data.creative.id }}"
},
{
"id": "1bc0c568-015a-4b7b-990b-42ef5613ca7c",
"name": "video_id",
"type": "string",
"value": ""
},
{
"id": "8d28b972-e82a-49c7-ad1a-fe488f30d842",
"name": "file_name",
"type": "string",
"value": "={{ $json.data.name }}"
},
{
"id": "0dd70485-3a48-4713-a132-3af888d56bc7",
"name": "image_url",
"type": "string",
"value": ""
},
{
"id": "7b508e9c-d605-4bb9-924a-8fe97e971818",
"name": "thumbnail_url",
"type": "string",
"value": "={{ $json.data.creative.thumbnail_url }}"
},
{
"id": "ce62f39e-941f-47ab-ab46-ffa162db561a",
"name": "source",
"type": "string",
"value": ""
},
{
"id": "56b517e5-abd3-4870-b6c1-4cbc318eb1bf",
"name": "processed_at_utc",
"type": "string",
"value": "={{ (new Date()).toISOString() }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "83446d6c-4e47-4953-a1d7-fd23086c0979",
"name": "Sticky Note Config",
"type": "n8n-nodes-base.stickyNote",
"position": [
-3040,
-192
],
"parameters": {
"color": 6,
"width": 450,
"height": 280,
"content": "**\u2699\ufe0f 1. Configuration: Campaign ID**\n\nThis is the main configuration node. Specify the Meta Ads Campaign ID you want to analyze.\n\n**How to find the Campaign ID:**\n1. Open Ads Manager.\n2. Select the desired campaign.\n3. In the browser's address bar, find the parameter `act_...&campaign_id=`. The number after the `=` is your ID."
},
"typeVersion": 1
},
{
"id": "12d3042f-5661-40ba-9ab9-e9cbfea54167",
"name": "Sticky Note Split",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2464,
224
],
"parameters": {
"color": 5,
"width": 450,
"height": 250,
"content": "**\ud83d\udd00 2. Branching Logic: Is it a Video or an Image?**\n\nThis node checks the creative type.\n\n- **If the creative contains a video (`video_id` exists):** \n It is sent down the top path for analysis via the Google Video Intelligence API.\n\n- **If it's a static image:**\n It is sent down the bottom path for analysis via the Google Vision API."
},
"typeVersion": 1
},
{
"id": "65252e3f-04ba-42d9-8e0f-041448744ae8",
"name": "Sticky Note Video",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1488,
-496
],
"parameters": {
"color": 4,
"width": 1570,
"height": 380,
"content": "**\ud83c\udf9e\ufe0f 3. Video Analysis**\n\nThis branch handles video processing:\n1. **Get Video Source URL:** Retrieves a direct link to the video file.\n2. **Download & Convert:** Downloads the video and encodes it to Base64 for the API request.\n3. **Start Video Annotation:** Sends the video to the Google Video Intelligence API and initiates an asynchronous analysis task (object, text, and speech recognition).\n4. **Loop & Check:** Periodically checks if the task is complete.\n5. **Parse data:** Parses the JSON response from Google and prepares the rows for the spreadsheet."
},
"typeVersion": 1
},
{
"id": "0e327863-2c8a-4f14-9bc4-cf203746d6a2",
"name": "Sticky Note Image",
"type": "n8n-nodes-base.stickyNote",
"position": [
-960,
736
],
"parameters": {
"color": 6,
"width": 1042,
"height": 328,
"content": "**\ud83d\uddbc\ufe0f 4. Image Analysis**\n\nThis branch handles static creatives:\n1. **Download & Convert:** Downloads the image and encodes it to Base64.\n2. **Start Image Annotation:** Sends the image to the Google Vision API for analysis (object, logo, text detection, etc.).\n3. **Parse data:** Parses the JSON response and prepares the data for the spreadsheet."
},
"typeVersion": 1
},
{
"id": "dfc557ed-974f-450d-ba29-b5a76097f8aa",
"name": "Sticky Note Errors",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1328,
0
],
"parameters": {
"color": 8,
"width": 770,
"height": 330,
"content": "\n\n\n\n**\u26a0\ufe0f 5. Error Handling**\n\nThis workflow is designed to catch errors. If:\n- A static creative is missing an `image_url`.\n- An error occurs during the Google API video analysis.\n\n...the error information will be logged to a separate `errors` sheet in your Google Sheet. This prevents data loss and helps you quickly identify problematic creatives."
},
"typeVersion": 1
},
{
"id": "5b3846c2-8a1b-4aeb-96d5-047bc932a3d4",
"name": "Sticky Note Google Sheets",
"type": "n8n-nodes-base.stickyNote",
"position": [
112,
-240
],
"parameters": {
"color": 7,
"width": 402,
"height": 394,
"content": "**\ud83d\udcbe 6. Write to Google Sheets**\n\nFinal step. All successfully processed data from both branches (video and image) is collected here and appended to the main sheet in your Google Sheet.\n\nMake sure the `Add Segments data` node is configured correctly and connected to your Google account and the target spreadsheet."
},
"typeVersion": 1
},
{
"id": "a1e7723f-7812-433c-bd3f-cf88cc65852d",
"name": "Wait 3s",
"type": "n8n-nodes-base.wait",
"position": [
-320,
64
],
"parameters": {
"amount": 3
},
"typeVersion": 1.1
},
{
"id": "e50f1d57-0fc5-413a-8f4c-88f5f5360834",
"name": "Wait 30s",
"type": "n8n-nodes-base.wait",
"position": [
-992,
-272
],
"parameters": {
"unit": "seconds",
"amount": 30
},
"typeVersion": 1
},
{
"id": "ce8b70bf-e911-4401-abd4-e1a9d97c3c4f",
"name": "Set (Error Row)",
"type": "n8n-nodes-base.set",
"position": [
-944,
256
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "cc622574-ba7c-4899-922f-1ea566b9d051",
"name": "error_type",
"type": "string",
"value": "NO_IMAGE_URL"
},
{
"id": "215a5640-66ed-434d-8b71-708dc1171954",
"name": "error_message",
"type": "string",
"value": "Image URL or video_id not found "
},
{
"id": "e303f282-9880-450f-b9a1-de04a79697ca",
"name": "campaign_id",
"type": "string",
"value": "={{ $('Set Campaign ID').item.json.campaign_id }}"
},
{
"id": "fd549b0b-67ba-4d81-a76a-c9766dfca013",
"name": "ad_id",
"type": "string",
"value": "={{ $json.data.id }}"
},
{
"id": "8a471e1d-bd4a-4a0c-b2de-6f92073b4545",
"name": "creative_id",
"type": "string",
"value": "={{ $json.data.creative.id }}"
},
{
"id": "1bc0c568-015a-4b7b-990b-42ef5613ca7c",
"name": "video_id",
"type": "string",
"value": ""
},
{
"id": "8d28b972-e82a-49c7-ad1a-fe488f30d842",
"name": "file_name",
"type": "string",
"value": "={{ $json.data.name }}"
},
{
"id": "0dd70485-3a48-4713-a132-3af888d56bc7",
"name": "image_url",
"type": "string",
"value": ""
},
{
"id": "7b508e9c-d605-4bb9-924a-8fe97e971818",
"name": "thumbnail_url",
"type": "string",
"value": "={{ $json.data.creative.thumbnail_url }}"
},
{
"id": "ce62f39e-941f-47ab-ab46-ffa162db561a",
"name": "source",
"type": "string",
"value": ""
},
{
"id": "56b517e5-abd3-4870-b6c1-4cbc318eb1bf",
"name": "processed_at_utc",
"type": "string",
"value": "={{ (new Date()).toISOString() }}"
}
]
}
},
"typeVersion": 3.4
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "46c643b2-3e26-4881-99bb-d4d2491d313d",
"connections": {
"Wait 3s": {
"main": [
[
{
"node": "Loop for videos",
"type": "main",
"index": 0
}
]
]
},
"If Ready": {
"main": [
[
{
"node": "Wait 3s",
"type": "main",
"index": 0
},
{
"node": "Set id data for Video",
"type": "main",
"index": 0
}
],
[
{
"node": "Wait 30s",
"type": "main",
"index": 0
}
]
]
},
"Wait 30s": {
"main": [
[
{
"node": "Check Operation Status",
"type": "main",
"index": 0
}
]
]
},
"Split Out": {
"main": [
[
{
"node": "Is it a Video?",
"type": "main",
"index": 0
}
]
]
},
"Parse data": {
"main": [
[
{
"node": "Add Segments data",
"type": "main",
"index": 0
}
]
]
},
"Get Active Ads": {
"main": [
[
{
"node": "Split Out",
"type": "main",
"index": 0
}
]
]
},
"Has image_url?": {
"main": [
[
{
"node": "Download Image File",
"type": "main",
"index": 0
}
],
[
{
"node": "Set (Error Row)",
"type": "main",
"index": 0
}
]
]
},
"Is it a Video?": {
"main": [
[
{
"node": "Get Video Source URL",
"type": "main",
"index": 0
}
],
[
{
"node": "Has image_url?",
"type": "main",
"index": 0
}
]
]
},
"Loop for videos": {
"main": [
[],
[
{
"node": "Start Video Annotation",
"type": "main",
"index": 0
}
]
]
},
"Set (Error Row)": {
"main": [
[
{
"node": "Add errors",
"type": "main",
"index": 0
}
]
]
},
"Set Campaign ID": {
"main": [
[
{
"node": "Get Active Ads",
"type": "main",
"index": 0
}
]
]
},
"Run Daily at 9 AM": {
"main": [
[
{
"node": "Set Campaign ID",
"type": "main",
"index": 0
}
]
]
},
"Download Image File": {
"main": [
[
{
"node": "Image to Base64 String",
"type": "main",
"index": 0
}
]
]
},
"Download Video File": {
"main": [
[
{
"node": "Video to Base64 String",
"type": "main",
"index": 0
}
]
]
},
"Get Video Source URL": {
"main": [
[
{
"node": "Download Video File",
"type": "main",
"index": 0
}
]
]
},
"Set (Video Error Row)": {
"main": [
[
{
"node": "Add errors",
"type": "main",
"index": 0
}
]
]
},
"Set id data for Video": {
"main": [
[
{
"node": "Parse data",
"type": "main",
"index": 0
}
]
]
},
"Check Operation Status": {
"main": [
[
{
"node": "If Ready",
"type": "main",
"index": 0
}
]
]
},
"Image to Base64 String": {
"main": [
[
{
"node": "Start Image Annotation",
"type": "main",
"index": 0
}
]
]
},
"Parse data from images": {
"main": [
[
{
"node": "Add Segments data",
"type": "main",
"index": 0
}
]
]
},
"Set id data for Static": {
"main": [
[
{
"node": "Parse data from images",
"type": "main",
"index": 0
}
]
]
},
"Start Image Annotation": {
"main": [
[
{
"node": "Set id data for Static",
"type": "main",
"index": 0
}
]
]
},
"Start Video Annotation": {
"main": [
[
{
"node": "Wait 30s",
"type": "main",
"index": 0
}
],
[
{
"node": "Set (Video Error Row)",
"type": "main",
"index": 0
}
]
]
},
"Video to Base64 String": {
"main": [
[
{
"node": "Loop for videos",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
facebookGraphApigoogleApigoogleSheetsOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow transforms your Meta Ads creatives into a rich dataset of actionable insights. It's designed for data-driven marketers, performance agencies, and analysts who want to move beyond basic metrics and understand the specific visual and textual elements that drive ad…
Source: https://n8n.io/workflows/7303/ — 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.
I created this workflow with great care to help you simplify your daily reporting routine. If you manage Meta Ads campaigns, you know how time-consuming it can be to open Ads Manager, filter data, and
I built this workflow to remove the daily pain of Meta Ads reporting. If you manage multiple ad accounts, you know how time-consuming it is to open Ads Manager, export campaign data, clean spreadsheet
This workflow monitors Meta Ads and Google Ads campaigns on a daily schedule to detect performance drops. It fetches yesterday’s campaign data, standardizes metrics, and calculates CTR and ROAS agains
Track companies adopting tools that complement yours and send AI-drafted co-marketing outreach emails to new adopters.
This automation is ideal for sales teams, digital marketers, support agents, or small business owners who collect leads in Google Sheets and want to automatically send WhatsApp welcome messages. It's