{
  "id": "43ryN3lwAYRLOkns",
  "name": "Abandoned Cart Recovery for Event Registration TEMPLATE",
  "tags": [],
  "nodes": [
    {
      "id": "4a3e4453-8e78-4187-bc38-855cfc76851a",
      "name": "Run Every 4 Hours",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -1120,
        400
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 4
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "7d4a1b09-7215-4bbe-9918-cf48f6001926",
      "name": "Query Incomplete Registrations",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -880,
        400
      ],
      "parameters": {
        "url": "https://milobravo1.app.n8n.cloud/api/v1/data-tables/PLACEHOLDER_REGISTRATIONS_TABLE_ID/rows",
        "options": {
          "timeout": 10000
        },
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "limit",
              "value": "100"
            },
            {
              "name": "filter",
              "value": "status=started"
            }
          ]
        }
      },
      "typeVersion": 4.2,
      "continueOnFail": true
    },
    {
      "id": "df39e8cd-88ea-4660-90e2-c05665e1bbd9",
      "name": "Calculate Recovery Stage",
      "type": "n8n-nodes-base.code",
      "position": [
        -672,
        400
      ],
      "parameters": {
        "jsCode": "// Calculate time since registration started and determine recovery stage\nconst items = $input.all();\nconst now = Date.now();\n\nconst results = [];\n\nfor (const item of items) {\n  const startedAt = new Date(item.json.created_at).getTime();\n  const hoursElapsed = (now - startedAt) / (1000 * 60 * 60);\n  const email = item.json.email || '';\n\n  // Skip if no email was captured (beacon-only, no way to contact)\n  if (!email) continue;\n\n  // Determine recovery stage\n  let stage = null;\n  let subject = '';\n  let urgency = '';\n\n  if (hoursElapsed >= 1 && hoursElapsed < 6) {\n    stage = '1h';\n    subject = 'Almost done! Complete your registration';\n    urgency = 'low';\n  } else if (hoursElapsed >= 24 && hoursElapsed < 48) {\n    stage = '24h';\n    subject = \"Don't miss out \u2014 spots are filling up\";\n    urgency = 'medium';\n  } else if (hoursElapsed >= 72 && hoursElapsed < 96) {\n    stage = '72h';\n    subject = 'Last chance to register at this price';\n    urgency = 'high';\n  }\n\n  // Skip if not in a recovery window or already handled\n  if (!stage) continue;\n\n  // Check if we've already sent this stage\n  const sentStages = (item.json.recovery_stages_sent || '').split(',').map(s => s.trim());\n  if (sentStages.includes(stage)) continue;\n\n  results.push({\n    json: {\n      ...item.json,\n      hours_elapsed: Math.round(hoursElapsed),\n      recovery_stage: stage,\n      email_subject: subject,\n      urgency,\n      reg_id: item.json.id || item.json.reg_id\n    }\n  });\n}\n\nif (results.length === 0) {\n  return [{ json: { empty: true, message: 'No carts to recover' } }];\n}\n\nreturn results;"
      },
      "typeVersion": 2
    },
    {
      "id": "75f8343c-786b-4936-aeef-31a7411132a7",
      "name": "Has Carts to Recover?",
      "type": "n8n-nodes-base.if",
      "position": [
        -464,
        400
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "operator": {
                "type": "boolean",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.empty }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "e30f18f0-2f36-4110-80f2-0ecc81fb655e",
      "name": "Route by Recovery Stage",
      "type": "n8n-nodes-base.switch",
      "position": [
        -256,
        384
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "Nudge (1h)",
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.recovery_stage }}",
                    "rightValue": "1h"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Social Proof (24h)",
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.recovery_stage }}",
                    "rightValue": "24h"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Last Chance (72h)",
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.recovery_stage }}",
                    "rightValue": "72h"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {
          "allMatchingOutputs": false
        }
      },
      "typeVersion": 3.2
    },
    {
      "id": "d068e09c-7d2c-4ef9-a960-a6106bfbaa88",
      "name": "Send Nudge Email (1h)",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        48,
        208
      ],
      "parameters": {
        "options": {},
        "subject": "={{ $json.email_subject }}"
      },
      "typeVersion": 2.1,
      "continueOnFail": true
    },
    {
      "id": "4effc98c-ad94-4580-a87b-86c061de5e13",
      "name": "Send Social Proof Email (24h)",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        48,
        400
      ],
      "parameters": {
        "options": {},
        "subject": "={{ $json.email_subject }}"
      },
      "typeVersion": 2.1,
      "continueOnFail": true
    },
    {
      "id": "8d56d5eb-c650-4133-bdcb-5b069dd659b4",
      "name": "Send Last Chance Email (72h)",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        48,
        608
      ],
      "parameters": {
        "options": {},
        "subject": "={{ $json.email_subject }}"
      },
      "typeVersion": 2.1,
      "continueOnFail": true
    },
    {
      "id": "a44572e1-2d62-4c8c-99e8-3a52845dbe15",
      "name": "Log Recovery Event",
      "type": "n8n-nodes-base.code",
      "position": [
        368,
        400
      ],
      "parameters": {
        "jsCode": "// Log that we sent a recovery email for this stage\nconst item = $input.first().json;\n\nreturn [{\n  json: {\n    reg_id: item.reg_id,\n    stage: item.recovery_stage,\n    email: item.email,\n    sent_at: new Date().toISOString(),\n    event_id: item.event_id\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "48915d3c-dc42-4efe-a2ad-1eabab0ceef2",
      "name": "Log to Cart Recovery Table",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        544,
        400
      ],
      "parameters": {
        "columns": {
          "mappingMode": "autoMapInputData"
        },
        "options": {},
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "PLACEHOLDER_CART_RECOVERY_TABLE_ID"
        }
      },
      "typeVersion": 1,
      "continueOnFail": true
    },
    {
      "id": "sticky-intro-cart",
      "name": "Intro \u2014 Abandoned Cart",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1808,
        112
      ],
      "parameters": {
        "width": 600,
        "height": 720,
        "content": "## Abandoned Cart Monitor\n\n### **What it does:**\nDetects incomplete registrations and sends a 3-stage recovery email sequence (1h nudge \u2192 24h social proof \u2192 72h last chance) to recover abandoned carts.\n\n### **Why it matters:**\nFight for every abandoned cart like there is no tomorrow. 6-7 page forms see 80-90% drop-off. Even with our minimal 4-field form, some registrants will abandon \u2014 this recovers them.\n\n### **How it works:**\n1. Runs every 4 hours via schedule trigger\n2. Queries registrations with `status = started` (beacon fired, no submit)\n3. Calculates time since start to determine recovery stage\n4. Sends stage-appropriate email with increasing urgency\n5. Logs recovery attempts to prevent duplicate sends\n\n### **Setup steps:**\n1. Update `PLACEHOLDER_REGISTRATIONS_TABLE_ID`\n2. Update `PLACEHOLDER_CART_RECOVERY_TABLE_ID`\n3. Update `PLACEHOLDER_REG_URL` in email templates\n4. Configure email credentials\n5. Activate the workflow"
      },
      "typeVersion": 1
    },
    {
      "id": "sticky-sequence",
      "name": "Section \u2014 Email Sequence",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -96,
        -80
      ],
      "parameters": {
        "color": 5,
        "width": 412,
        "height": 860,
        "content": "## Email Recovery Sequence\n\n**1h \u2014 Nudge:** Friendly reminder, takes 30 seconds to finish\n**24h \u2014 Social Proof:** \"47 more professionals registered since you left\"\n**72h \u2014 Last Chance:** Price increase urgency, scarcity messaging\n\nPer Julius: \"No urgency, no sale\" + \"Remarketing is essential\"\n\nEach email links directly back to the reg form with the session pre-loaded."
      },
      "typeVersion": 1
    },
    {
      "id": "0a9c0a0e-4ca5-4e2b-9365-286b0d662e1b",
      "name": "Contact \u2014 Braia Labs1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        752,
        16
      ],
      "parameters": {
        "width": 560,
        "height": 1160,
        "content": "## Was this helpful? Get in touch!\n\n[![clic](https://vptkuqoipqbebipqjnqw.supabase.co/storage/v1/object/public/Milo%20Bravo/seeAxWUupcOOXY5tntexZ_video.gif)](https://tally.so/r/EkKGgB)\n\nI really hope this automation helped you. Your feedback is incredibly valuable and helps me create better resources for business and the n8n community.\n\n### **Have Feedback, a Question, or a Project Idea?**\n\nI've streamlined the way we connect. It all starts with one simple form that takes less than 10 seconds. After that, you'll chat with my AI assistant who will gather the key details and pass them directly on to me.\n\n####  **[Start the conversation here](https://tally.so/r/EkKGgB)**\n\n*   **Give Feedback:** Share your thoughts on this template\u2014whether you found a typo, encountered an unexpected error, have a suggestion, or just want to say thanks!\n\n*   **n8n Consulting:** Have a complex business challenge or need a custom workflow built from scratch? Let's partner on a powerful automation solution tailored to your specific needs.\n\n*   **Join your team:** We can work together to get you launched with confidence.\n\n---\n\nHappy Automating!\n[Milo Bravo](https://linkedin.com/in/MiloBravo/) | BRaiA Labs | Automation & BI Systems + AI Integration"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "callerPolicy": "workflowsFromSameOwner",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "03f19725-a446-49df-9911-54fbb5eceae0",
  "connections": {
    "Run Every 4 Hours": {
      "main": [
        [
          {
            "node": "Query Incomplete Registrations",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Recovery Event": {
      "main": [
        [
          {
            "node": "Log to Cart Recovery Table",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has Carts to Recover?": {
      "main": [
        [
          {
            "node": "Route by Recovery Stage",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "Send Nudge Email (1h)": {
      "main": [
        [
          {
            "node": "Log Recovery Event",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route by Recovery Stage": {
      "main": [
        [
          {
            "node": "Send Nudge Email (1h)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send Social Proof Email (24h)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send Last Chance Email (72h)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculate Recovery Stage": {
      "main": [
        [
          {
            "node": "Has Carts to Recover?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Last Chance Email (72h)": {
      "main": [
        [
          {
            "node": "Log Recovery Event",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Social Proof Email (24h)": {
      "main": [
        [
          {
            "node": "Log Recovery Event",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Query Incomplete Registrations": {
      "main": [
        [
          {
            "node": "Calculate Recovery Stage",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}