Google广告活动报告自动生成到Google表格(含Airtable客户管理)
高级
这是一个Miscellaneous, Multimodal AI领域的自动化工作流,包含 31 个节点。主要使用 If, Code, Wait, Switch, Airtable 等节点。 Google广告活动报告自动生成到Google表格(含Airtable客户管理)
前置要求
- •Airtable API Key
- •可能需要目标 API 的认证凭证
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
"meta": {
"instanceId": "393ca9e36a1f81b0f643c72792946a5fe5e49eb4864181ba4032e5a408278263",
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "c4758e73-06d7-4bc0-a6c4-52b6a2b53a9c",
"name": "遍历项目",
"type": "n8n-nodes-base.splitInBatches",
"position": [
992,
64
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "b3664fd2-799c-4478-9455-8d5b71cd7aa0",
"name": "从 Airtable 获取信息",
"type": "n8n-nodes-base.airtable",
"position": [
240,
80
],
"parameters": {
"base": {
"__rl": true,
"mode": "list",
"value": "appk6h4dLarLUXKpR",
"cachedResultUrl": "https://airtable.com/appk6h4dLarLUXKpR",
"cachedResultName": "Base clients"
},
"table": {
"__rl": true,
"mode": "list",
"value": "tblTrvdyaIcsSgOWR",
"cachedResultUrl": "https://airtable.com/appk6h4dLarLUXKpR/tblTrvdyaIcsSgOWR",
"cachedResultName": "Projets"
},
"options": {},
"operation": "search"
},
"credentials": {
"airtableTokenApi": {
"id": "9mTR7mhD0VA7GbZP",
"name": "Airtable Personal Access Token account"
}
},
"typeVersion": 2.1
},
{
"id": "4e919d97-042a-47d8-a547-5a0266e689c1",
"name": "活跃",
"type": "n8n-nodes-base.if",
"position": [
512,
80
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "273b2433-ec4f-4016-bdb1-591e005d65db",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json['Status - Prévisionnel budgétaire'] }}",
"rightValue": "Actif"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "31348885-1dea-42ee-935c-a5c00e134fee",
"name": "电商/潜在客户",
"type": "n8n-nodes-base.switch",
"position": [
1568,
80
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "Ecommerce",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "f1a24e58-8bd1-47c2-bd53-08e8e0f6b150",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json['Typologie ADS'] }}",
"rightValue": "Ecommerce"
}
]
},
"renameOutput": true
},
{
"outputKey": "Lead",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "84e9b31e-50a6-4fe0-a05c-361f4c20bb53",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json['Typologie ADS'] }}",
"rightValue": "Lead"
}
]
},
"renameOutput": true
}
]
},
"options": {}
},
"typeVersion": 3.2
},
{
"id": "8e111aeb-60f6-4447-bb63-0f1e1e628aed",
"name": "查询电商",
"type": "n8n-nodes-base.httpRequest",
"position": [
2176,
0
],
"parameters": {
"url": "= https://googleads.googleapis.com/v21/customers/{{ $json['ID GADS'] }}/googleAds:searchStream",
"method": "POST",
"options": {},
"jsonBody": "{\n \"query\": \"SELECT campaign.advertising_channel_type, metrics.cost_micros, metrics.conversions_value FROM campaign WHERE segments.date DURING LAST_MONTH AND metrics.cost_micros > 0 ORDER BY metrics.cost_micros DESC\"\n}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "developer-token",
"value": "Your cool token"
},
{
"name": "login-customer-id",
"value": "Your cool customer id"
}
]
},
"nodeCredentialType": "googleAdsOAuth2Api"
},
"credentials": {
"googleAdsOAuth2Api": {
"id": "m33VGwzg8HmFr9hC",
"name": "Google Ads account"
}
},
"typeVersion": 4.2,
"alwaysOutputData": true
},
{
"id": "19b0ef3d-97b9-46e7-a9e1-d8ec74b5a6ce",
"name": "查询潜在客户",
"type": "n8n-nodes-base.httpRequest",
"position": [
2176,
144
],
"parameters": {
"url": "=https://googleads.googleapis.com/v21/customers/{{ $json['ID GADS'] }}/googleAds:searchStream",
"method": "POST",
"options": {},
"jsonBody": "{\n \"query\": \"SELECT campaign.advertising_channel_type, metrics.cost_micros, metrics.conversions FROM campaign WHERE segments.date DURING LAST_MONTH AND metrics.cost_micros > 0 ORDER BY metrics.cost_micros DESC\"\n}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "developer-token",
"value": "Your cool token"
},
{
"name": "login-customer-id",
"value": "Your cool customer id"
}
]
},
"nodeCredentialType": "googleAdsOAuth2Api"
},
"credentials": {
"googleAdsOAuth2Api": {
"id": "m33VGwzg8HmFr9hC",
"name": "Google Ads account"
}
},
"typeVersion": 4.2,
"alwaysOutputData": true
},
{
"id": "17dbc8cc-5d4c-4fc6-9716-3d57a33d1ac9",
"name": "电商数据排序",
"type": "n8n-nodes-base.code",
"position": [
2784,
0
],
"parameters": {
"jsCode": "// Fonction pour traiter et grouper les données Google Ads (ECOMMERCE uniquement)\nfunction processGoogleAdsData(inputData) {\n // Vérifier si nous avons la structure attendue: inputData[0].json.results\n if (!inputData || !Array.isArray(inputData) || !inputData[0] || !inputData[0].json || !inputData[0].json.results) {\n console.log(\"Structure non reconnue:\", JSON.stringify(inputData).substring(0, 300));\n return {};\n }\n \n const results = inputData[0].json.results;\n \n // Initialiser tous les types de campagnes avec des valeurs à 0\n const campaignTypes = {\n 'PERFORMANCE_MAX': { cout: 0, conversion: 0 },\n 'SEARCH': { cout: 0, conversion: 0 },\n 'DISPLAY': { cout: 0, conversion: 0 },\n 'VIDEO': { cout: 0, conversion: 0 },\n 'DEMAND_GEN': { cout: 0, conversion: 0 },\n 'SHOPPING': { cout: 0, conversion: 0 }\n };\n \n // Grouper les données par type de campagne\n const groupedData = {};\n \n results.forEach(result => {\n const channelType = result.campaign.advertisingChannelType;\n const costEuros = parseFloat(result.metrics.costMicros) / 1000000;\n const conversionsValue = parseFloat(result.metrics.conversionsValue || 0); // Chercher conversionsValue dans les données\n \n if (!groupedData[channelType]) {\n groupedData[channelType] = {\n totalCost: 0,\n totalConversionsValue: 0\n };\n }\n \n groupedData[channelType].totalCost += costEuros;\n groupedData[channelType].totalConversionsValue += conversionsValue;\n });\n \n // Remplir les données pour chaque type de campagne\n Object.keys(campaignTypes).forEach(type => {\n if (groupedData[type]) {\n campaignTypes[type].cout = Math.round(groupedData[type].totalCost * 100) / 100;\n campaignTypes[type].conversion = Math.round(groupedData[type].totalConversionsValue * 100) / 100; // Valeur en euros\n }\n // Les valeurs restent à 0 si pas de données pour ce type\n });\n \n return campaignTypes;\n}\n\n// Récupérer les données d'entrée\nconst inputData = $input.all();\nconst campaignData = processGoogleAdsData(inputData);\n\n// Retourner les données dans le format demandé\nreturn { \n json: {\n Performance_max: campaignData.PERFORMANCE_MAX,\n Search: campaignData.SEARCH,\n Display: campaignData.DISPLAY,\n Video: campaignData.VIDEO,\n Demand_gen: campaignData.DEMAND_GEN,\n Shopping: campaignData.SHOPPING\n } \n};"
},
"typeVersion": 2
},
{
"id": "b35fc1c9-8242-4b75-bd08-ef6e0eff9018",
"name": "潜在客户数据排序",
"type": "n8n-nodes-base.code",
"position": [
2784,
144
],
"parameters": {
"jsCode": "// Fonction pour traiter et grouper les données Google Ads\nfunction processGoogleAdsData(inputData) {\n // Vérifier si nous avons la structure attendue: inputData[0].json.results\n if (!inputData || !Array.isArray(inputData) || !inputData[0] || !inputData[0].json || !inputData[0].json.results) {\n console.log(\"Structure non reconnue:\", JSON.stringify(inputData).substring(0, 300));\n return {};\n }\n\n const results = inputData[0].json.results;\n \n // Initialiser tous les types de campagnes avec des valeurs à 0\n const campaignTypes = {\n 'PERFORMANCE_MAX': { cout: 0, conversion: 0 },\n 'SEARCH': { cout: 0, conversion: 0 },\n 'DISPLAY': { cout: 0, conversion: 0 },\n 'VIDEO': { cout: 0, conversion: 0 },\n 'DEMAND_GEN': { cout: 0, conversion: 0 },\n 'SHOPPING': { cout: 0, conversion: 0 }\n };\n\n // Grouper les données par type de campagne\n const groupedData = {};\n \n results.forEach(result => {\n const channelType = result.campaign.advertisingChannelType;\n const costEuros = parseFloat(result.metrics.costMicros) / 1000000;\n const conversions = parseFloat(result.metrics.conversions);\n\n if (!groupedData[channelType]) {\n groupedData[channelType] = {\n totalCost: 0,\n totalConversions: 0\n };\n }\n\n groupedData[channelType].totalCost += costEuros;\n groupedData[channelType].totalConversions += conversions;\n });\n\n // Remplir les données pour chaque type de campagne\n Object.keys(campaignTypes).forEach(type => {\n if (groupedData[type]) {\n campaignTypes[type].cout = Math.round(groupedData[type].totalCost * 100) / 100;\n campaignTypes[type].conversion = Math.round(groupedData[type].totalConversions * 100) / 100;\n }\n // Les valeurs restent à 0 si pas de données pour ce type\n });\n\n return campaignTypes;\n}\n\n// Récupérer les données d'entrée\nconst inputData = $input.all();\nconst campaignData = processGoogleAdsData(inputData);\n\n// Retourner les données dans le format demandé\nreturn { \n json: {\n Performance_max: campaignData.PERFORMANCE_MAX,\n Search: campaignData.SEARCH,\n Display: campaignData.DISPLAY,\n Video: campaignData.VIDEO,\n Demand_gen: campaignData.DEMAND_GEN,\n Shopping: campaignData.SHOPPING\n } \n};"
},
"typeVersion": 2
},
{
"id": "e3ca13a8-2d94-46b9-a6d1-43b0896f7c57",
"name": "格式化电商查询",
"type": "n8n-nodes-base.code",
"position": [
3328,
0
],
"parameters": {
"jsCode": "// Fonction pour obtenir la colonne correspondant au mois précédent\nfunction getPreviousMonthColumn() {\n const now = new Date();\n const currentMonth = now.getMonth(); // 0 = Janvier, 1 = Février, etc.\n \n // Calculer le mois précédent\n let previousMonth = currentMonth - 1;\n \n // Si on est en janvier (0), le mois précédent est décembre (11)\n if (previousMonth < 0) {\n previousMonth = 11;\n }\n \n // Mapping des mois vers les colonnes (0-indexed)\n const monthToColumn = {\n 0: 'B', // Janvier\n 1: 'C', // Février\n 2: 'D', // Mars\n 3: 'E', // Avril\n 4: 'F', // Mai\n 5: 'G', // Juin\n 6: 'H', // Juillet\n 7: 'I', // Août\n 8: 'J', // Septembre\n 9: 'K', // Octobre\n 10: 'L', // Novembre\n 11: 'M' // Décembre\n };\n \n return monthToColumn[previousMonth];\n}\n\n// Obtenir la colonne pour le mois précédent\nconst column = getPreviousMonthColumn();\n\n// Récupérer l'URL du spreadsheet depuis le module précédent\nconst spreadsheetUrl = $('Loop Over Items').first().json['Automation budget'];\n\n// Extraire l'ID du spreadsheet depuis l'URL Google Sheets\nfunction extractSpreadsheetId(url) {\n // Format: https://docs.google.com/spreadsheets/d/ID/edit#gid=0\n // ou: https://docs.google.com/spreadsheets/d/ID\n const match = url.match(/\\/spreadsheets\\/d\\/([a-zA-Z0-9-_]+)/);\n return match ? match[1] : null;\n}\n\nconst spreadsheetId = extractSpreadsheetId(spreadsheetUrl);\n\nif (!spreadsheetId) {\n console.log(\"Impossible d'extraire l'ID du spreadsheet depuis:\", spreadsheetUrl);\n}\n\n// Construire l'URL avec la colonne dynamique pour les lignes 2 à 11\nconst range = `${column}2:${column}11`; // CORRIGÉ : F2:F11 pour mai au lieu de F2:F3\nconst url = `https://sheets.googleapis.com/v4/spreadsheets/${spreadsheetId}/values/${range}?valueInputOption=USER_ENTERED`;\n\n// Récupérer les données du nœud précédent (vos données Google Ads)\nconst inputData = $input.first();\n\n// Debug pour voir la structure des données\nconsole.log(\"Structure inputData:\", JSON.stringify(inputData, null, 2));\n\n// Extraire les données selon la structure réelle\nlet performanceMaxCost = 0;\nlet performanceMaxConversions = 0;\nlet demandGenCost = 0;\nlet demandGenConversions = 0;\nlet searchCost = 0;\nlet searchConversions = 0;\nlet videoCost = 0;\nlet videoConversions = 0;\nlet shoppingCost = 0;\nlet shoppingConversions = 0;\n\n// Vérifier différentes structures possibles\nif (inputData && inputData.Performance_max) {\n // Structure directe\n performanceMaxCost = inputData.Performance_max.cout || 0;\n performanceMaxConversions = inputData.Performance_max.conversion || 0;\n demandGenCost = inputData.Demand_gen.cout || 0;\n demandGenConversions = inputData.Demand_gen.conversion || 0;\n searchCost = inputData.Search.cout || 0;\n searchConversions = inputData.Search.conversion || 0;\n videoCost = inputData.Video.cout || 0;\n videoConversions = inputData.Video.conversion || 0;\n shoppingCost = inputData.Shopping?.cout || 0;\n shoppingConversions = inputData.Shopping?.conversion || 0;\n} else if (inputData && inputData.json) {\n // Structure avec json\n performanceMaxCost = inputData.json.Performance_max?.cout || 0;\n performanceMaxConversions = inputData.json.Performance_max?.conversion || 0;\n demandGenCost = inputData.json.Demand_gen?.cout || 0;\n demandGenConversions = inputData.json.Demand_gen?.conversion || 0;\n searchCost = inputData.json.Search?.cout || 0;\n searchConversions = inputData.json.Search?.conversion || 0;\n videoCost = inputData.json.Video?.cout || 0;\n videoConversions = inputData.json.Video?.conversion || 0;\n shoppingCost = inputData.json.Shopping?.cout || 0;\n shoppingConversions = inputData.json.Shopping?.conversion || 0;\n} else {\n console.log(\"Structure des données non reconnue\");\n}\n\n// Construire le body avec toutes les valeurs\nconst bodyData = {\n \"values\": [\n [performanceMaxCost], // Ligne 2 = coût Performance Max\n [performanceMaxConversions], // Ligne 3 = conversions Performance Max\n [demandGenCost], // Ligne 4 = coût Demand Gen\n [demandGenConversions], // Ligne 5 = conversions Demand Gen\n [searchCost], // Ligne 6 = coût Search\n [searchConversions], // Ligne 7 = conversions Search\n [videoCost], // Ligne 8 = coût Video\n [videoConversions], // Ligne 9 = conversions Video\n [shoppingCost], // Ligne 10 = coût Shopping\n [shoppingConversions] // Ligne 11 = conversions Shopping\n ]\n};\n\n// Retourner la configuration pour le nœud HTTP\nreturn {\n json: {\n url: url,\n method: 'PUT',\n body: JSON.stringify(bodyData),\n range: range,\n column: column,\n currentMonth: new Date().toLocaleDateString('fr-FR', { month: 'long' }),\n previousMonth: new Date(new Date().setMonth(new Date().getMonth() - 1)).toLocaleDateString('fr-FR', { month: 'long' })\n }\n};"
},
"typeVersion": 2
},
{
"id": "b128af04-8aca-4870-9354-6c9a5f051911",
"name": "格式化潜在客户查询",
"type": "n8n-nodes-base.code",
"position": [
3328,
144
],
"parameters": {
"jsCode": "// Fonction pour obtenir la colonne correspondant au mois précédent\nfunction getPreviousMonthColumn() {\n const now = new Date();\n const currentMonth = now.getMonth(); // 0 = Janvier, 1 = Février, etc.\n \n // Calculer le mois précédent\n let previousMonth = currentMonth - 1;\n \n // Si on est en janvier (0), le mois précédent est décembre (11)\n if (previousMonth < 0) {\n previousMonth = 11;\n }\n \n // Mapping des mois vers les colonnes (0-indexed)\n const monthToColumn = {\n 0: 'B', // Janvier\n 1: 'C', // Février\n 2: 'D', // Mars\n 3: 'E', // Avril\n 4: 'F', // Mai\n 5: 'G', // Juin\n 6: 'H', // Juillet\n 7: 'I', // Août\n 8: 'J', // Septembre\n 9: 'K', // Octobre\n 10: 'L', // Novembre\n 11: 'M' // Décembre\n };\n \n return monthToColumn[previousMonth];\n}\n\n// Obtenir la colonne pour le mois précédent\nconst column = getPreviousMonthColumn();\n\n// Récupérer l'URL du spreadsheet depuis le module précédent\nconst spreadsheetUrl = $('Loop Over Items').first().json['Automation budget'];\n\n// Extraire l'ID du spreadsheet depuis l'URL Google Sheets\nfunction extractSpreadsheetId(url) {\n // Format: https://docs.google.com/spreadsheets/d/ID/edit#gid=0\n // ou: https://docs.google.com/spreadsheets/d/ID\n const match = url.match(/\\/spreadsheets\\/d\\/([a-zA-Z0-9-_]+)/);\n return match ? match[1] : null;\n}\n\nconst spreadsheetId = extractSpreadsheetId(spreadsheetUrl);\n\nif (!spreadsheetId) {\n console.log(\"Impossible d'extraire l'ID du spreadsheet depuis:\", spreadsheetUrl);\n}\n\n// Construire l'URL avec la colonne dynamique pour les lignes 2 à 11\nconst range = `${column}2:${column}11`; // CORRIGÉ : F2:F11 pour mai au lieu de F2:F3\nconst url = `https://sheets.googleapis.com/v4/spreadsheets/${spreadsheetId}/values/${range}?valueInputOption=USER_ENTERED`;\n\n// Récupérer les données du nœud précédent (vos données Google Ads)\nconst inputData = $input.first();\n\n// Debug pour voir la structure des données\nconsole.log(\"Structure inputData:\", JSON.stringify(inputData, null, 2));\n\n// Extraire les données selon la structure réelle\nlet performanceMaxCost = 0;\nlet performanceMaxConversions = 0;\nlet demandGenCost = 0;\nlet demandGenConversions = 0;\nlet searchCost = 0;\nlet searchConversions = 0;\nlet videoCost = 0;\nlet videoConversions = 0;\nlet shoppingCost = 0;\nlet shoppingConversions = 0;\n\n// Vérifier différentes structures possibles\nif (inputData && inputData.Performance_max) {\n // Structure directe\n performanceMaxCost = inputData.Performance_max.cout || 0;\n performanceMaxConversions = inputData.Performance_max.conversion || 0;\n demandGenCost = inputData.Demand_gen.cout || 0;\n demandGenConversions = inputData.Demand_gen.conversion || 0;\n searchCost = inputData.Search.cout || 0;\n searchConversions = inputData.Search.conversion || 0;\n videoCost = inputData.Video.cout || 0;\n videoConversions = inputData.Video.conversion || 0;\n shoppingCost = inputData.Shopping?.cout || 0;\n shoppingConversions = inputData.Shopping?.conversion || 0;\n} else if (inputData && inputData.json) {\n // Structure avec json\n performanceMaxCost = inputData.json.Performance_max?.cout || 0;\n performanceMaxConversions = inputData.json.Performance_max?.conversion || 0;\n demandGenCost = inputData.json.Demand_gen?.cout || 0;\n demandGenConversions = inputData.json.Demand_gen?.conversion || 0;\n searchCost = inputData.json.Search?.cout || 0;\n searchConversions = inputData.json.Search?.conversion || 0;\n videoCost = inputData.json.Video?.cout || 0;\n videoConversions = inputData.json.Video?.conversion || 0;\n shoppingCost = inputData.json.Shopping?.cout || 0;\n shoppingConversions = inputData.json.Shopping?.conversion || 0;\n} else {\n console.log(\"Structure des données non reconnue\");\n}\n\n// Construire le body avec toutes les valeurs\nconst bodyData = {\n \"values\": [\n [performanceMaxCost], // Ligne 2 = coût Performance Max\n [performanceMaxConversions], // Ligne 3 = conversions Performance Max\n [demandGenCost], // Ligne 4 = coût Demand Gen\n [demandGenConversions], // Ligne 5 = conversions Demand Gen\n [searchCost], // Ligne 6 = coût Search\n [searchConversions], // Ligne 7 = conversions Search\n [videoCost], // Ligne 8 = coût Video\n [videoConversions], // Ligne 9 = conversions Video\n [shoppingCost], // Ligne 10 = coût Shopping\n [shoppingConversions] // Ligne 11 = conversions Shopping\n ]\n};\n\n// Retourner la configuration pour le nœud HTTP\nreturn {\n json: {\n url: url,\n method: 'PUT',\n body: JSON.stringify(bodyData),\n range: range,\n column: column,\n currentMonth: new Date().toLocaleDateString('fr-FR', { month: 'long' }),\n previousMonth: new Date(new Date().setMonth(new Date().getMonth() - 1)).toLocaleDateString('fr-FR', { month: 'long' })\n }\n};"
},
"typeVersion": 2
},
{
"id": "cf4d7432-ad0e-4723-8d2a-f16ff06ad930",
"name": "填充电商数据",
"type": "n8n-nodes-base.httpRequest",
"maxTries": 5,
"position": [
3856,
0
],
"parameters": {
"url": "={{ $json.url }}",
"method": "PUT",
"options": {},
"jsonBody": "={{ $json.body }}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"nodeCredentialType": "googleSheetsOAuth2Api"
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "wBRLUCktxqXE6DVJ",
"name": "Google Sheets account"
}
},
"retryOnFail": true,
"typeVersion": 4.2,
"waitBetweenTries": 5000
},
{
"id": "1442efc1-a364-4db8-8093-a666dbea53b3",
"name": "填充潜在客户数据",
"type": "n8n-nodes-base.httpRequest",
"maxTries": 5,
"position": [
3856,
144
],
"parameters": {
"url": "={{ $json.url }}",
"method": "PUT",
"options": {},
"jsonBody": "={{ $json.body }}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"nodeCredentialType": "googleSheetsOAuth2Api"
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "wBRLUCktxqXE6DVJ",
"name": "Google Sheets account"
}
},
"retryOnFail": true,
"typeVersion": 4.2,
"waitBetweenTries": 5000
},
{
"id": "774d718e-621e-4e7f-888f-e00568bd165a",
"name": "等待",
"type": "n8n-nodes-base.wait",
"position": [
4080,
0
],
"webhookId": "bd560ce5-7949-451a-86d5-94609aea5368",
"parameters": {
"unit": "minutes",
"amount": 1
},
"typeVersion": 1.1
},
{
"id": "826b1370-83e8-40ae-b575-8f0df2392b8b",
"name": "等待1",
"type": "n8n-nodes-base.wait",
"position": [
4080,
144
],
"webhookId": "b8153fc1-ce55-40c5-a0cb-14ace51e0e48",
"parameters": {
"unit": "minutes",
"amount": 1
},
"typeVersion": 1.1
},
{
"id": "1fb19d74-b1f5-4315-8ed5-7e4219cf5000",
"name": "便签 1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-432,
-48
],
"parameters": {
"width": 544,
"height": 288,
"content": "# 阶段 1:月度计划激活"
},
"typeVersion": 1
},
{
"id": "51823372-7977-40e8-8324-579e1cd660b3",
"name": "每月 10 号",
"type": "n8n-nodes-base.scheduleTrigger",
"notes": "10 du mois",
"position": [
-176,
80
],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 10 3 * *"
}
]
}
},
"notesInFlow": true,
"typeVersion": 1.2
},
{
"id": "1d08c787-1165-4281-b8ba-b985479fc310",
"name": "便签 3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-432,
288
],
"parameters": {
"width": 544,
"height": 288,
"content": "### 系统功能:"
},
"typeVersion": 1
},
{
"id": "d29504a1-5ef4-4dfd-8c67-4ac9be4710a0",
"name": "便签 4",
"type": "n8n-nodes-base.stickyNote",
"position": [
160,
-48
],
"parameters": {
"color": 2,
"width": 544,
"height": 288,
"content": "# 阶段 2:客户数据库检索与筛选"
},
"typeVersion": 1
},
{
"id": "c8d9c354-25d5-4e4e-a485-d81c347c36ed",
"name": "便签 5",
"type": "n8n-nodes-base.stickyNote",
"position": [
160,
288
],
"parameters": {
"color": 2,
"width": 544,
"height": 496,
"content": "### 您需要做的:"
},
"typeVersion": 1
},
{
"id": "5f21ead0-6816-4bef-82b7-3ef551a03ab7",
"name": "便签6",
"type": "n8n-nodes-base.stickyNote",
"position": [
752,
-48
],
"parameters": {
"color": 3,
"width": 544,
"height": 288,
"content": "# 阶段 3:顺序账户处理"
},
"typeVersion": 1
},
{
"id": "22019478-e669-4151-8db3-9cf2aa40c30b",
"name": "便签7",
"type": "n8n-nodes-base.stickyNote",
"position": [
752,
288
],
"parameters": {
"color": 3,
"width": 544,
"height": 272,
"content": "### 系统功能:"
},
"typeVersion": 1
},
{
"id": "89441ce2-fa24-4524-b66e-41e80184d850",
"name": "便签8",
"type": "n8n-nodes-base.stickyNote",
"position": [
1344,
-48
],
"parameters": {
"color": 4,
"width": 544,
"height": 288,
"content": "# 阶段 4:广告系列类型分类与数据提取"
},
"typeVersion": 1
},
{
"id": "00341c81-6a1c-42ce-aa63-8bdc4f8899ef",
"name": "便签9",
"type": "n8n-nodes-base.stickyNote",
"position": [
1344,
288
],
"parameters": {
"color": 4,
"width": 544,
"height": 496,
"content": "### 系统功能:"
},
"typeVersion": 1
},
{
"id": "322980fc-5181-401e-aefd-14a1a8053719",
"name": "便签 10",
"type": "n8n-nodes-base.stickyNote",
"position": [
1936,
-128
],
"parameters": {
"color": 5,
"width": 544,
"height": 432,
"content": "# 阶段 5:Google Ads API 数据检索"
},
"typeVersion": 1
},
{
"id": "83bed6d5-39a0-4dc4-bba1-7cab6534152a",
"name": "便签11",
"type": "n8n-nodes-base.stickyNote",
"position": [
1936,
352
],
"parameters": {
"color": 5,
"width": 544,
"height": 464,
"content": "### 系统功能:"
},
"typeVersion": 1
},
{
"id": "79b2649e-1feb-42ad-ac51-d09544e9fa12",
"name": "便签 12",
"type": "n8n-nodes-base.stickyNote",
"position": [
2528,
-128
],
"parameters": {
"color": 6,
"width": 544,
"height": 432,
"content": "# 阶段 6:数据处理与广告系列聚合"
},
"typeVersion": 1
},
{
"id": "6166bbce-8850-41e6-ab80-5917502ec881",
"name": "便签 13",
"type": "n8n-nodes-base.stickyNote",
"position": [
2528,
352
],
"parameters": {
"color": 6,
"width": 544,
"height": 464,
"content": "### 系统功能:"
},
"typeVersion": 1
},
{
"id": "77ef6875-b3cc-4c20-9ce9-0daa90726fe7",
"name": "便签14",
"type": "n8n-nodes-base.stickyNote",
"position": [
3120,
-128
],
"parameters": {
"color": 7,
"width": 544,
"height": 432,
"content": "# 阶段 7:动态电子表格集成设置"
},
"typeVersion": 1
},
{
"id": "a7360df4-4481-4590-8a9d-f13f0dbe453d",
"name": "便签15",
"type": "n8n-nodes-base.stickyNote",
"position": [
3120,
352
],
"parameters": {
"color": 7,
"width": 544,
"height": 464,
"content": "### 系统功能:"
},
"typeVersion": 1
},
{
"id": "11b83dcf-f6f9-452c-8642-64534baffd71",
"name": "便签 16",
"type": "n8n-nodes-base.stickyNote",
"position": [
3696,
-128
],
"parameters": {
"width": 544,
"height": 432,
"content": "# 阶段 8:自动化电子表格更新与速率限制"
},
"typeVersion": 1
},
{
"id": "ea4f4d08-b487-46f7-affc-d7e7d51f459b",
"name": "便签 17",
"type": "n8n-nodes-base.stickyNote",
"position": [
3696,
352
],
"parameters": {
"width": 544,
"height": 512,
"content": "### 系统功能:"
},
"typeVersion": 1
}
],
"pinData": {},
"connections": {
"Wait": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Actif": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Wait1": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"10 du mois": {
"main": [
[
{
"node": "Récupération info airtable",
"type": "main",
"index": 0
}
]
]
},
"Query Lead": {
"main": [
[
{
"node": "Tri données lead",
"type": "main",
"index": 0
}
]
]
},
"Ecommerce/Lead": {
"main": [
[
{
"node": "Query Ecommerce",
"type": "main",
"index": 0
}
],
[
{
"node": "Query Lead",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Items": {
"main": [
[],
[
{
"node": "Ecommerce/Lead",
"type": "main",
"index": 0
}
]
]
},
"Query Ecommerce": {
"main": [
[
{
"node": "Tri données ecommerce",
"type": "main",
"index": 0
}
]
]
},
"Remplissage lead": {
"main": [
[
{
"node": "Wait1",
"type": "main",
"index": 0
}
]
]
},
"Tri données lead": {
"main": [
[
{
"node": "Formatage requete lead",
"type": "main",
"index": 0
}
]
]
},
"Remplissage ecommerce": {
"main": [
[
{
"node": "Wait",
"type": "main",
"index": 0
}
]
]
},
"Formatage requete lead": {
"main": [
[
{
"node": "Remplissage lead",
"type": "main",
"index": 0
}
]
]
},
"Tri données ecommerce": {
"main": [
[
{
"node": "Formatage requete ecommerce",
"type": "main",
"index": 0
}
]
]
},
"Formatage requete ecommerce": {
"main": [
[
{
"node": "Remplissage ecommerce",
"type": "main",
"index": 0
}
]
]
},
"Récupération info airtable": {
"main": [
[
{
"node": "Actif",
"type": "main",
"index": 0
}
]
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
高级 - 杂项, 多模态 AI
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
使用Motion和Airtable自动编辑任务跟踪与通知
使用Motion和Airtable自动编辑任务跟踪与通知
If
Code
Gmail
+6
12 节点Growth AI
项目管理
每日 WhatsApp 群组智能分析:GPT-4.1 分析与语音消息转录
每日 WhatsApp 群组智能分析:GPT-4.1 分析与语音消息转录
If
Set
Code
+20
52 节点Daniel Lianes
杂项
使用 BOAMP API 和 Google Sheets 监控并筛选法国采购招标
使用 BOAMP API 和 Google Sheets 监控并筛选法国采购招标
If
Code
Wait
+7
55 节点Growth AI
内容创作
使用Gemini AI视觉分析与Telegram警报监控X平台品牌提及
使用Gemini AI视觉分析与Telegram警报监控X平台品牌提及
If
Set
Code
+13
24 节点Atta
杂项
使用Airtable、OpenAI和Unipile的自动化LinkedIn潜在客户生成与私信触达
使用Airtable、OpenAI和Unipile的自动化LinkedIn潜在客户生成与私信触达
If
Set
Code
+15
143 节点Ruben AI
客户培育
使用Apify监控Reddit、Instagram和TikTok社交媒体趋势
使用Apify监控Reddit、Instagram和TikTok社交媒体趋势
Code
Wait
Gmail
+3
30 节点Growth AI
杂项