Home / Blog / Shopify Abandoned Cart SMS with n8n + Twilio
Shopify Abandoned Cart SMS — Shopify, n8n and Twilio logos in a flow diagram ending at SMS
Tutorial · 2026

How to Set Up Shopify Abandoned Cart SMS Recovery with n8n and Twilio

A working SMS recovery flow you control end to end. Shopify checkout webhooks → n8n delay → Twilio SMS, with the conditional logic that stops you from texting customers who already paid. About 30 minutes start to finish.

You're losing real revenue every day to abandoned carts. The faster you have a recovery flow live, the faster that revenue comes back. This tutorial gets you from zero to a working, compliant SMS recovery flow in about 30 minutes, using tools you control end to end.

Why n8n and Twilio specifically: n8n gives you a visual workflow you can branch, debug and extend without waiting on a vendor's roadmap. Twilio is the SMS infrastructure layer Klaviyo, Postscript and most others sit on top of, you're just removing the middleman so you own the message logic. The result is a flow that does exactly what you tell it to, that you can rewrite in five minutes when your store needs something different.

~18% recovery
Typical SMS cart recovery rate when timing, opt-in and dedup are handled correctly. The stack below gets all three right.

What you'll build

An automated flow that triggers when a Shopify customer abandons checkout, waits 20 minutes, checks if they completed the order, and if not, sends a Twilio SMS with a recovery link.

  1. Customer fills checkout, enters phone, doesn't complete
  2. Shopify fires checkouts/update webhook to n8n
  3. n8n waits 20 minutes
  4. n8n calls Shopify API to check if the checkout converted to an order
  5. If not, Twilio sends an SMS with the recovery link
  6. If yes, the workflow exits silently

That last step is the one most tutorials skip. Without it, you'll text customers who paid 18 minutes ago, which is the fastest way to get marked as spam.

What you need

ComponentWhat it does
Shopify storeSource of checkout webhook + Admin API
n8n (cloud or self-hosted)Workflow orchestrator. Cloud is faster to start, self-hosted gives you full control
Twilio accountThe SMS infrastructure that actually delivers the message
A public URL for n8nSo Shopify can reach your webhook endpoint

Step 1. Set up Twilio

1.1

Create the account and buy a number

Sign up at twilio.com. Verify your email and phone. In the console, go to Phone Numbers → Manage → Buy a number. Pick a number in the country your customers are in, SMS-capable. Local long-code is the easiest path; if you expect high volume, look at toll-free or short codes once you're past 1k sends/day.

1.2

Grab your credentials

From the Twilio console homepage, copy:

  • Account SID (starts with AC...)
  • Auth Token (click reveal)
  • The phone number you just bought, in E.164 format: +15551234567

Stash these in a password manager. You'll paste them into n8n in step 4.

A2P 10DLC if you're texting US numbers

US carriers require business SMS senders to register their brand and campaign. Twilio walks you through this on first send. Budget 1–3 days for approval. Outside the US it's typically not required.

Step 2. Get n8n running

Two paths. Pick whichever gets you to a public URL fastest.

Option A. n8n Cloud (~5 min)

Sign up at n8n.io on the Starter plan. You get a public URL out of the box, no infra to manage. Skip ahead to step 3.

Option B. Self-hosted with Docker (~10 min)

If you'd rather host it yourself, drop this on any small VPS (Hetzner, DigitalOcean, Fly.io):

# docker-compose.yml
services:
  n8n:
    image: n8nio/n8n
    restart: always
    ports:
      - "5678:5678"
    environment:
      - N8N_HOST=your-domain.com
      - N8N_PROTOCOL=https
      - WEBHOOK_URL=https://your-domain.com/
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER=admin
      - N8N_BASIC_AUTH_PASSWORD=changeme
    volumes:
      - n8n_data:/home/node/.n8n
volumes:
  n8n_data:

Run docker compose up -d, point a subdomain at the box, terminate TLS with Caddy or Traefik. Done.

Either way you end up with a base URL like https://n8n.yourdomain.com and login credentials.

Step 3. Configure the Shopify webhook

Why OAuth2, not a copy-pasted token

