Build an Abandoned Cart Recovery System That Recovers 20% of Lost Sales
Quick win: Recover 15-25% of abandoned carts with automated 3-email sequence. Typical store recovers $500-2,000/month.
Here’s the complete system.
The Numbers
Average cart abandonment rate: 69.8% Recovery rate with good sequence: 15-25% Average order value: $100
Monthly calculation (100 carts/month):
100 carts × 69.8% abandoned = 70 abandoned carts
70 × 20% recovered = 14 recovered orders
14 × $100 AOV = $1,400 recovered revenue
Cost to build: $0 (n8n + SendGrid free tiers)
The 3-Email Sequence
Email 1: Reminder (1 hour after abandonment)
Subject: “You left something in your cart”
Content:
- Remind what they left behind
- Show product images
- Single CTA: “Complete Your Purchase”
- NO discount yet
Conversion rate: 30-40% of recoveries
Email 2: Social Proof + Urgency (24 hours)
Subject: “Still thinking it over? Here’s what others say”
Content:
- Customer reviews/testimonials
- Limited stock warning (if true)
- Free shipping reminder
- CTA: “Claim Your Items”
Conversion rate: 40-50% of recoveries
Email 3: Discount Offer (72 hours)
Subject: “Here’s 10% off to complete your order”
Content:
- 10% discount code
- Expires in 48 hours
- Highlight value proposition
- Final CTA
Conversion rate: 20-30% of recoveries
Total sequence recovery: 15-25% of abandoned carts
n8n Workflow Architecture
Schedule (hourly check)
→ Query store API (abandoned carts > 1 hour)
→ Filter (not yet contacted)
→ Branch by time abandoned:
→ 1-2 hours: Send Email 1
→ 24-48 hours: Send Email 2
→ 72-120 hours: Send Email 3
→ Mark as contacted
→ Log to Google Sheets
Step-by-Step Setup
Step 1: Create Google Sheet for Tracking
Columns:
- Cart ID
- Customer Email
- Customer Name
- Cart Value
- Abandoned At
- Email 1 Sent (date)
- Email 2 Sent (date)
- Email 3 Sent (date)
- Recovered (yes/no)
- Recovery Date
- Recovery Value
Step 2: Build n8n Workflow
Node 1: Schedule Trigger
Cron: 0 * * * * (every hour)
Node 2: HTTP Request (Get Abandoned Carts)
For Shopify:
Method: GET
URL: https://your-store.myshopify.com/admin/api/2024-01/checkouts.json
Headers:
- X-Shopify-Access-Token: YOUR_TOKEN
Parameters:
- status: open
- created_at_min: (2 hours ago)
For DashNex:
Method: GET
URL: https://your-dashnex-store.com/api/abandoned-carts
Headers:
- Authorization: Bearer YOUR_API_KEY
Node 3: Filter Node
Filter carts that haven’t been contacted yet:
const cart = $json;
const hoursSince = (Date.now() - new Date(cart.abandoned_at)) / (1000 * 60 * 60);
// Only process carts 1-120 hours old
return hoursSince >= 1 && hoursSince <= 120;
Node 4: Google Sheets Lookup
Check if cart already in tracking sheet:
Operation: Lookup
Column: Cart ID
Value: \{\{$json.id\}\}
Node 5: Switch Node (Route by Time)
Route 1: 1-2 hours since abandonment
Route 2: 24-26 hours since abandonment
Route 3: 72-74 hours since abandonment
Default: Skip (already contacted)
Node 6a: SendGrid (Email 1)
Template ID: abandoned-cart-reminder
To: \{\{$json.customer_email\}\}
Dynamic Data:
- customer_name: \{\{$json.customer_name\}\}
- cart_items: \{\{$json.items\}\}
- cart_total: \{\{$json.total\}\}
- cart_url: \{\{$json.recovery_url\}\}
Node 6b: SendGrid (Email 2)
Template ID: abandoned-cart-social-proof
Dynamic Data:
- customer_name
- cart_items
- testimonials: (pull from database)
- cart_url
Node 6c: SendGrid (Email 3)
Template ID: abandoned-cart-discount
Dynamic Data:
- customer_name
- cart_items
- discount_code: \{\{$json.discount_code\}\}
- expiry_date: (calculate: now + 48 hours)
- cart_url
Node 7: Google Sheets Update
Log which email was sent:
Operation: Append or Update
Columns:
- Cart ID
- Email 1/2/3 Sent: Current timestamp
Email Templates
Template 1: Reminder
<!DOCTYPE html>
<html>
<body>
<h2>Hi \{\{customer_name\}\},</h2>
<p>You left these items in your cart:</p>
\{\{#each cart_items\}\}
<div>
<img src="\{\{image_url\}\}" width="100">
<h3>\{\{name\}\}</h3>
<p>$\{\{price\}\}</p>
</div>
\{\{/each\}\}
<p><strong>Total: $\{\{cart_total\}\}</strong></p>
<a href="\{\{cart_url\}\}" style="background: #007bff; color: white; padding: 12px 24px; text-decoration: none;">
Complete Your Purchase
</a>
<p>Questions? Reply to this email.</p>
</body>
</html>
Template 2: Social Proof
<h2>Still thinking it over, \{\{customer_name\}\}?</h2>
<p>Here's what other customers say:</p>
<blockquote>
"Best purchase I've made this year!" - Sarah M.
</blockquote>
<blockquote>
"Exceeded my expectations." - John D.
</blockquote>
<p><strong>Only 3 left in stock!</strong> Secure yours now.</p>
<a href="\{\{cart_url\}\}">Claim Your Items</a>
Template 3: Discount
<h2>\{\{customer_name\}\}, here's 10% off</h2>
<p>We want to make this easy for you.</p>
<div style="background: #f0f0f0; padding: 20px; text-align: center;">
<h3>Use code: \{\{discount_code\}\}</h3>
<p>Save 10% on your order</p>
<p><strong>Expires in 48 hours</strong></p>
</div>
<a href="\{\{cart_url\}\}">Complete Purchase & Save 10%</a>
<p><small>This is our final email about this cart.</small></p>
Testing Your Workflow
Test sequence:
- Create test abandoned cart in your store
- Wait 1 hour → Check Email 1 received
- Mark as “not recovered” in tracking sheet
- Wait 24 hours → Check Email 2 received
- Wait 72 hours → Check Email 3 received
Common issues:
Email not sending:
- Check SendGrid API key
- Verify template IDs
- Check spam folder
Workflow not triggering:
- Verify cron schedule is correct
- Check store API credentials
- Ensure workflow is activated
Optimization Tips
Timing Adjustments
Test different timings:
- Email 1: Try 30 min, 1 hour, or 2 hours
- Email 2: Try 12 hours or 48 hours
- Email 3: Try 48 hours or 5 days
Track recovery rates for each timing.
Discount Strategies
A/B test:
- 10% vs 15% discount
- Free shipping vs percentage off
- Dollar amount vs percentage
My results: 10% converts almost as well as 15%, keeps margins higher.
Personalization
Advanced tactics:
- Reference specific products by name
- Show related products customer might like
- Mention items frequently bought together
- Use customer’s browsing history
Legal & Best Practices
GDPR/Privacy:
- Only email customers who opted in
- Include unsubscribe link
- Honor opt-outs immediately
Frequency caps:
- Max 3 emails per abandoned cart
- Don’t email if customer already purchased
- Respect “do not email” preferences
Subject line rules:
- No all caps
- No excessive punctuation!!!
- No misleading claims
ROI Calculation
Scenario: Small store (50 orders/month)
Orders: 50/month
Abandoned carts: 50 × (69.8% / 30.2%) = 115 abandoned
Recovery rate: 20%
Recovered: 115 × 20% = 23 orders
Average order: $75
Monthly recovered revenue: 23 × $75 = $1,725
Annual recovered revenue: $20,700
Setup time: 4 hours @ $50/hour = $200
Monthly cost: $0 (free tiers)
ROI: Infinite (after initial setup)
FAQ
Q: Won’t frequent emails annoy customers?
3 emails over 5 days is reasonable. Customers want reminders. High unsubscribe rates (>2%) mean you’re overdoing it.
Q: Should I always offer a discount?
No! Try the sequence without discounts first. Only add discount in Email 3 if needed.
Q: What if customer already purchased?
Add a check in your workflow to skip carts where order was completed.
Q: Can this work with Shopify/WooCommerce?
Yes! Same concept. Just connect to their APIs instead of DashNex.
Related:
About: I’m Mike Holownych. I build e-commerce automation systems that recover lost revenue. Learn more →
More Posts You'll Love
Based on your interests and activity