This guide builds a shopify repeat customer reward email n8n workflow that watches every new order, spots the moment a shopper places their third order, generates a unique Shopify discount code through the Admin API, and sends a personal thank-you email with Gmail. No loyalty-app subscription and no manual list-pulling. It takes about 35 minutes to wire up and runs free on self-hosted n8n.
Prefer to skip the setup? Grab the ready-made template below and have it live in under 10 minutes.
What it does
Your repeat buyers are the cheapest revenue you will ever earn, yet most stores only thank a customer once, in the order-confirmation receipt. After that, a shopper can place a second and third order and hear nothing. This workflow fixes that quietly in the background.
Every time an order is created in your Shopify store, n8n receives it, reads how many orders that customer has now placed, and waits for the one that turns them into a three-time buyer. At that point it mints a brand-new discount code just for them and emails it as a thank-you. The shopper feels recognized at the exact moment loyalty is forming, and you never touch a spreadsheet.
It is one piece of a larger toolkit. If you are mapping out your whole store, start with the pillar guide on n8n Shopify automation and slot this reward email in alongside your welcome and post-purchase flows.
Why it beats the default
Shopify Flow can tag a repeat customer, but it cannot generate a personal discount code and write a warm email in the same run without bolting on a third-party app. Dedicated loyalty apps do all of this, but they start around 30 to 50 dollars a month and grow with your order volume, and they own the customer relationship instead of you.
Doing it in n8n keeps three things in your hands:
- The trigger logic. Reward on the third order, the fifth, or a spend threshold. It is one field, not a pricing tier.
- The email. It sends from your own Gmail address, so it lands in the primary inbox and reads like a note from a shop owner, not a marketing blast.
- The cost. One n8n instance runs this and dozens of other store workflows for the price of nothing extra.
What you need
- An n8n instance, cloud or self-hosted (the workflow is identical on both).
- A Shopify custom app access token with
read_orders,write_price_rules, andwrite_discountsscopes. - One price rule created in Shopify admin ahead of time, for example “Repeat customer 15% off”. You will copy its numeric ID.
- A Gmail account connected to n8n for sending the reward email.
Estimated build time: about 35 minutes from scratch, or under 10 minutes with the template.
Node-by-node list
Five nodes, in a straight line with one branch:
┌──────────────────────────────────────────────────────────────┐ │ SHOPIFY REPEAT CUSTOMER REWARD EMAIL │ │ │ │ [Shopify Trigger] → [Edit Fields] → [IF orders = 3] │ │ │ true │ │ ▼ │ │ [HTTP: create discount code] │ │ │ │ │ ▼ │ │ [Gmail: send reward] │ └──────────────────────────────────────────────────────────────┘
- Shopify Trigger (
n8n-nodes-base.shopifyTrigger) on theorders/createtopic. - Edit Fields (
n8n-nodes-base.set, v3.4) to extract the customer details. - IF (
n8n-nodes-base.if, v2.2) to continue only on the third order. - HTTP Request (
n8n-nodes-base.httpRequest, v4.2) to create the discount code. - Gmail (
n8n-nodes-base.gmail, v2.1) to send the thank-you email.
Step-by-step build
1 Shopify Trigger
Add a Shopify Trigger node and connect your Shopify credential. Set the topic to orders/create. n8n registers the webhook in your store automatically, so a new order now fires the workflow within seconds. The node hands the full order object to the next step. The slice you care about lives under customer:
{
"order_number": 1042,
"customer": {
"id": 6072830012345,
"first_name": "Emily",
"email": "emily.rodriguez@gmail.com",
"orders_count": 3,
"total_spent": "284.00"
}
}
Tip: orders_count already includes the order that just triggered the webhook, so a shopper’s third purchase reads as 3. That is the number the IF node checks.
2 Edit Fields
Add an Edit Fields node (the Set node, version 3.4) to pull the four values you need into clean, predictable names. Add these assignments:
| Name | Type | Value |
|---|---|---|
customerEmail |
String | ={{ $json.customer.email }} |
firstName |
String | ={{ $json.customer.first_name }} |
ordersCount |
Number | ={{ $json.customer.orders_count }} |
orderNumber |
Number | ={{ $json.order_number }} |
After this node, every downstream step reads $json.customerEmail instead of digging back into the raw payload.
3 IF — is this the third order?
Add an IF node. Create one condition comparing numbers:
- Left value:
={{ $json.ordersCount }} - Operator: Number → Equals
- Right value:
3
Wire only the true output forward. Every order still flows in, but only the one that makes someone a three-time buyer continues. The false branch is left empty, which silently ignores first orders, second orders, and everything past the third.
Using Equals 3 rather than greater than or equal to 3 is deliberate. Equals fires the reward exactly once. A greater-or-equal check would re-send a code on the fourth, fifth, and every later order.
4 HTTP Request — create the discount code
Add an HTTP Request node (version 4.2). This is where the reward becomes real. You create a unique code under the price rule you set up earlier.
- Method: POST
- URL:
https://YOUR_STORE.myshopify.com/admin/api/2026-04/price_rules/YOUR_PRICE_RULE_ID/discount_codes.json - Authentication: Predefined Credential Type → Shopify API, using the same credential as the trigger.
- Body: set Body Content Type to JSON and paste the JSON body below.
{
"discount_code": {
"code": "LOYAL15-{{ $json.orderNumber }}"
}
}
Because the code is built from the order number, every reward is unique and easy to trace back to the order that earned it. Shopify returns the created code:
{
"discount_code": {
"id": 13294857263,
"price_rule_id": 9876543210,
"code": "LOYAL15-1042"
}
}
Tip: The price rule decides the actual discount (percentage, usage limits, expiry). Build it once in Discounts → no, use the price rule via the API or the admin, set “Limit to one use per customer”, and the workflow simply attaches fresh codes to it.
5 Gmail — send the reward email
Add a Gmail node (version 2.1), operation Send. Connect your Gmail credential and fill in:
- To:
={{ $('Edit Fields').item.json.customerEmail }} - Subject:
A thank-you gift for your third order - Email type: HTML
- Message:
Hi {{ $('Edit Fields').item.json.firstName }},
Three orders in. That means a lot to a small shop, so here is
15% off your next one, just for you:
{{ $json.discount_code.code }}
Apply it at checkout. Thanks for keeping us in your corner.
Save the workflow and toggle it active. The next customer to reach their third order gets a personal code in their inbox minutes later.
Common mistakes
- Using greater-or-equal in the IF. It re-rewards the same shopper on every order past the third. Use exact Equals, or a modulo expression like
={{ $json.ordersCount % 5 === 0 }}for an every-fifth-order reward. - Missing the write scopes. A token with only
read_ordersreturns a 403 at the HTTP node. Addwrite_price_rulesandwrite_discountsto the custom app. - Sending a plain text body as HTML. If you choose HTML email type, wrap the message in real markup so line breaks render. Or switch the type to Text for the simple version above.
- Forgetting the price rule limit. Without “one use per customer” on the price rule, a forwarded code can be redeemed by anyone. Set the usage limit on the rule, not the code.
- Testing with an account that has imported history. If you migrated orders,
orders_countmay not start at 1. Place a test order and read the real value before trusting the number 3.
Cost at realistic volume
Take a store doing 600 orders a month. Repeat-buyer rates vary, but suppose 40 customers cross into their third order in a given month. That is 40 discount-code API calls and 40 Gmail sends.
| Component | Usage at this volume | Cost |
|---|---|---|
| n8n (self-hosted) | 600 trigger runs, 40 full runs | $0 |
| Shopify Admin API | 40 discount-code calls | $0 (within rate limits) |
| Gmail | 40 emails (limit ~500/day) | $0 |
The whole thing runs for nothing beyond the server you already pay for. Compare that to a loyalty app at 39 dollars a month and the workflow pays for itself the day you turn it on. On n8n Cloud, these executions sit comfortably inside the entry plan.
🚀 Get the Repeat Customer Reward Email template
The guide above is free to follow. If you would rather skip the build, download the ready-to-import workflow, then just add your credentials. Prefer it installed and tuned for you? See our done-for-you services.
Instant download · Works on n8n Cloud and self-hosted
FAQ
Does this send a reward on every future order?
No. The IF node checks for an exact orders count of 3, so the reward fires once when the customer becomes a three-time buyer. Change the number, or use a modulo expression, if you want a reward on every fifth order instead.
Do I need a paid loyalty app for this?
No. The workflow uses the native Shopify Admin API to mint discount codes and Gmail to deliver them, so there is no monthly loyalty-app fee. You only need an n8n instance, which runs free when self-hosted and cheaply on Cloud.
Where does the discount code come from?
You create one reusable price rule in Shopify admin, for example fifteen percent off. The workflow then generates a fresh, single-customer code under that price rule on each qualifying order, so every reward code is unique and trackable.
Will the customer count be off by one?
The orders_count on the customer object includes the order that just triggered the webhook, so a third purchase reads as 3. If your store imported historical orders, test with a real account first and adjust the IF value to match what you actually see.
Can I reward by total spend instead of order count?
Yes. The customer object also carries total_spent. Map that field in the Edit Fields node and change the IF condition to a spend threshold, such as greater than 300 dollars, to reward your highest-value buyers instead of counting orders.