使用 RFM 分析对 WooCommerce 客户进行细分以实现精准营销
中级
这是一个Marketing领域的自动化工作流,包含 7 个节点。主要使用 Code、Html、Start、WooCommerce、ScheduleTrigger 等节点。 使用 RFM 分析对 WooCommerce 客户进行细分以实现精准营销
前置要求
- •无特殊前置要求,导入即可使用
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
"meta": {
"instanceId": "370f0437fbf8d71caf7e9230e115239afcf5012c55ac368aa9dee29869df4a6b",
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "5db1ea37-aa49-4081-8fd0-fa9416cbcff4",
"name": "手动开始",
"type": "n8n-nodes-base.start",
"position": [
0,
0
],
"parameters": {},
"typeVersion": 1
},
{
"id": "c6c0b7d2-e1d4-442d-aff5-b206426411bc",
"name": "每周触发器",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
0,
200
],
"parameters": {
"rule": {
"interval": [
{}
]
}
},
"typeVersion": 1.1
},
{
"id": "e00baa15-fd2c-444b-9c31-189d6b9986c7",
"name": "从 WooCommerce 获取订单",
"type": "n8n-nodes-base.wooCommerce",
"position": [
200,
0
],
"parameters": {
"options": {
"after": "={{ $now.minus(1, 'year').toISO() }}",
"status": "completed"
},
"resource": "order",
"operation": "getAll",
"returnAll": true
},
"credentials": {
"wooCommerceApi": {
"id": "7FzoXyPl8TAUChEg",
"name": "WooCommerce account"
}
},
"typeVersion": 1
},
{
"id": "ef5905d0-4db8-4e57-bc4e-44b72d3bf4a6",
"name": "计算 RFM 细分",
"type": "n8n-nodes-base.code",
"position": [
480,
0
],
"parameters": {
"jsCode": "// Group orders by customer and calculate RFM\nconst orders = $input.all();\nconst customers = {};\nconst today = new Date();\n\n// Process orders\norders.forEach(order => {\n const customerId = order.json.customer_id || order.json.billing.email;\n if (!customerId) return;\n \n if (!customers[customerId]) {\n customers[customerId] = {\n customerId: customerId,\n customerName: `${order.json.billing.first_name} ${order.json.billing.last_name}`,\n email: order.json.billing.email,\n orders: [],\n totalSpent: 0,\n orderCount: 0\n };\n }\n \n const orderDate = new Date(order.json.date_created);\n customers[customerId].orders.push({\n date: orderDate,\n total: parseFloat(order.json.total)\n });\n customers[customerId].totalSpent += parseFloat(order.json.total);\n customers[customerId].orderCount++;\n});\n\n// Calculate RFM values\nconst customerData = Object.values(customers).map(customer => {\n // Recency: Number of days since last purchase\n const lastOrderDate = Math.max(...customer.orders.map(o => o.date));\n const recency = Math.floor((today - new Date(lastOrderDate)) / (1000 * 60 * 60 * 24));\n \n // Frequency: Number of orders\n const frequency = customer.orderCount;\n \n // Monetary: Total spent\n const monetary = customer.totalSpent;\n \n return {\n customerId: customer.customerId,\n customerName: customer.customerName,\n email: customer.email,\n recency: recency,\n frequency: frequency,\n monetary: monetary,\n lastOrderDate: new Date(lastOrderDate).toISOString().split('T')[0]\n };\n});\n\n// Sort for quartile calculations\nconst sortedByRecency = [...customerData].sort((a, b) => a.recency - b.recency);\nconst sortedByFrequency = [...customerData].sort((a, b) => b.frequency - a.frequency);\nconst sortedByMonetary = [...customerData].sort((a, b) => b.monetary - a.monetary);\n\n// Quartile calculation helper\nfunction getQuartile(sortedArray, value, field, ascending = false) {\n const index = sortedArray.findIndex(item => item[field] === value);\n const quartile = Math.ceil((index + 1) / sortedArray.length * 4);\n return ascending ? quartile : 5 - quartile;\n}\n\n// Assign RFM scores\nconst rfmScores = customerData.map(customer => {\n const rScore = getQuartile(sortedByRecency, customer.recency, 'recency', true);\n const fScore = getQuartile(sortedByFrequency, customer.frequency, 'frequency');\n const mScore = getQuartile(sortedByMonetary, customer.monetary, 'monetary');\n \n const rfmScore = `${rScore}${fScore}${mScore}`;\n \n // Determine segment\n let segment = '';\n if (rScore >= 4 && fScore >= 4 && mScore >= 4) {\n segment = 'Champions';\n } else if (rScore >= 3 && fScore >= 3 && mScore >= 4) {\n segment = 'Loyal Customers';\n } else if (rScore >= 3 && fScore >= 1 && mScore >= 3) {\n segment = 'Potential Loyalists';\n } else if (rScore >= 4 && fScore <= 2) {\n segment = 'New Customers';\n } else if (rScore >= 3 && fScore >= 3 && mScore <= 2) {\n segment = 'Promising';\n } else if (rScore <= 2 && fScore >= 3) {\n segment = 'Need Attention';\n } else if (rScore <= 2 && fScore <= 2 && mScore >= 3) {\n segment = 'About to Sleep';\n } else if (rScore <= 2 && fScore >= 3 && mScore >= 3) {\n segment = 'At Risk';\n } else if (rScore <= 2 && fScore <= 2 && mScore <= 2) {\n segment = 'Lost';\n } else {\n segment = 'Others';\n }\n \n return {\n ...customer,\n rScore,\n fScore,\n mScore,\n rfmScore,\n segment,\n avgOrderValue: customer.monetary / customer.frequency\n };\n});\n\nreturn rfmScores;\n"
},
"typeVersion": 2
},
{
"id": "5702ae22-50a8-4a53-9fef-593a9e4c8001",
"name": "生成细分摘要",
"type": "n8n-nodes-base.code",
"position": [
840,
0
],
"parameters": {
"jsCode": "const items = $input.all();\n\n// Segment translation and priority definitions\nconst segmentDetails = {\n 'Champions': { fa: 'Champions', priority: 1, action: 'Send VIP offer and exclusive discount code' },\n 'Loyal Customers': { fa: 'Loyal Customers', priority: 2, action: 'Invite to loyalty club and introduce new products' },\n 'Potential Loyalists': { fa: 'Potential Loyalists', priority: 3, action: 'Encourage more interaction and suggest complementary products' },\n 'New Customers': { fa: 'New Customers', priority: 4, action: 'Send welcome message and encourage second purchase' },\n 'Promising': { fa: 'Promising', priority: 5, action: 'Send product reminders and additional education' },\n 'Need Attention': { fa: 'Need Attention', priority: 6, action: 'Investigate reasons for inactivity and send comeback campaign' },\n 'About to Sleep': { fa: 'About to Sleep', priority: 7, action: 'Send new products and return incentives' },\n 'At Risk': { fa: 'At Risk', priority: 8, action: 'Send personalized message with heavy discount' },\n 'Lost': { fa: 'Lost', priority: 9, action: 'Offer return deal and \"We Miss You\" campaign' },\n 'Others': { fa: 'Others', priority: 10, action: 'Manual review for behavior analysis' },\n};\n\n// Count customers per segment\nconst segmentCounts = {};\n\nfor (const item of items) {\n const seg = item.json.segment || 'Others';\n if (!segmentCounts[seg]) segmentCounts[seg] = 0;\n segmentCounts[seg]++;\n}\n\n// Build HTML table\nlet html = `\n<h2 style=\"text-align: center;\">RFM Summary Report - ${new Date().toISOString().split('T')[0]}</h2>\n<table border=\"1\" cellpadding=\"8\" cellspacing=\"0\" style=\"width:90%; margin:auto; border-collapse:collapse; font-family:sans-serif;\">\n <thead style=\"background:#e6f2ff;\">\n <tr>\n <th>Segment</th>\n <th>Customer Count</th>\n <th>Marketing Suggestion</th>\n </tr>\n </thead>\n <tbody>\n`;\n\nObject.entries(segmentCounts)\n .map(([key, count]) => ({\n key,\n count,\n priority: segmentDetails[key]?.priority || 999,\n label: segmentDetails[key]?.fa || key,\n action: segmentDetails[key]?.action || '-'\n }))\n .sort((a, b) => a.priority - b.priority)\n .forEach(({ label, count, action }) => {\n html += `\n <tr>\n <td>${label}</td>\n <td>${count}</td>\n <td>${action}</td>\n </tr>\n `;\n });\n\nhtml += `\n </tbody>\n</table>\n`;\n\nreturn [{ json: { html } }];\n"
},
"typeVersion": 2
},
{
"id": "4b4993f8-25d0-4109-bec7-41902c065eb3",
"name": "构建报告页面",
"type": "n8n-nodes-base.html",
"position": [
1120,
0
],
"parameters": {
"html": "<head>\n <meta charset=\"UTF-8\">\n <style>\n body {\n font-family: sans-serif;\n background-color: #f7f7f7;\n padding: 20px;\n }\n h2 {\n text-align: center;\n color: #333;\n }\n table {\n width: 100%;\n border-collapse: collapse;\n margin-top: 20px;\n background-color: #fff;\n }\n th, td {\n border: 1px solid #ccc;\n padding: 8px 12px;\n font-size: 14px;\n text-align: center;\n }\n th {\n background-color: #e6f2ff;\n }\n tr:nth-child(even) {\n background-color: #f9f9f9;\n }\n .segment {\n font-weight: bold;\n color: #2e7d32;\n }\n </style>\n</head>\n{{ $json.html }}\n"
},
"typeVersion": 1.2
},
{
"id": "76665a4f-a27d-42a2-81dd-4e62411a7129",
"name": "便签",
"type": "n8n-nodes-base.stickyNote",
"position": [
0,
-460
],
"parameters": {
"width": 740,
"height": 440,
"content": "## 🛠️ 本工作流设置说明"
},
"typeVersion": 1
}
],
"pinData": {},
"connections": {
"Manual Start": {
"main": [
[
{
"node": "Fetch Orders From WooCommerce",
"type": "main",
"index": 0
}
]
]
},
"Weekly Trigger": {
"main": [
[
{
"node": "Fetch Orders From WooCommerce",
"type": "main",
"index": 0
}
]
]
},
"Compute RFM Segmentation": {
"main": [
[
{
"node": "Generate Segment Summary",
"type": "main",
"index": 0
}
]
]
},
"Generate Segment Summary": {
"main": [
[
{
"node": "Build Report Page",
"type": "main",
"index": 0
}
]
]
},
"Fetch Orders From WooCommerce": {
"main": [
[
{
"node": "Compute RFM Segmentation",
"type": "main",
"index": 0
}
]
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
这是一个中级难度的工作流,适用于Marketing等场景。适合有一定经验的用户,包含 6-15 个节点的中等复杂度工作流
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
免费监控竞争对手价格
使用网络爬虫、Google Sheets 和 Telegram 免费监控竞争对手价格
If
Code
Html
+7
24 节点Tony Paul
AI
使用 AI 创建 LinkedIn 贡献并在 Slack 上通知用户
使用 AI 创建 LinkedIn 贡献并在 Slack 上通知用户
Set
Code
Html
+11
33 节点Darryn
AI
每日播客摘要
每日播客摘要
If
Set
Code
+8
21 节点Jay Hartley
AI
使用Bright Data和Google搜索通过邮箱和域名查找丰富卖家数据
使用Bright Data和Google搜索通过邮箱和域名查找丰富卖家数据
If
Set
Code
+12
32 节点Cyril Nicko Gaspar
Sales
实时Notion Todoist双向同步模板
使用Redis的Notion Todoist实时双向同步
If
Set
Code
+26
246 节点Mario
Sales
🏤 欧盟事件抓取与 Google Sheets
🏤 使用 Google Sheets 抓取欧盟事件
If
Set
Code
+8
20 节点Samir Saci
AI