The old Settings → Apps and sales channels → Develop apps path inside the storefront admin was retired for new apps on 1 January 2026. New custom apps live in the Shopify Dev Dashboard, and the cleanest way to wire one to n8n is OAuth2 — n8n stores the access token, refreshes it automatically when needed, and reuses the same credential across the Shopify node and the HTTP Request node. You don't see shpat_ tokens at all.

If you'd rather paste an Admin API token manually (e.g. for a CLI-installed dev-store app), n8n's "Shopify Access Token API" credential still accepts one. But for a fresh setup in 2026, OAuth2 is less work and less to maintain.

3.1

Create the Shopify app in the Dev Dashboard

Sign in to shopify.dev/dashboard with the Shopify ID that owns your store. Click Create app → Custom distribution, name it "n8n SMS Recovery", and pick the store you'll install on.

In Configuration → Admin API access scopes, grant:

  • read_checkouts (so you can poll for completion)
  • read_orders (so you can confirm conversion)
  • read_customers (for phone + name lookup)

You'll add the redirect URL in the next step. Leave the Dev Dashboard tab open — you'll need the Client ID and Client Secret from the app's overview page in a moment.

3.2

Connect the OAuth2 credential in n8n

In n8n, go to Credentials → Add credential → Shopify OAuth2 API. Paste the Client ID and Client Secret from the Dev Dashboard, and the Shop subdomain (the bit before .myshopify.com).

n8n shows you an OAuth Callback URL — copy it. Back in the Dev Dashboard, open Configuration → URLs, add that callback URL under Allowed redirection URLs, save. Then in n8n click Connect my account. Shopify shows the install screen, you approve the scopes, n8n stores the access token and (if you enabled expiring tokens) the refresh token. From now on, n8n handles the refresh automatically — you never touch the token yourself.

3.3

In n8n, create a Webhook node

New workflow → Add node → search "Webhook". Set:

  • HTTP Method: POST
  • Path: shopify-checkout
  • Response: Immediately

Copy the Production URL. It'll look like https://n8n.yourdomain.com/webhook/shopify-checkout.

3.4

Subscribe Shopify to that URL

In your storefront admin → Settings → Notifications → Webhooks. Click Create webhook:

  • Event: Checkout update
  • Format: JSON
  • URL: paste the n8n production URL
  • API version: latest stable

Save. Then in n8n, click Listen for test event and add an item to a Shopify cart in another tab. Within seconds the checkout payload should land in n8n. Pin it as test data — you'll reference its fields in every node downstream.

Step 4. Filter for real abandoners

checkouts/update fires constantly. It fires when the customer adds a line item, when they update their address, when they change quantity, when they enter their phone, and when they complete the order. You want exactly one branch: customer entered a phone number and has not yet completed.

Add an IF node after the webhook. Set conditions (all must match):

// Condition 1 — phone is set
{{ $json.phone }} is not empty

// Condition 2 — checkout not yet completed
{{ $json.completed_at }} is empty

// Condition 3 — has at least one line item
{{ $json.line_items.length }} greater than 0

// Condition 4 — customer accepts marketing (compliance)
{{ $json.sms_marketing_consent.state }} equals "subscribed"

If any of these fail, the workflow exits. That last condition is the one that keeps you out of trouble. Shopify's checkout has a "Text me with news and offers" toggle. Only send to people who ticked it.

Step 5. Wait, then verify

5.1

Wait node

After the IF node's true branch, add a Wait node. Set Resume = After Time Interval, Wait Amount = 20, Wait Unit = Minutes.

20 minutes is the sweet spot. Earlier feels creepy; later loses purchase intent. More on the timing window in the 2026 guide.

5.2

Check if they paid

