AutomationFlowsSlack & Telegram › Recover Shopify Abandoned Carts with Email, Sms, Whatsapp & Facebook Retargeting

Recover Shopify Abandoned Carts with Email, Sms, Whatsapp & Facebook Retargeting

ByȚugui Dragoș @tuguidragos on n8n.io

This workflow is a complete, production-ready solution for recovering abandoned carts in Shopify stores using a multi-channel, multi-touch approach. It automates personalized follow-ups via Email, SMS, and WhatsApp, tracks every customer interaction for multi-touch attribution,…

Webhook trigger★★★★★ complexity54 nodesHTTP RequestShopifySendGridGoogle SheetsTwilioWhatsAppFacebook Graph ApiSlack
Slack & Telegram Trigger: Webhook Nodes: 54 Complexity: ★★★★★ Added:
Recover Shopify Abandoned Carts with Email, Sms, Whatsapp & Facebook Retargeting — n8n workflow card showing HTTP Request, Shopify, SendGrid integration

This workflow corresponds to n8n.io template #11805 — 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 →

Download .json
{
  "id": "mrc7eOumjGzatbaj",
  "name": "Recover Shopify Abandoned Carts (Multi-Touch)",
  "tags": [
    {
      "id": "BozSnIOP0arZwOpu",
      "name": "tuguidragos.com",
      "createdAt": "2025-12-14T19:49:53.386Z",
      "updatedAt": "2025-12-14T19:49:53.386Z"
    }
  ],
  "nodes": [
    {
      "id": "2af57041-a8fa-4b7f-a0fa-4b9f2e78d45d",
      "name": "Abandoned Cart Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -5328,
        208
      ],
      "parameters": {
        "path": "abandoned-cart",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "lastNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "b8a225f1-7bb0-4e47-be3f-46bc83de07c8",
      "name": "Workflow Configuration",
      "type": "n8n-nodes-base.set",
      "position": [
        -5104,
        208
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "id-1",
              "name": "highValueThreshold",
              "type": "number",
              "value": 500
            },
            {
              "id": "id-2",
              "name": "cartApiUrl",
              "type": "string",
              "value": "<__PLACEHOLDER_VALUE__Cart API endpoint URL__>"
            },
            {
              "id": "id-3",
              "name": "customerApiUrl",
              "type": "string",
              "value": "<__PLACEHOLDER_VALUE__Customer API endpoint URL__>"
            },
            {
              "id": "id-4",
              "name": "shopifyDomain",
              "type": "string",
              "value": "<__PLACEHOLDER_VALUE__Shopify store domain__>"
            },
            {
              "id": "id-5",
              "name": "googleSheetsId",
              "type": "string",
              "value": "<__PLACEHOLDER_VALUE__Google Sheets spreadsheet ID__>"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "83e8f42f-dc24-4682-b3df-f2502daaa081",
      "name": "Normalize Cart Data",
      "type": "n8n-nodes-base.set",
      "position": [
        -5312,
        832
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "id-1",
              "name": "cart_id",
              "type": "string",
              "value": "={{ $json.body?.cart_id || $json.cart_id || '' }}"
            },
            {
              "id": "id-2",
              "name": "customer_id",
              "type": "string",
              "value": "={{ $json.body?.customer_id || $json.customer_id || '' }}"
            },
            {
              "id": "id-3",
              "name": "products",
              "type": "array",
              "value": "={{ $json.body?.products || $json.products || [] }}"
            },
            {
              "id": "id-4",
              "name": "subtotal",
              "type": "number",
              "value": "={{ $json.body?.subtotal || $json.subtotal || 0 }}"
            },
            {
              "id": "id-5",
              "name": "device",
              "type": "string",
              "value": "={{ $json.body?.device || $json.device || 'desktop' }}"
            },
            {
              "id": "id-6",
              "name": "country",
              "type": "string",
              "value": "={{ $json.body?.country || $json.country || 'US' }}"
            },
            {
              "id": "id-7",
              "name": "email",
              "type": "string",
              "value": "={{ $json.body?.email || $json.email || '' }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "0981e7c2-c0c9-4f9e-a05c-cda0fbbd5d62",
      "name": "Fetch Cart Details",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -5088,
        928
      ],
      "parameters": {
        "url": "={{ $('Workflow Configuration').first().json.cartApiUrl }}/{{ $json.cart_id }}",
        "options": {},
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "45b42e77-b9d2-4527-ba22-349520cfce7e",
      "name": "Fetch Customer History",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -5088,
        736
      ],
      "parameters": {
        "url": "={{ $('Workflow Configuration').first().json.customerApiUrl }}/{{ $json.customer_id }}",
        "options": {},
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "20ba8d41-0963-4a83-bdbf-3c7b50681a48",
      "name": "Predict Abandonment Reason",
      "type": "n8n-nodes-base.code",
      "position": [
        -4784,
        816
      ],
      "parameters": {
        "jsCode": "// Predict Abandonment Reason - Merge cart and customer data\nconst items = $input.all();\nconst results = [];\n\n// Group items by cart_id to merge cart details and customer history\nconst cartMap = new Map();\n\nfor (const item of items) {\n  const cartId = item.json.cart_id;\n  \n  if (!cartMap.has(cartId)) {\n    cartMap.set(cartId, {\n      cartData: {},\n      customerData: {},\n      originalData: {}\n    });\n  }\n  \n  const entry = cartMap.get(cartId);\n  \n  // Check if this item has cart details (from Fetch Cart Details node)\n  if (item.json.items || item.json.line_items) {\n    entry.cartData = item.json;\n  }\n  // Check if this item has customer history (from Fetch Customer History node)\n  else if (item.json.orders || item.json.total_spent !== undefined) {\n    entry.customerData = item.json;\n  }\n  // Otherwise it's the original normalized data\n  else {\n    entry.originalData = item.json;\n  }\n}\n\n// Process each cart\nfor (const [cartId, data] of cartMap.entries()) {\n  const original = data.originalData;\n  const cart = data.cartData;\n  const customer = data.customerData;\n  \n  // Calculate cart metrics\n  const cartItems = cart.items || cart.line_items || original.products || [];\n  const cartValue = original.subtotal || cart.total_price || 0;\n  const itemCount = Array.isArray(cartItems) ? cartItems.length : 0;\n  \n  // Calculate customer metrics\n  const orderHistory = customer.orders || [];\n  const orderCount = Array.isArray(orderHistory) ? orderHistory.length : (customer.orders_count || 0);\n  const totalSpent = customer.total_spent || 0;\n  const avgOrderValue = orderCount > 0 ? totalSpent / orderCount : 0;\n  \n  // Simple rule-based abandonment prediction\n  let predictedReason = 'Just Browsing';\n  let confidence = 60;\n  let explanation = 'Customer may be comparing options';\n  let recommendedAction = 'Send gentle reminder with product highlights';\n  \n  if (cartValue > 200) {\n    predictedReason = 'Price Sensitivity';\n    confidence = 75;\n    explanation = 'High cart value may cause hesitation';\n    recommendedAction = 'Offer discount or payment plan';\n  } else if (orderCount === 0) {\n    predictedReason = 'Checkout Complexity';\n    confidence = 70;\n    explanation = 'First-time customer unfamiliar with checkout';\n    recommendedAction = 'Simplify checkout messaging, offer support';\n  } else if (original.device === 'mobile') {\n    predictedReason = 'Technical Issues';\n    confidence = 65;\n    explanation = 'Mobile checkout may have usability challenges';\n    recommendedAction = 'Send mobile-optimized reminder';\n  } else if (itemCount > 5) {\n    predictedReason = 'Comparison Shopping';\n    confidence = 68;\n    explanation = 'Multiple items suggest research phase';\n    recommendedAction = 'Highlight bestsellers and reviews';\n  }\n  \n  results.push({\n    json: {\n      ...original,\n      cart_id: cartId,\n      cartDetails: cart,\n      customerHistory: customer,\n      cartValue: cartValue,\n      itemCount: itemCount,\n      orderCount: orderCount,\n      totalSpent: totalSpent,\n      avgOrderValue: avgOrderValue,\n      predictedReason: predictedReason,\n      confidence: confidence,\n      explanation: explanation,\n      recommendedAction: recommendedAction,\n      predictedAt: new Date().toISOString()\n    }\n  });\n}\n\nreturn results;"
      },
      "typeVersion": 2
    },
    {
      "id": "888a5d08-3f58-43a3-bffa-9c1fea08c022",
      "name": "Personalization Engine",
      "type": "n8n-nodes-base.code",
      "position": [
        -4560,
        816
      ],
      "parameters": {
        "jsCode": "// Personalization Engine - Generate personalized offers and segment customers\nconst items = $input.all();\nconst results = [];\n\nfor (const item of items) {\n  const data = item.json;\n  \n  const orderCount = data.orderCount || 0;\n  const totalSpent = data.totalSpent || 0;\n  const cartValue = data.cartValue || 0;\n  \n  // Classify customer segment\n  let customerSegment = 'new';\n  if (orderCount === 0) {\n    customerSegment = 'new';\n  } else if (orderCount >= 5 || totalSpent >= 1000) {\n    customerSegment = 'vip';\n  } else {\n    customerSegment = 'returning';\n  }\n  \n  // Calculate dynamic discount\n  let discountPercent = 10;\n  let discountCode = 'CART10';\n  \n  if (customerSegment === 'new') {\n    if (cartValue >= 100) {\n      discountPercent = 15;\n      discountCode = 'WELCOME15';\n    } else {\n      discountPercent = 10;\n      discountCode = 'WELCOME10';\n    }\n  } else if (customerSegment === 'returning') {\n    if (cartValue >= 150) {\n      discountPercent = 12;\n      discountCode = 'RETURN12';\n    } else {\n      discountPercent = 8;\n      discountCode = 'RETURN8';\n    }\n  } else if (customerSegment === 'vip') {\n    if (cartValue >= 200) {\n      discountPercent = 20;\n      discountCode = 'VIP20';\n    } else {\n      discountPercent = 15;\n      discountCode = 'VIP15';\n    }\n  }\n  \n  // A/B test group\n  const abGroup = Math.random() < 0.5 ? 'A' : 'B';\n  \n  // Extract customer name\n  const customerName = data.customer_name || data.customerHistory?.first_name || 'Valued Customer';\n  const customerEmail = data.email || data.customer_email || '';\n  const customerPhone = data.phone || data.customer_phone || '';\n  \n  // Build checkout URL\n  const shopifyDomain = $('Workflow Configuration').first().json.shopifyDomain || 'shop.example.com';\n  const checkoutUrl = `https://${shopifyDomain}/cart/${data.cart_id}`;\n  \n  results.push({\n    json: {\n      ...data,\n      customerSegment: customerSegment,\n      discountPercent: discountPercent,\n      discountCode: discountCode,\n      abGroup: abGroup,\n      customerName: customerName,\n      customerEmail: customerEmail,\n      customerPhone: customerPhone,\n      checkoutUrl: checkoutUrl,\n      personalizedAt: new Date().toISOString()\n    }\n  });\n}\n\nreturn results;"
      },
      "typeVersion": 2
    },
    {
      "id": "b7acc79b-8942-46ca-9e14-4f3182c7f26a",
      "name": "Wait 1 Hour",
      "type": "n8n-nodes-base.wait",
      "position": [
        -3744,
        800
      ],
      "parameters": {
        "unit": "hours",
        "amount": 1
      },
      "typeVersion": 1.1
    },
    {
      "id": "c3fbf7d5-7845-470a-8caf-26df40901dc7",
      "name": "Check Order Completed (1h)",
      "type": "n8n-nodes-base.if",
      "position": [
        -3376,
        800
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "id-1",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.financial_status }}",
              "rightValue": "paid"
            },
            {
              "id": "id-2",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.fulfillment_status }}",
              "rightValue": "completed"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "a55f97b5-ab34-4d73-927f-1e76cccc2efc",
      "name": "Check Order Status (1h)",
      "type": "n8n-nodes-base.shopify",
      "position": [
        -3584,
        800
      ],
      "parameters": {
        "options": {},
        "orderId": "={{ $json.order_id || $json.cart_id }}",
        "operation": "get"
      },
      "typeVersion": 1
    },
    {
      "id": "b7084dab-ec4b-4b06-99ed-e733aec65e48",
      "name": "Generate Email 1 Content",
      "type": "n8n-nodes-base.code",
      "position": [
        -3184,
        912
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Generate Email 1 Content - Simple personalized email\nconst item = $input.item.json;\n\nconst customerName = item.customerName || 'Valued Customer';\nconst cartValue = item.cartValue || 0;\nconst itemCount = item.itemCount || 0;\nconst checkoutUrl = item.checkoutUrl || '#';\nconst predictedReason = item.predictedReason || 'browsing';\n\n// Generate subject based on segment\nlet subject = `${customerName}, you left something behind!`;\nif (item.customerSegment === 'vip') {\n  subject = `${customerName}, your VIP cart is waiting \u2b50`;\n} else if (item.customerSegment === 'new') {\n  subject = `Complete your first order, ${customerName}!`;\n}\n\n// Generate email body\nconst emailBody = `\n<!DOCTYPE html>\n<html>\n<head>\n  <style>\n    body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }\n    .container { max-width: 600px; margin: 0 auto; padding: 20px; }\n    .header { background: #4CAF50; color: white; padding: 20px; text-align: center; }\n    .content { padding: 20px; background: #f9f9f9; }\n    .cta { display: inline-block; padding: 15px 30px; background: #4CAF50; color: white; text-decoration: none; border-radius: 5px; margin: 20px 0; }\n    .footer { text-align: center; padding: 20px; font-size: 12px; color: #666; }\n  </style>\n</head>\n<body>\n  <div class=\"container\">\n    <div class=\"header\">\n      <h1>Your Cart is Waiting!</h1>\n    </div>\n    <div class=\"content\">\n      <p>Hi ${customerName},</p>\n      <p>We noticed you left ${itemCount} item${itemCount > 1 ? 's' : ''} in your cart (total: $${cartValue.toFixed(2)}).</p>\n      <p>We've saved everything for you! Complete your order now before items sell out.</p>\n      <p style=\"text-align: center;\">\n        <a href=\"${checkoutUrl}\" class=\"cta\">Complete Your Order</a>\n      </p>\n      <p>Need help? Just reply to this email and we'll assist you right away.</p>\n      <p>Best regards,<br>Your Store Team</p>\n    </div>\n    <div class=\"footer\">\n      <p>You received this because you have items in your cart.</p>\n    </div>\n  </div>\n</body>\n</html>\n`;\n\nreturn {\n  json: {\n    ...item,\n    emailSubject: subject,\n    emailBody: emailBody,\n    touchpoint: 'email_1',\n    generatedAt: new Date().toISOString()\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "d8c4f4ab-136a-4c04-b9f6-79b7698b4ad1",
      "name": "Send Email 1",
      "type": "n8n-nodes-base.sendGrid",
      "position": [
        -2992,
        912
      ],
      "parameters": {
        "subject": "={{ $json.emailSubject }}",
        "toEmail": "={{ $json.customerEmail || $json.email }}",
        "resource": "mail",
        "fromEmail": "<__PLACEHOLDER_VALUE__Sender email address__>",
        "contentType": "text/html",
        "contentValue": "={{ $json.emailBody }}",
        "additionalFields": {}
      },
      "typeVersion": 1
    },
    {
      "id": "6b2a3b61-c910-4a15-be6a-ba57203b47a4",
      "name": "Log Email 1 Touchpoint",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -2832,
        912
      ],
      "parameters": {
        "columns": {
          "value": {
            "cart_id": "={{ $json.cart_id }}",
            "channel": "email",
            "ab_group": "={{ $json.abGroup }}",
            "timestamp": "={{ $now.toISO() }}",
            "customer_id": "={{ $json.customer_id }}",
            "touchpoint_type": "email_1"
          },
          "schema": [
            {
              "id": "cart_id",
              "required": false,
              "displayName": "cart_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "customer_id",
              "required": false,
              "displayName": "customer_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "touchpoint_type",
              "required": false,
              "displayName": "touchpoint_type",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "timestamp",
              "required": false,
              "displayName": "timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "channel",
              "required": false,
              "displayName": "channel",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "ab_group",
              "required": false,
              "displayName": "ab_group",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "cart_id"
          ]
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Touchpoints"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Workflow Configuration').first().json.googleSheetsId }}"
        },
        "authentication": "serviceAccount"
      },
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "f60cee52-ea2b-4320-b944-0f7dbbc5e873",
      "name": "Attribution - Email 1",
      "type": "n8n-nodes-base.code",
      "position": [
        -2656,
        912
      ],
      "parameters": {
        "jsCode": "// Attribution - Email 1: Track first touchpoint\nconst items = $input.all();\nconst results = [];\n\nfor (const item of items) {\n  results.push({\n    json: {\n      ...item.json,\n      attribution_touchpoint: 'email_1',\n      attribution_timestamp: new Date().toISOString(),\n      attribution_channel: 'email',\n      attribution_sequence: 1,\n      journey_touchpoints: [\n        {\n          id: 'email_1',\n          type: 'email',\n          timestamp: new Date().toISOString(),\n          status: 'sent'\n        }\n      ]\n    }\n  });\n}\n\nreturn results;"
      },
      "typeVersion": 2
    },
    {
      "id": "c16bc685-afa8-4757-9846-916f64bb0441",
      "name": "Wait Until 4 Hours",
      "type": "n8n-nodes-base.wait",
      "position": [
        -2400,
        656
      ],
      "parameters": {
        "unit": "hours",
        "amount": 4
      },
      "typeVersion": 1.1
    },
    {
      "id": "60b06474-9d7c-4cac-a284-887af6791057",
      "name": "Check Order Status (4h)",
      "type": "n8n-nodes-base.shopify",
      "position": [
        -2208,
        656
      ],
      "parameters": {
        "options": {},
        "orderId": "={{ $json.order_id || $json.cart_id }}",
        "operation": "get"
      },
      "typeVersion": 1
    },
    {
      "id": "0775ea03-bf48-45dc-a6b1-f2c7b09cc9ba",
      "name": "Check Order Completed (4h)",
      "type": "n8n-nodes-base.if",
      "position": [
        -2000,
        656
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "loose"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "id-1",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.financial_status }}",
              "rightValue": "paid"
            },
            {
              "id": "id-2",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.status }}",
              "rightValue": "completed"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "d9e7c858-3b17-4adf-a74d-516689624281",
      "name": "Prepare SMS Content",
      "type": "n8n-nodes-base.set",
      "position": [
        -1760,
        752
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "id-1",
              "name": "smsMessage",
              "type": "string",
              "value": "=Hi {{ $json.customerName }}! Your cart with {{ $json.itemCount }} items is waiting. Use code {{ $json.discountCode }} for {{ $json.discountPercent }}% off! {{ $json.checkoutUrl }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "62aaf0ff-fb0b-4667-a417-f9006ebc7afc",
      "name": "Send SMS with Discount",
      "type": "n8n-nodes-base.twilio",
      "position": [
        -1552,
        752
      ],
      "parameters": {
        "to": "={{ $json.customerPhone || $json.phone }}",
        "from": "<__PLACEHOLDER_VALUE__Twilio Phone Number__>",
        "message": "={{ $json.smsMessage }}",
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "96d01cc2-8522-4255-8d8b-1666c5a5d254",
      "name": "Log SMS Touchpoint",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -1360,
        752
      ],
      "parameters": {
        "columns": {
          "value": {
            "cart_id": "={{ $json.cart_id }}",
            "channel": "sms",
            "ab_group": "={{ $json.abGroup }}",
            "timestamp": "={{ $now.toISO() }}",
            "customer_id": "={{ $json.customer_id }}",
            "touchpoint_type": "sms"
          },
          "schema": [
            {
              "id": "cart_id",
              "required": false,
              "displayName": "cart_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "customer_id",
              "required": false,
              "displayName": "customer_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "touchpoint_type",
              "required": false,
              "displayName": "touchpoint_type",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "timestamp",
              "required": false,
              "displayName": "timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "channel",
              "required": false,
              "displayName": "channel",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "ab_group",
              "required": false,
              "displayName": "ab_group",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "cart_id"
          ]
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Touchpoints"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Workflow Configuration').first().json.googleSheetsId }}"
        },
        "authentication": "serviceAccount"
      },
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "fbe4c840-8a40-4cff-a5e5-41f3162ae7c1",
      "name": "Wait Until 24 Hours",
      "type": "n8n-nodes-base.wait",
      "position": [
        -1696,
        1200
      ],
      "parameters": {
        "unit": "hours",
        "amount": 24
      },
      "typeVersion": 1.1
    },
    {
      "id": "582cfd05-900a-4342-8b58-28ebc76a5f6e",
      "name": "Check Order Status (24h)",
      "type": "n8n-nodes-base.shopify",
      "position": [
        -1504,
        1200
      ],
      "parameters": {
        "options": {},
        "orderId": "={{ $json.order_id || $json.cart_id }}",
        "operation": "get"
      },
      "typeVersion": 1
    },
    {
      "id": "e637c2f3-eaf1-4275-92b3-85e8b97c38c1",
      "name": "Check Order Completed (24h)",
      "type": "n8n-nodes-base.if",
      "position": [
        -1264,
        1200
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "loose"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "id-1",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.financial_status }}",
              "rightValue": "paid"
            },
            {
              "id": "id-2",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.fulfillment_status }}",
              "rightValue": "completed"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "1d4afe20-f9e2-489a-b521-80b462403213",
      "name": "Generate Email 2 Content",
      "type": "n8n-nodes-base.code",
      "position": [
        -1024,
        1216
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Generate Email 2 Content - Social Proof Email\nconst item = $input.item.json;\n\nconst customerName = item.customerName || 'Valued Customer';\nconst cartValue = item.cartValue || 0;\nconst itemCount = item.itemCount || 0;\nconst checkoutUrl = item.checkoutUrl || '#';\nconst discountCode = item.discountCode || 'SAVE10';\nconst discountPercent = item.discountPercent || 10;\n\nconst subject = `${customerName}, join 50,000+ happy customers! \u2b50`;\n\nconst emailBody = `\n<!DOCTYPE html>\n<html>\n<head>\n  <style>\n    body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }\n    .container { max-width: 600px; margin: 0 auto; padding: 20px; }\n    .header { background: #FF6B6B; color: white; padding: 20px; text-align: center; }\n    .content { padding: 20px; background: #f9f9f9; }\n    .badge { display: inline-block; background: #FFD93D; color: #333; padding: 5px 10px; border-radius: 3px; font-weight: bold; margin: 5px; }\n    .testimonial { background: white; padding: 15px; margin: 15px 0; border-left: 4px solid #4CAF50; }\n    .cta { display: inline-block; padding: 15px 30px; background: #FF6B6B; color: white; text-decoration: none; border-radius: 5px; margin: 20px 0; font-size: 18px; }\n    .discount { background: #4CAF50; color: white; padding: 15px; text-align: center; font-size: 20px; font-weight: bold; margin: 20px 0; }\n  </style>\n</head>\n<body>\n  <div class=\"container\">\n    <div class=\"header\">\n      <h1>\ud83c\udf1f Your Items Are Bestsellers!</h1>\n    </div>\n    <div class=\"content\">\n      <p>Hi ${customerName},</p>\n      <p><span class=\"badge\">\u2b50 BESTSELLER</span> <span class=\"badge\">\ud83d\udd25 TRENDING</span></p>\n      <p>The ${itemCount} item${itemCount > 1 ? 's' : ''} in your cart are customer favorites with 4.8/5 star ratings!</p>\n      \n      <div class=\"testimonial\">\n        <p><em>\"Best purchase I've made this year! Quality exceeded expectations.\"</em></p>\n        <p><strong>- Sarah M., Verified Buyer</strong></p>\n      </div>\n      \n      <div class=\"testimonial\">\n        <p><em>\"Fast shipping and amazing product. Highly recommend!\"</em></p>\n        <p><strong>- James T., Verified Buyer</strong></p>\n      </div>\n      \n      <p><strong>Join 50,000+ happy customers who trust us!</strong></p>\n      \n      <div class=\"discount\">\n        \ud83c\udf81 EXCLUSIVE: ${discountPercent}% OFF with code ${discountCode}\n      </div>\n      \n      <p style=\"text-align: center;\">\n        <a href=\"${checkoutUrl}\" class=\"cta\">Complete Your Order Now</a>\n      </p>\n      \n      <p style=\"color: #FF6B6B; font-weight: bold;\">\u23f0 Your cart is reserved for 24 more hours only!</p>\n      \n      <p>Questions? Our support team is here to help 24/7.</p>\n    </div>\n  </div>\n</body>\n</html>\n`;\n\nreturn {\n  json: {\n    ...item,\n    emailSubject: subject,\n    emailBody: emailBody,\n    touchpoint: 'email_2',\n    generatedAt: new Date().toISOString()\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "c99a81a4-6200-4efb-bf08-7deaec9b64dd",
      "name": "Send Email 2",
      "type": "n8n-nodes-base.sendGrid",
      "position": [
        -848,
        1216
      ],
      "parameters": {
        "subject": "={{ $json.emailSubject }}",
        "toEmail": "={{ $json.customerEmail || $json.email }}",
        "resource": "mail",
        "fromEmail": "<__PLACEHOLDER_VALUE__Sender email address__>",
        "contentType": "text/html",
        "contentValue": "={{ $json.emailBody }}",
        "additionalFields": {}
      },
      "typeVersion": 1
    },
    {
      "id": "537b3a44-3679-48fd-a7c4-5034f7259e93",
      "name": "Log Email 2 Touchpoint",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -656,
        1216
      ],
      "parameters": {
        "columns": {
          "value": {
            "cart_id": "={{ $json.cart_id }}",
            "channel": "email",
            "ab_group": "={{ $json.abGroup }}",
            "timestamp": "={{ $now.toISO() }}",
            "customer_id": "={{ $json.customer_id }}",
            "touchpoint_type": "email_2"
          },
          "schema": [
            {
              "id": "cart_id",
              "required": false,
              "displayName": "cart_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "customer_id",
              "required": false,
              "displayName": "customer_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "touchpoint_type",
              "required": false,
              "displayName": "touchpoint_type",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "timestamp",
              "required": false,
              "displayName": "timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "channel",
              "required": false,
              "displayName": "channel",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "ab_group",
              "required": false,
              "displayName": "ab_group",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "cart_id"
          ]
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Touchpoints"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Workflow Configuration').first().json.googleSheetsId }}"
        },
        "authentication": "serviceAccount"
      },
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "b0d91f66-829e-4ed6-b457-c7f1c83714c9",
      "name": "Wait Until 48 Hours",
      "type": "n8n-nodes-base.wait",
      "position": [
        -400,
        1216
      ],
      "parameters": {
        "unit": "hours",
        "amount": 48
      },
      "typeVersion": 1.1
    },
    {
      "id": "86dafe3f-b0f2-435b-bf2a-77f8a922db27",
      "name": "Check Order Completed (48h)",
      "type": "n8n-nodes-base.if",
      "position": [
        -208,
        1216
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "loose"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "id-1",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.financial_status }}",
              "rightValue": "paid"
            },
            {
              "id": "id-2",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.fulfillment_status }}",
              "rightValue": "completed"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "1e23dd15-87cd-4a76-96ff-44bcd584db95",
      "name": "Generate WhatsApp Message",
      "type": "n8n-nodes-base.code",
      "position": [
        0,
        1312
      ],
      "parameters": {
        "jsCode": "// Generate WhatsApp Message - Final touchpoint\nconst items = $input.all();\nconst results = [];\n\nfor (const item of items) {\n  const customerName = item.json.customerName || 'there';\n  const discountCode = item.json.discountCode || 'SAVE10';\n  const discountPercent = item.json.discountPercent || 10;\n  const checkoutUrl = item.json.checkoutUrl || '#';\n  \n  const message = `Hi ${customerName}! \ud83d\udc4b Last chance to complete your order with ${discountPercent}% off using code ${discountCode}. We've addressed common concerns - free shipping, easy returns, secure checkout. Complete now: ${checkoutUrl}`;\n  \n  results.push({\n    json: {\n      ...item.json,\n      whatsappMessage: message,\n      touchpoint: 'whatsapp',\n      generatedAt: new Date().toISOString()\n    }\n  });\n}\n\nreturn results;"
      },
      "typeVersion": 2
    },
    {
      "id": "87950621-7664-485b-9a58-2e5ff8f4282e",
      "name": "Send WhatsApp Message",
      "type": "n8n-nodes-base.whatsApp",
      "position": [
        192,
        1312
      ],
      "parameters": {
        "template": "abandoned_cart_final",
        "phoneNumberId": "={{ $env.WHATSAPP_PHONE_NUMBER_ID }}",
        "recipientPhoneNumber": "={{ $json.customerPhone || $json.phone }}"
      },
      "typeVersion": 1.1
    },
    {
      "id": "68396f90-df47-4791-a66b-750747145722",
      "name": "Add to Retargeting Audience",
      "type": "n8n-nodes-base.facebookGraphApi",
      "position": [
        608,
        1312
      ],
      "parameters": {
        "edge": "users",
        "node": "={{ $env.FACEBOOK_CUSTOM_AUDIENCE_ID }}",
        "options": {
          "queryParametersJson": "={{ { 'payload': { 'schema': ['EMAIL', 'PHONE'], 'data': [[$json.hashedEmail, $json.hashedPhone]] } } }}"
        },
        "graphApiVersion": "v18.0",
        "httpRequestMethod": "POST"
      },
      "credentials": {
        "facebookGraphApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "3c357ffd-ac8b-48c1-a818-b146eb0c2ced",
      "name": "Merge Attribution Data",
      "type": "n8n-nodes-base.merge",
      "position": [
        -2400,
        1088
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "fieldsToMatchString": "cart_id"
      },
      "typeVersion": 3.2
    },
    {
      "id": "413e1e34-57b7-4297-bcc5-8d90298185ad",
      "name": "Notify High-Value Recovery",
      "type": "n8n-nodes-base.slack",
      "position": [
        -1952,
        1088
      ],
      "parameters": {
        "text": "=\ud83c\udfaf High-value cart recovered!\n\nCart ID: {{ $json.cart_id }}\nCustomer: {{ $json.customerEmail }}\nValue: ${{ $json.subtotal }}\nSegment: {{ $json.customerSegment }}\nTouchpoints: {{ $json.journey_touchpoints?.length || 'N/A' }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $env.SLACK_CHANNEL_NAME }}"
        },
        "otherOptions": {}
      },
      "typeVersion": 2.3
    },
    {
      "id": "f1669543-ea4d-42e4-bb72-6b06b9a05838",
      "name": "Check Cart Value Threshold",
      "type": "n8n-nodes-base.if",
      "position": [
        -2176,
        1088
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "id-1",
              "operator": {
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{ $json.subtotal }}",
              "rightValue": "={{ $('Workflow Configuration').first().json.highValueThreshold }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "fce23508-83d3-4a6c-9ec4-24f0492b0373",
      "name": "Customer Segment Check",
      "type": "n8n-nodes-base.if",
      "position": [
        -4272,
        816
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "id-1",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.customerSegment }}",
              "rightValue": "new"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "b22392a5-9eab-4191-9ee0-5e43c4a93b68",
      "name": "Device Type Check",
      "type": "n8n-nodes-base.if",
      "position": [
        -4048,
        816
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "loose"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "id-1",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.device }}",
              "rightValue": "mobile"
            },
            {
              "id": "id-2",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.device }}",
              "rightValue": "tablet"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "e0caac6b-4ccb-43fb-a424-2461dc408103",
      "name": "Mark Success - Order Completed (1h)",
      "type": "n8n-nodes-base.set",
      "position": [
        -3184,
        720
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "id-1",
              "name": "recovery_status",
              "type": "string",
              "value": "completed_at_1h"
            },
            {
              "id": "id-2",
              "name": "recovery_timestamp",
              "type": "string",
              "value": "={{ $now.toISO() }}"
            },
            {
              "id": "id-3",
              "name": "recovery_touchpoint",
              "type": "string",
              "value": "none"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "6a6a02ba-452f-47d1-b84d-a6860e6ac2bb",
      "name": "Mark Success - Order Completed (4h)",
      "type": "n8n-nodes-base.set",
      "position": [
        -1760,
        560
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "id-1",
              "name": "recovery_status",
              "type": "string",
              "value": "completed_at_4h"
            },
            {
              "id": "id-2",
              "name": "recovery_timestamp",
              "type": "string",
              "value": "={{ $now.toISO() }}"
            },
            {
              "id": "id-3",
              "name": "recovery_touchpoint",
              "type": "string",
              "value": "email_1"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "46ffac66-0c1b-451b-adb9-924d3b070728",
      "name": "Mark Success - Order Completed (24h)",
      "type": "n8n-nodes-base.set",
      "position": [
        -1024,
        1040
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "id-1",
              "name": "recovery_status",
              "type": "string",
              "value": "completed_at_24h"
            },
            {
              "id": "id-2",
              "name": "recovery_timestamp",
              "type": "string",
              "value": "={{ $now.toISO() }}"
            },
            {
              "id": "id-3",
              "name": "recovery_touchpoint",
              "type": "string",
              "value": "sms"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "1dd40762-ebc5-493a-8263-72e0b506865c",
      "name": "Mark Success - Order Completed (48h)",
      "type": "n8n-nodes-base.set",
      "position": [
        0,
        1120
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "id-1",
              "name": "recovery_status",
              "type": "string",
              "value": "completed_at_48h"
            },
            {
              "id": "id-2",
              "name": "recovery_timestamp",
              "type": "string",
              "value": "={{ $now.toISO() }}"
            },
            {
              "id": "id-3",
              "name": "recovery_touchpoint",
              "type": "string",
              "value": "email_2"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "d94b879e-70a0-441c-b6b0-a0caae8a165c",
      "name": "Merge Attribution - SMS",
      "type": "n8n-nodes-base.code",
      "position": [
        -1152,
        752
      ],
      "parameters": {
        "jsCode": "// Merge Attribution - SMS: Add SMS touchpoint to journey\nconst items = $input.all();\nconst results = [];\n\nfor (const item of items) {\n  const data = item.json;\n  \n  // Get existing journey touchpoints or initialize\n  const journeyTouchpoints = data.journey_touchpoints || [];\n  \n  // Add SMS touchpoint\n  journeyTouchpoints.push({\n    id: 'sms',\n    type: 'sms',\n    timestamp: new Date().toISOString(),\n    status: 'sent',\n    discount_code: data.discountCode,\n    discount_percent: data.discountPercent\n  });\n  \n  results.push({\n    json: {\n      ...data,\n      journey_touchpoints: journeyTouchpoints,\n      attribution_touchpoint: 'sms',\n      attribution_timestamp: new Date().toISOString(),\n      attribution_channel: 'sms',\n      attribution_sequence: journeyTouchpoints.length,\n      last_touchpoint: 'sms'\n    }\n  });\n}\n\nreturn results;"
      },
      "typeVersion": 2
    },
    {
      "id": "28105702-e993-435d-a115-451b0cdad347",
      "name": "Merge Attribution - Email 2",
      "type": "n8n-nodes-base.code",
      "position": [
        -656,
        1456
      ],
      "parameters": {
        "jsCode": "// Merge Attribution - Email 2: Add Email 2 touchpoint to journey\nconst items = $input.all();\nconst results = [];\n\nfor (const item of items) {\n  const existingTouchpoints = item.json.journey_touchpoints || [];\n  \n  // Add Email 2 touchpoint\n  const updatedTouchpoints = [\n    ...existingTouchpoints,\n    {\n      id: 'email_2',\n      type: 'email',\n      timestamp: new Date().toISOString(),\n      status: 'sent'\n    }\n  ];\n  \n  results.push({\n    json: {\n      ...item.json,\n      attribution_touchpoint: 'email_2',\n      attribution_timestamp: new Date().toISOString(),\n      attribution_channel: 'email',\n      attribution_sequence: updatedTouchpoints.length,\n      journey_touchpoints: updatedTouchpoints\n    }\n  });\n}\n\nreturn results;"
      },
      "typeVersion": 2
    },
    {
      "id": "182084ce-93de-4d45-b100-e6c0218b2e87",
      "name": "Merge Attribution - WhatsApp",
      "type": "n8n-nodes-base.code",
      "position": [
        800,
        1312
      ],
      "parameters": {
        "jsCode": "// Merge Attribution - WhatsApp: Track WhatsApp touchpoint\nconst items = $input.all();\nconst results = [];\n\nfor (const item of items) {\n  const existingTouchpoints = item.json.journey_touchpoints || [];\n  \n  // Add WhatsApp touchpoint to journey\n  const updatedTouchpoints = [\n    ...existingTouchpoints,\n    {\n      id: 'whatsapp',\n      type: 'whatsapp',\n      timestamp: new Date().toISOString(),\n      status: 'sent'\n    }\n  ];\n  \n  results.push({\n    json: {\n      ...item.json,\n      attribution_touchpoint: 'whatsapp',\n      attribution_timestamp: new Date().toISOString(),\n      attribution_channel: 'whatsapp',\n      attribution_sequence: updatedTouchpoints.length,\n      journey_touchpoints: updatedTouchpoints\n    }\n  });\n}\n\nreturn results;"
      },
      "typeVersion": 2
    },
    {
      "id": "549131f5-1dba-4f46-ad89-ebcd87213891",
      "name": "Hash Customer Data for Facebook",
      "type": "n8n-nodes-base.code",
      "position": [
        400,
        1312
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Hash Customer Data for Facebook Custom Audience API\nconst crypto = require('crypto');\n\nconst item = $input.item.json;\n\n// Function to hash data with SHA256\nfunction hashSHA256(data) {\n  if (!data) return '';\n  return crypto.createHash('sha256').update(data.toLowerCase().trim()).digest('hex');\n}\n\n// Hash email and phone\nconst hashedEmail = hashSHA256(item.customerEmail || item.email || '');\nconst hashedPhone = hashSHA256(item.customerPhone || item.phone || '');\n\nreturn {\n  json: {\n    ...item,\n    hashedEmail: hashedEmail,\n    hashedPhone: hashedPhone,\n    facebookPayload: {\n      schema: ['EMAIL', 'PHONE'],\n      data: [[hashedEmail, hashedPhone]]\n    },\n    hashedAt: new Date().toISOString()\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "22be27bd-d0b3-488c-bb41-4a834fab5bed",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -4864,
        80
      ],
      "parameters": {
        "width": 1008,
        "height": 464,
        "content": "## How it works\nThis workflow recovers abandoned carts using a timed, multi-channel sequence (Email \u2192 SMS \u2192 Email \u2192 WhatsApp) and logs every touchpoint for multi-touch attribution.\n\nWhen a cart is abandoned, the workflow normalizes the incoming payload, fetches cart details and customer purchase history, then predicts the most likely abandonment reason. A personalization step segments the customer (new/returning/vip), assigns an A/B group, generates a discount and checkout URL, and applies basic routing rules (segment and device checks).\n\nThe sequence starts with a 1-hour wait, then checks if the order was completed. If not recovered, it sends Email #1, logs the touchpoint to Google Sheets, and initializes the attribution journey. After additional waits (4h, 24h, 48h), it re-checks order status and sends follow-ups: an SMS with discount, Email #2 with social proof/urgency, and a final WhatsApp reminder. Each message is logged and appended to the journey touchpoints.\n\nIf the cart is still not recovered after the final step, the workflow hashes customer identifiers and adds them to a Facebook Custom Audience for retargeting. Finally, it merges attribution data and triggers a Slack notification for high-value recovered carts.\n\n## Setup steps\n1. Configure API URLs, Shopify domain, Sheets ID, and high-value threshold in **Workflow Configuration**.\n2. Connect Shopify, SendGrid, Twilio, WhatsApp, Facebook Graph API, Google Sheets, and Slack credentials.\n3. Create a \u201cTouchpoints\u201d sheet with the required columns and test with a sample cart payload.\n4. Enable the webhook after validating message sends and logging."
      },
      "typeVersion": 1
    },
    {
      "id": "d50e1660-2c7d-40c7-8e4a-b5ec068824ff",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -5360,
        80
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 272,
        "content": "## Intake & Configuration\nReceives the abandoned cart event and loads global settings (API URLs, Shopify domain, Sheets ID, high-value threshold) used across the workflow."
      },
      "typeVersion": 1
    },
    {
      "id": "5765c821-090b-42fb-810e-9d940539cc72",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -5360,
        624
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 432,
        "content": "## Normalize & Enrich Cart Data\nNormalizes the incoming cart payload and fetches full cart details and customer purchase history to build a complete recovery context."
      },
      "typeVersion": 1
    },
    {
      "id": "54dc8d9f-354a-460f-af5a-8e93df8e25cd",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -4864,
        624
      ],
      "parameters": {
        "color": 7,
        "width": 448,
        "height": 432,
        "content": "## Reason Prediction & Personalization\nPredicts the likely abandonment reason, segments the customer, assigns A/B group, calculates a discount, and builds a checkout URL for personalized messaging."
      },
      "typeVersion": 1
    },
    {
      "id": "7d49d894-3526-491d-8014-e3017a2ee754",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -3776,
        624
      ],
      "parameters": {
        "color": 7,
        "width": 1248,
        "height": 432,
        "content": "## 1h Checkpoint & Email 1\nWaits 1 hour, checks if the order was completed, and if not, generates and sends the first email reminder. Logs the send as the first attribution touchpoint."
      },
      "typeVersion": 1
    },
    {
      "id": "302de9e4-99b1-49f8-9088-ab239bc7077b",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -4336,
        624
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 432,
        "content": "## Routing Rules\nApplies simple routing logic based on customer segment and device type before starting the timed recovery sequence."
      },
      "typeVersion": 1
    },
    {
      "id": "858bd62a-01f8-4f74-bdbd-dbe6ed0c95f7",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -464,
        960
      ],
      "parameters": {
        "color": 7,
        "width": 1664,
        "height": 672,
        "content": "## 48h Final Touchpoint & Retargeting\nAt 48 hours, checks completion one last time. If still not recovered, sends a final WhatsApp reminder, hashes customer identifiers, and adds the user to a Facebook Custom Audience for retargeting."
      },
      "typeVersion": 1
    },
    {
      "id": "24f3d943-5a26-4169-a1fd-20228725663b",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2448,
        480
      ],
      "parameters": {
        "color": 7,
        "width": 1456,
        "height": 432,
        "content": "## 4h Checkpoint & SMS\nAfter additional waiting, re-checks order completion. If still not recovered, sends an SMS with a personalized discount and logs the SMS touchpoint."
      },
      "typeVersion": 1
    },
    {
      "id": "086c5390-aaa0-455b-9c5c-e2d4dfb97bea",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2448,
        960
      ],
      "parameters": {
        "color": 7,
        "width": 672,
        "height": 304,
        "content": "## Attribution Merge & High-Value Alert\nMerges touchpoints into a single journey record and triggers a Slack notification when a recovered cart exceeds the configured high-value threshold."
      },
      "typeVersion": 1
    },
    {
      "id": "2a06a916-dadb-444f-9843-e30ff45bc81b",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1744,
        960
      ],
      "parameters": {
        "color": 7,
        "width": 1232,
        "height": 672,
        "content": "## 24h Checkpoint & Email 2\nWaits until 24 hours, checks again for completion, and sends a second email focused on social proof and urgency. Logs the touchpoint and updates attribution."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "675f7830-80ba-497e-bfa1-a10715cae9ad",
  "connections": {
    "Wait 1 Hour": {
      "main": [
        [
          {
            "node": "Check Order Status (1h)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Email 1": {
      "main": [
        [
          {
            "node": "Log Email 1 Touchpoint",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Email 2": {
      "main": [
        [
          {
            "node": "Log Email 2 Touchpoint",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Device Type Check": {
      "main": [
        [
          {
            "node": "Wait 1 Hour",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Cart Details": {
      "main": [
        [
          {
            "node": "Predict Abandonment Reason",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log SMS Touchpoint": {
      "main": [
        [
          {
            "node": "Wait Until 24 Hours",
            "type": "main",
            "index": 0
          },
          {
            "node": "Merge Attribution - SMS",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait Until 4 Hours": {
      "main": [
        [
          {
            "node": "Check Order Status (4h)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Cart Data": {
      "main": [
        [
          {
            "node": "Fetch Cart Details",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch Customer History",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare SMS Content": {
      "main": [
        [
          {
            "node": "Send SMS with Discount",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait Until 24 Hours": {
      "main": [
        [
          {
            "node": "Check Order Status (24h)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait Until 48 Hours": {
      "main": [
        [
          {
            "node": "Check Order Completed (48h)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Attribution - Email 1": {
      "main": [
        [
          {
            "node": "Wait Until 4 Hours",
            "type": "main",
            "index": 0
          },
          {
            "node": "Merge Attribution Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send WhatsApp Message": {
      "main": [
        [
          {
            "node": "Hash Customer Data for Facebook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Abandoned Cart Webhook": {
      "main": [
        [
          {
            "node": "Workflow Configuration",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Customer Segment Check": {
      "main": [
        [
          {
            "node": "Device Type Check",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Customer History": {
      "main": [
        [
          {
            "node": "Predict Abandonment Reason",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Email 1 Touchpoint": {
      "main": [
        [
          {
            "node": "Attribution - Email 1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Email 2 Touchpoint": {
      "main": [
        [
          {
            "node": "Wait Until 48 Hours",
            "type": "main",
            "index": 0
          },
          {
            "node": "Merge Attribution - Email 2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Attribution Data": {
      "main": [
        [
          {
            "node": "Check Cart Value Threshold",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Personalization Engine": {
      "main": [
        [
          {
            "node": "Customer Segment Check",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send SMS with Discount": {
      "main": [
        [
          {
            "node": "Log SMS Touchpoint",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Workflow Configuration": {
      "main": [
        [
          {
            "node": "Normalize Cart Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Order Status (

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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow is a complete, production-ready solution for recovering abandoned carts in Shopify stores using a multi-channel, multi-touch approach. It automates personalized follow-ups via Email, SMS, and WhatsApp, tracks every customer interaction for multi-touch attribution,…

Source: https://n8n.io/workflows/11805/ — original creator credit. Request a take-down →

More Slack & Telegram workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Slack & Telegram

This workflow is essential for dropshippers, e-commerce store owners, and anyone looking to quickly import product catalogs from specific websites into their Shopify store.

Shopify, Slack, HTTP Request +2
Slack & Telegram

Turn every sales meeting into a coaching opportunity. This workflow automatically analyzes tldv meeting recordings using OpenAI (GPT-4) to provide instant, actionable feedback to your sales team.

HTTP Request, Slack, Google Sheets
Slack & Telegram

Automated video processing system that monitors S3 for new uploads, generates thumbnails and preview clips, extracts metadata, transcodes to multiple formats, and distributes to CDN with webhook notif

HTTP Request, Google Sheets, Slack
Slack & Telegram

Eliminate manual data entry from your accounts payable process. This workflow transforms raw invoice scans into structured financial records by combining UploadToURL for hosting, AWS Textract for OCR

N8N Nodes Uploadtourl, HTTP Request, Google Sheets +1
Slack & Telegram

Connect Fireflies and WayinVideo to this workflow once and every recorded sales call automatically generates a set of training clips delivered to your Slack channel. The moment Fireflies finishes tran

HTTP Request, Google Sheets, Slack