🛍️ Optimisation du flux Google Shopping en utilisant Channable, Relevance AI et Merchant API
Ceci est unContent Creation, Multimodal AIworkflow d'automatisation du domainecontenant 19 nœuds.Utilise principalement des nœuds comme If, Code, Slack, Aggregate, ItemLists. 🛍️ Optimisation du flux Google Shopping avec Channable, Relevance AI et Merchant API
- •Token Bot Slack ou URL Webhook
- •Peut nécessiter les informations d'identification d'authentification de l'API cible
Nœuds utilisés (19)
Catégorie
{
"meta": {
"instanceId": "04fd795d32aabb18b913b4a3350b5cd0e9313a422ea0e7bdac0da2fb76cac9f7",
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "34eafce0-026c-416e-99b8-fd6d012d758f",
"name": "Déclencheur quotidien - 6h",
"type": "n8n-nodes-base.scheduleTrigger",
"notes": "Triggers daily at 6 AM for feed optimization before Merchant Center sync",
"position": [
-4200,
460
],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 6 * * *"
}
]
}
},
"typeVersion": 1
},
{
"id": "698d4143-e209-4c81-94ce-01094c4b1f14",
"name": "Obtenir le flux produits",
"type": "n8n-nodes-base.httpRequest",
"notes": "Retrieves product feed. Can replace with your e-commerce platform API endpoint.",
"position": [
-4000,
460
],
"parameters": {
"url": "={{$env.CHANNABLE_API_URL}}/companies/{{$env.CHANNABLE_COMPANY_ID}}/projects/{{$env.CHANNABLE_PROJECT_ID}}/feeds/{{$env.FEED_ID}}",
"options": {},
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth"
},
"credentials": {
"httpHeaderAuth": {
"id": "luTyM3gZSgwhM8i0",
"name": "Header Auth account"
}
},
"typeVersion": 4.2
},
{
"id": "a88adbdf-2712-42cb-afe0-328f84038941",
"name": "Contrôles de qualité des données",
"type": "n8n-nodes-base.code",
"notes": "Validates: GTINs, images, categories, pricing, title/description length. Assigns quality score.",
"position": [
-3800,
460
],
"parameters": {
"jsCode": "// Data quality checks for Shopping feed\n\nconst items = $input.all();\nconst qualityIssues = [];\nconst validProducts = [];\n\nitems.forEach(item => {\n const product = item.json;\n const issues = [];\n \n // Check for missing GTIN\n if (!product.gtin || product.gtin === '') {\n issues.push('Missing GTIN');\n }\n \n // Check image\n if (!product.image_link || product.image_link === '') {\n issues.push('Missing image link');\n }\n \n // Check for missing category\n if (!product.google_product_category || product.google_product_category === '') {\n issues.push('Missing Google product category');\n }\n \n // Check for pricing errors\n const price = parseFloat(product.price);\n if (isNaN(price) || price <= 0) {\n issues.push('Invalid price');\n }\n \n // Check title length (30-150 chars optimal)\n const title = product.title || '';\n if (title.length < 30) {\n issues.push('Title too short (recommend 30-150 chars)');\n }\n if (title.length > 150) {\n issues.push('Title too long (max 150 chars)');\n }\n \n // Check for missing description\n if (!product.description || product.description.length < 160) {\n issues.push('Description missing or too short (recommend 160-500 chars)');\n }\n \n // Check availability\n if (!product.availability || !['in stock', 'out of stock', 'preorder', 'backorder'].includes(product.availability.toLowerCase())) {\n issues.push('Invalid availability status');\n }\n \n // Quality score\n const maxIssues = 7;\n const qualityScore = Math.round(((maxIssues - issues.length) / maxIssues) * 100);\n \n const result = {\n ...product,\n quality_score: qualityScore,\n quality_issues: issues,\n needs_optimization: issues.length > 0\n };\n \n if (qualityScore < 80) {\n qualityIssues.push(result);\n } else {\n validProducts.push(result);\n }\n});\n\nreturn {\n total_products: items.length,\n products_with_issues: qualityIssues.length,\n valid_products: validProducts.length,\n all_products: [...validProducts, ...qualityIssues]\n};"
},
"typeVersion": 2
},
{
"id": "4ba2eb7c-ce9d-4219-8adb-823f0e14dac8",
"name": "Optimiser le titre",
"type": "n8n-nodes-base.httpRequest",
"notes": "CORRECTED: Uses /trigger with tool ID. Optimizes title: Brand + Type + Features + Attributes. Max 150 chars.",
"position": [
-3400,
460
],
"parameters": {
"url": "={{$env.RELEVANCE_AI_API_URL}}/tools/{{$env.RELEVANCE_TOOL_TITLE_OPTIMIZER_ID}}/trigger",
"method": "POST",
"options": {},
"jsonBody": "={\n \"params\": {\n \"current_title\": \"{{$json.title}}\",\n \"category\": \"{{$json.google_product_category}}\",\n \"brand\": \"{{$json.brand}}\",\n \"color\": \"{{$json.color}}\",\n \"size\": \"{{$json.size}}\",\n \"material\": \"{{$json.material}}\"\n }\n}",
"sendBody": true,
"specifyBody": "json",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth"
},
"credentials": {
"httpHeaderAuth": {
"id": "luTyM3gZSgwhM8i0",
"name": "Header Auth account"
}
},
"typeVersion": 4.2
},
{
"id": "f505b7a4-9bb9-44fd-8ecd-ddfe94a4926d",
"name": "Générer la description",
"type": "n8n-nodes-base.httpRequest",
"notes": "CORRECTED: Uses /trigger with tool ID. Generates 300-400 char benefit-focused description.",
"position": [
-3200,
460
],
"parameters": {
"url": "={{$env.RELEVANCE_AI_API_URL}}/tools/{{$env.RELEVANCE_TOOL_DESCRIPTION_ID}}/trigger",
"method": "POST",
"options": {},
"jsonBody": "={\n \"params\": {\n \"product_title\": \"{{$json.optimized_title || $json.title}}\",\n \"product_features\": \"{{$json.description}}\",\n \"category\": \"{{$json.google_product_category}}\"\n }\n}",
"sendBody": true,
"specifyBody": "json",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth"
},
"credentials": {
"httpHeaderAuth": {
"id": "luTyM3gZSgwhM8i0",
"name": "Header Auth account"
}
},
"typeVersion": 4.2
},
{
"id": "a74d968c-c188-47fa-86da-448382eeaea9",
"name": "Attribuer des étiquettes personnalisées",
"type": "n8n-nodes-base.code",
"notes": "Assigns 5 custom labels for segmented bidding: margin, performance, seasonality, stock, category",
"position": [
-3000,
460
],
"parameters": {
"jsCode": "// Assign custom labels for campaign segmentation\n\nconst product = $input.item.json;\nconst price = parseFloat(product.price);\nconst cost = parseFloat(product.cost || 0);\n\n// Calculate margin\nconst margin = cost > 0 ? ((price - cost) / price) * 100 : 0;\n\n// Custom Label 0: Margin Tier\nlet marginTier = 'low';\nif (margin > 40) marginTier = 'high';\nelse if (margin > 25) marginTier = 'mid';\n\n// Custom Label 1: Performance\nlet performanceLabel = 'standard';\nif (product.sales_rank && product.sales_rank < 100) {\n performanceLabel = 'bestseller';\n} else if (product.created_date && new Date(product.created_date) > new Date(Date.now() - 30*24*60*60*1000)) {\n performanceLabel = 'new';\n} else if (product.availability === 'limited stock') {\n performanceLabel = 'clearance';\n}\n\n// Custom Label 2: Seasonality\nconst month = new Date().getMonth() + 1;\nlet seasonality = 'evergreen';\nif ([11, 12].includes(month)) seasonality = 'holiday';\nelse if ([6, 7, 8].includes(month)) seasonality = 'summer';\nelse if ([3, 4, 5].includes(month)) seasonality = 'spring';\n\n// Custom Label 3: Stock Level\nlet stockLevel = 'in-stock';\nif (product.quantity) {\n const qty = parseInt(product.quantity);\n if (qty === 0) stockLevel = 'out-of-stock';\n else if (qty < 10) stockLevel = 'low-stock';\n else if (qty > 100) stockLevel = 'high-stock';\n}\n\n// Custom Label 4: Category\nconst category = product.google_product_category || product.product_type || 'uncategorized';\nconst categoryShort = category.split('>')[0].trim().toLowerCase().replace(/\\s+/g, '-');\n\nreturn {\n ...product,\n optimized_title: $input.item.json.optimized_title || product.title,\n optimized_description: $input.item.json.optimized_description || product.description,\n custom_label_0: marginTier,\n custom_label_1: performanceLabel,\n custom_label_2: seasonality,\n custom_label_3: stockLevel,\n custom_label_4: categoryShort,\n margin_percent: margin.toFixed(2)\n};"
},
"typeVersion": 2
},
{
"id": "bc0cc114-262f-4594-a4d2-793926ab1e54",
"name": "Agréger les produits",
"type": "n8n-nodes-base.aggregate",
"notes": "Combines all optimized products",
"position": [
-2800,
460
],
"parameters": {
"options": {},
"aggregate": "aggregateAllItemData"
},
"typeVersion": 1
},
{
"id": "1116b030-6b5d-40c0-b871-7fea79fb7c46",
"name": "Vérifier le statut produit (NEW API)",
"type": "n8n-nodes-base.httpRequest",
"notes": "CORRECTED: Uses NEW Merchant API to list products and check for issues. PageSize now supports up to 1000.",
"position": [
-2240,
460
],
"parameters": {
"url": "=={{$env.MERCHANT_API_URL}}/{{$env.MERCHANT_ACCOUNT_ID}}/products",
"options": {},
"authentication": "predefinedCredentialType",
"nodeCredentialType": "googleApi"
},
"typeVersion": 4.2
},
{
"id": "3ea2945d-d376-4c72-9aed-c7da9529c772",
"name": "Analyser les problèmes produits",
"type": "n8n-nodes-base.code",
"notes": "CORRECTED: Parses NEW Merchant API response format for issues",
"position": [
-2040,
460
],
"parameters": {
"jsCode": "// Monitor for disapprovals and quality issues\n\nconst items = $input.all();\nconst products = items[0]?.json?.products || [];\nconst disapprovals = [];\nconst warnings = [];\n\nproducts.forEach(product => {\n // Check for issues in NEW Merchant API format\n if (product.issues && product.issues.length > 0) {\n product.issues.forEach(issue => {\n if (issue.severity === 'error' || issue.applicability === 'DISAPPROVED') {\n disapprovals.push({\n product_id: product.offerId,\n product_title: product.title,\n issue: issue.description || issue.detail,\n severity: 'CRITICAL'\n });\n } else if (issue.severity === 'warning') {\n warnings.push({\n product_id: product.offerId,\n product_title: product.title,\n issue: issue.description || issue.detail,\n severity: 'WARNING'\n });\n }\n });\n }\n});\n\nreturn {\n total_products_checked: products.length,\n disapprovals: disapprovals,\n warnings: warnings,\n disapproval_count: disapprovals.length,\n warning_count: warnings.length,\n check_timestamp: new Date().toISOString()\n};"
},
"typeVersion": 2
},
{
"id": "7766d9c2-5967-4984-a9ff-5448b19fd51d",
"name": "SI rejets détectés",
"type": "n8n-nodes-base.if",
"notes": "Check if any critical disapprovals exist",
"position": [
-1840,
460
],
"parameters": {
"options": {},
"conditions": {
"number": [
{
"value1": "={{$json.disapproval_count}}",
"value2": 0,
"operation": "larger"
}
]
}
},
"typeVersion": 2
},
{
"id": "7ad9791b-2c14-4fee-bac2-b35ce882745d",
"name": "Alerte - Rejets",
"type": "n8n-nodes-base.slack",
"notes": "Sends alert if disapprovals found",
"position": [
-1380,
380
],
"webhookId": "affe0e89-ef4a-4813-9a51-d6e096a7d774",
"parameters": {
"text": "=🚨 *Merchant Center Disapprovals Alert*\n\n*Total Disapprovals:* {{$json.disapproval_count}}\n*Total Warnings:* {{$json.warning_count}}\n\n*Critical Issues:*\n{{$json.disapprovals.slice(0,10).map(d => `• Product: ${d.product_title} (${d.product_id})\\n Issue: ${d.issue}`).join('\\n\\n')}}\n\n*Action Required:* Review and fix disapproved products in Merchant Center.\n\n*Timestamp:* {{$json.check_timestamp}}",
"otherOptions": {}
},
"typeVersion": 2.1
},
{
"id": "e7d48164-e460-4f7e-bf8d-53f99df36e1e",
"name": "Résumé de réussite",
"type": "n8n-nodes-base.slack",
"notes": "Sends daily summary of feed optimization",
"position": [
-1380,
580
],
"webhookId": "84c5cd8c-521b-4982-81ca-fe0e7d24dff0",
"parameters": {
"text": "=✅ *Shopping Feed Optimization Complete*\n\n📊 *Summary:*\n• Total Products Processed: {{$node['Aggregate Products'].json.length}}\n• Products with Quality Issues: {{$node['Data Quality Checks'].json.products_with_issues}}\n• Disapprovals: {{$json.disapproval_count}}\n• Warnings: {{$json.warning_count}}\n\n🎯 *Optimizations Applied:*\n• Titles optimized for SEO\n• Descriptions enhanced\n• Custom labels assigned for segmented bidding\n\n*API Used:* NEW Merchant API (merchantapi.googleapis.com)\n*Next optimization:* Tomorrow 6 AM\n*Timestamp:* {{$now.toISO()}}",
"otherOptions": {}
},
"typeVersion": 2.1
},
{
"id": "7d1494bd-00c4-4aee-bda2-1f7a88e70109",
"name": "Téléverser vers Merchant Center (Content API v2.1)",
"type": "n8n-nodes-base.httpRequest",
"notes": "CRITICAL CORRECTION: Uses NEW Merchant API (merchantapi.googleapis.com) instead of deprecated Content API. Endpoint: /products:insert. Max 1000 products per batch.",
"position": [
-2440,
460
],
"parameters": {
"url": "=={{$env.MERCHANT_API_URL}}/{{$env.MERCHANT_ACCOUNT_ID}}/products",
"method": "POST",
"options": {
"batching": {
"batch": {
"batchSize": 1000
}
}
},
"jsonBody": "={\n \"productId\": \"{{$json.id}}\",\n \"contentLanguage\": \"en\",\n \"targetCountry\": \"US\",\n \"channel\": \"online\",\n \"offerId\": \"{{$json.id}}\",\n \"title\": \"{{$json.optimized_title}}\",\n \"description\": \"{{$json.optimized_description}}\",\n \"link\": \"{{$json.link}}\",\n \"imageLink\": \"{{$json.image_link}}\",\n \"price\": {\n \"value\": \"{{$json.price}}\",\n \"currency\": \"{{$json.currency || 'USD'}}\"\n },\n \"availability\": \"{{$json.availability}}\",\n \"brand\": \"{{$json.brand}}\",\n \"gtin\": \"{{$json.gtin}}\",\n \"condition\": \"{{$json.condition || 'new'}}\",\n \"googleProductCategory\": \"{{$json.google_product_category}}\",\n \"productTypes\": [\"{{$json.product_type}}\"],\n \"customLabel0\": \"{{$json.custom_label_0}}\",\n \"customLabel1\": \"{{$json.custom_label_1}}\",\n \"customLabel2\": \"{{$json.custom_label_2}}\",\n \"customLabel3\": \"{{$json.custom_label_3}}\",\n \"customLabel4\": \"{{$json.custom_label_4}}\"\n}",
"sendBody": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "googleApi"
},
"typeVersion": 4.2
},
{
"id": "0f405975-1874-4a86-8f6e-8cadac48922d",
"name": "Diviser les produits 1",
"type": "n8n-nodes-base.itemLists",
"notes": "Splits the 'all_products' array from Data Quality Checks into individual product items for further processing (Relevance AI optimization, labeling, etc).",
"position": [
-3600,
460
],
"parameters": {
"options": {},
"fieldToSplitOut": "all_products"
},
"typeVersion": 3
},
{
"id": "0fdb96fb-cbfc-4a0e-b5cc-adf8f6d4c35f",
"name": "Note adhésive",
"type": "n8n-nodes-base.stickyNote",
"position": [
-5060,
340
],
"parameters": {
"width": 640,
"height": 300,
"content": "# 🛍️ Google Shopping Feed Optimization with Relevance AI + Google Merchant API\n\nAutomates your Google Shopping product feed optimization.\nUses Relevance AI to enhance titles/descriptions, adds custom labels, and syncs optimized products daily to Merchant Center."
},
"typeVersion": 1
},
{
"id": "58d75113-8d09-4dbe-93d4-7f61f6a2c51f",
"name": "Note adhésive 2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-4240,
680
],
"parameters": {
"width": 820,
"height": 220,
"content": "## 🟨 Stage 1 — Workflow Start\n\n| 🕓 Daily Trigger – 6 AM | 📦 Get Product Feed | 🔍 Data Quality Checks | ✂️ Split Products |\n|--------------------------|--------------------|------------------------|------------------|\n| Runs automatically every morning.<br>Starts 6 AM daily to refresh and optimize the feed before Merchant Center sync. | Fetches product data from Channable (or your e-commerce API). | Checks for missing GTINs, titles, prices, and descriptions.Calculates a quality score for each item. | Prepares each product for AI optimization by splitting the feed into individual items. |\n"
},
"typeVersion": 1
},
{
"id": "e474c0ae-303d-4038-b395-4288c83b1d30",
"name": "Note adhésive 3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-3420,
160
],
"parameters": {
"width": 680,
"height": 240,
"content": "## 🟨 Stage 2 — AI Optimization Stage\n\n| 🧠 Optimize Title | 📝 Generate Description | 🏷️ Assign Custom Labels | 📊 Aggregate Products |\n|------------------|-------------------------|-------------------------|----------------------|\n| AI-powered title optimizer using Relevance AI.Improves clarity and SEO.e.g., “Running Shoes” → “Nike Air Zoom Men’s Running Shoes – Size 42”. | AI-generated 300–400 char benefit-focused descriptions via Relevance AI. | Adds five campaign segmentation labels (margin, performance, seasonality, stock, category). | Combines all optimized products back into a single feed ready for upload. |"
},
"typeVersion": 1
},
{
"id": "4653db9a-6b15-4882-a55a-717e010fb0bc",
"name": "Note adhésive 4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2660,
760
],
"parameters": {
"width": 1220,
"height": 220,
"content": "## 🟨 Stage 3 — Merchant Center Sync\n\n| 🚀 Upload to Merchant Center (API v2.1) | 🔁 Check Product Status (NEW API) | ⚠️ Analyze Product Issues | 🚦 IF Disapprovals Found |\n|-----------------------------------------|----------------------------------|---------------------------|--------------------------|\n| Publishes optimized feed in batches (max 1000) using the new Merchant API (`merchantapi.googleapis.com`). | Verifies upload results by listing live products and checking for warnings or errors. | Detects disapprovals and warnings from Merchant API responses and groups them by severity. | Routes workflow based on disapprovals – alerts team if issues exist or sends success summary otherwise. |"
},
"typeVersion": 1
},
{
"id": "fe61502c-d105-4610-a3fd-f6b1786ce661",
"name": "Note adhésive 5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1120,
400
],
"parameters": {
"width": 440,
"height": 240,
"content": "## 🟨 Stage 4 — Notifications\n\n| 🚨 Alert – Disapprovals | ✅ Success Summary |\n|--------------------------|--------------------|\n| Immediate Slack alert listing disapproved products and issues requiring review. | Posts daily Slack summary with total products, issues, and confirmation of successful optimization. |\n"
},
"typeVersion": 1
}
],
"pinData": {},
"connections": {
"4ba2eb7c-ce9d-4219-8adb-823f0e14dac8": {
"main": [
[
{
"node": "f505b7a4-9bb9-44fd-8ecd-ddfe94a4926d",
"type": "main",
"index": 0
}
]
]
},
"0f405975-1874-4a86-8f6e-8cadac48922d": {
"main": [
[
{
"node": "4ba2eb7c-ce9d-4219-8adb-823f0e14dac8",
"type": "main",
"index": 0
}
]
]
},
"698d4143-e209-4c81-94ce-01094c4b1f14": {
"main": [
[
{
"node": "a88adbdf-2712-42cb-afe0-328f84038941",
"type": "main",
"index": 0
}
]
]
},
"bc0cc114-262f-4594-a4d2-793926ab1e54": {
"main": [
[
{
"node": "7d1494bd-00c4-4aee-bda2-1f7a88e70109",
"type": "main",
"index": 0
}
]
]
},
"a88adbdf-2712-42cb-afe0-328f84038941": {
"main": [
[
{
"node": "0f405975-1874-4a86-8f6e-8cadac48922d",
"type": "main",
"index": 0
}
]
]
},
"a74d968c-c188-47fa-86da-448382eeaea9": {
"main": [
[
{
"node": "bc0cc114-262f-4594-a4d2-793926ab1e54",
"type": "main",
"index": 0
}
]
]
},
"34eafce0-026c-416e-99b8-fd6d012d758f": {
"main": [
[
{
"node": "698d4143-e209-4c81-94ce-01094c4b1f14",
"type": "main",
"index": 0
}
]
]
},
"f505b7a4-9bb9-44fd-8ecd-ddfe94a4926d": {
"main": [
[
{
"node": "a74d968c-c188-47fa-86da-448382eeaea9",
"type": "main",
"index": 0
}
]
]
},
"7766d9c2-5967-4984-a9ff-5448b19fd51d": {
"main": [
[
{
"node": "7ad9791b-2c14-4fee-bac2-b35ce882745d",
"type": "main",
"index": 0
}
],
[
{
"node": "e7d48164-e460-4f7e-bf8d-53f99df36e1e",
"type": "main",
"index": 0
}
]
]
},
"3ea2945d-d376-4c72-9aed-c7da9529c772": {
"main": [
[
{
"node": "7766d9c2-5967-4984-a9ff-5448b19fd51d",
"type": "main",
"index": 0
}
]
]
},
"1116b030-6b5d-40c0-b871-7fea79fb7c46": {
"main": [
[
{
"node": "3ea2945d-d376-4c72-9aed-c7da9529c772",
"type": "main",
"index": 0
}
]
]
},
"7d1494bd-00c4-4aee-bda2-1f7a88e70109": {
"main": [
[
{
"node": "1116b030-6b5d-40c0-b871-7fea79fb7c46",
"type": "main",
"index": 0
}
]
]
}
}
}Comment utiliser ce workflow ?
Copiez le code de configuration JSON ci-dessus, créez un nouveau workflow dans votre instance n8n et sélectionnez "Importer depuis le JSON", collez la configuration et modifiez les paramètres d'authentification selon vos besoins.
Dans quelles scénarios ce workflow est-il adapté ?
Avancé - Création de contenu, IA Multimodale
Est-ce payant ?
Ce workflow est entièrement gratuit et peut être utilisé directement. Veuillez noter que les services tiers utilisés dans le workflow (comme l'API OpenAI) peuvent nécessiter un paiement de votre part.
Workflows recommandés
Nikan Noorafkan
@nikkannooraHey, I’m Nikan Noorafkan — a creator passionate about building smart, automated workflows that drive business outcomes. With a background in performance marketing, user acquisition, and retention strategies, I use n8n to connect data, automate repetitive tasks, and scale growth across the funnel.
Partager ce workflow