After the Wait, add an HTTP Request node. This re-queries Shopify to see whether the checkout converted while we slept.

  • Method: GET
  • URL: https://{{ $('Webhook').item.json.shop_domain }}/admin/api/2026-01/checkouts/{{ $('Webhook').item.json.token }}.json
  • Authentication: Predefined Credential Type → Shopify OAuth2 API, then pick the credential you connected in 3.2. n8n attaches the access token (and refreshes it if it's expired) — no header to set by hand.

Add another IF node: only continue if {{ $json.checkout.completed_at }} is still empty. If it's filled in, the customer paid in the last 20 minutes, exit.

Step 6. Send the SMS

Add a Twilio node. n8n has a native one.

  • Credential: New → paste your Account SID and Auth Token
  • Resource: SMS
  • Operation: Send
  • From: your purchased Twilio number, in E.164
  • To: {{ $('Webhook').item.json.phone }}
  • Message: see template below
Hi {{ $('Webhook').item.json.customer.first_name }},
you left items in your cart at {{ $('Webhook').item.json.shop_name }}.
Finish here: {{ $('Webhook').item.json.abandoned_checkout_url }}
Reply STOP to unsubscribe.

The abandoned_checkout_url is critical. It's a one-tap link back to a pre-filled cart with their items already loaded. Don't link to your homepage. Don't link to the product page. Link to the abandoned checkout URL Shopify gives you, that's the whole point.

The Reply STOP to unsubscribe line is required by US carrier rules and a good idea everywhere else. Twilio honors it automatically, when a customer texts STOP, future sends to that number bounce.

Step 7. Test end-to-end

  1. Activate the workflow in n8n (toggle top-right)
  2. Open your Shopify store in an incognito window
  3. Add a product to cart, go to checkout
  4. Enter your real phone number, tick the SMS marketing consent box
  5. Stop. Don't pay
  6. Wait 20 minutes
  7. You should get the SMS

Then run it again, complete the order this time. You should not get an SMS. If you do, check that your IF node in step 5.2 is firing on the right field.

Optional: a second nudge at 24 hours

Duplicate the Wait + check-if-paid + Twilio chain. Wait 24 hours instead of 20 minutes. Different message:

Still thinking about your cart at {{ shop }}? It's saved for you.
Use code COMEBACK10 for 10% off in the next 24h: {{ url }}

Hard cap at 2 messages. A third gets you reported as spam, and the spam-report-to-shortcode-deactivation pipeline is fast and unforgiving.

Compliance, the short version

The non-negotiables

Carriers and regulators don't care that you built it yourself. The same rules apply.

  • Only send to opted-in customers. The condition in step 4 enforces this. Don't bypass it.
  • Identify yourself. Include your store name in the first message.
  • Honor STOP. Twilio handles this automatically, don't override it.
  • US: register A2P 10DLC. Twilio prompts you. Skipping this means filtered or dropped messages.
  • EU: GDPR consent at the point of capture. Shopify's marketing-consent toggle covers it if it's clearly worded next to the input.

What this won't do

Honest list of what you're giving up vs a managed product:

  • No two-way conversation. If the customer replies "is this in stock?", nothing handles it. You can wire a reply webhook back into n8n, but you'll need an LLM node and a knowledge base, that's a different tutorial.
  • No segmentation by AOV, geography, or LTV. Every abandoner gets the same message. You can build this with extra IF branches, but it adds up fast.
  • No deliverability dashboard. Twilio gives you raw logs. You build the dashboard yourself or query the API.
  • No image/MMS support out of the box. Twilio supports MMS but you'd need to host product images and pass the media URL.
  • WhatsApp is a different channel. Twilio supports WhatsApp Business too, but the template approval process is its own thing. See the WhatsApp guide for that.

For a $10k/mo store, this stack is genuinely fine. For a $100k/mo store recovering hundreds of carts a day, the lack of segmentation and reply handling will cost you more than the $300/mo Klaviyo bill saved.

When to graduate to a managed tool

This stack solves the core problem: a customer abandons, the right SMS goes out at the right time, paid customers don't get pinged. That's enough to start recovering carts today.

You'll outgrow it when one of these starts costing you more revenue than the time saved:

  • Replies pile up unanswered. Customers ask "is this in stock?" and nobody's home
  • You need to segment by AOV, geography or LTV and the IF-tree gets unmanageable
  • Recovery rates plateau and you can't tell why without a real analytics layer
  • You want WhatsApp on top of SMS, and the template approval + opt-in flow is its own project

At that point, switch. Until then, ship this.

If you want the result without building it

If the goal is "recover more carts" and not "build the recovery system", install CartGhost on Shopify. AI-led WhatsApp conversation recovery, storefront phone capture, compliant opt-in flow, all of it handled. 10 minutes to live, then you're back to running your store.

CartGhost. Built for the parts this tutorial skips. AI-led WhatsApp cart recovery, storefront phone capture, compliant opt-in flow. Shopify-native. Live in 10 minutes.
Install on Shopify