A shopify birthday discount code email n8n workflow reads customer birthdays from a Google Sheet every morning, finds whoever is celebrating today, generates a unique single-use discount code inside Shopify, and emails it through Gmail. No paid loyalty app, no manual list checking, no shared coupon that ends up on a deal site. You build it once with five nodes and it runs on autopilot. Below you get the node-by-node map, the exact build steps, the common mistakes, and the real cost at volume.
Prefer to skip the setup? Grab the ready-made template and be running in under 10 minutes.
What it does
Birthday emails are one of the highest-converting messages an ecommerce store ever sends, because they land when the customer already feels like treating themselves. The problem is that Shopify has no birthday field and no built-in way to trigger something on a date each year. So most owners either pay for a loyalty app or forget the whole idea.
This automation closes that gap with parts you already have. You keep a simple sheet of names, emails, and birthdays. Every morning n8n wakes up, checks the sheet against today’s date, and for each match it asks Shopify to mint a fresh discount code and then sends that code to the customer by email. The customer opens their inbox on their birthday and finds a personal, one-time offer waiting.
- Runs on a daily schedule, fully unattended.
- Creates a unique code per customer, capped at one use.
- Sends a warm, personal Gmail message with the code inside.
- Costs nothing beyond tools you likely already run.
Why it beats the default
The default option is a birthday app from the Shopify App Store. Those work, but they add a recurring bill, they park your customer data inside another vendor, and they usually hand out one static coupon code that anyone can reuse once it leaks. A single shared code on a birthday campaign is a margin risk, because a deal-hunting forum can drain it in hours.
Building it in n8n flips all three problems. There is no monthly fee. The customer list stays in your own Google Sheet and your own Shopify store. And because every code is generated on the fly with a usage limit of one, a leaked code is worthless to anyone but the person it was meant for. You also get to shape the email exactly how you want, in your own brand voice, instead of squeezing into an app’s template editor.
Tip: Before you connect n8n to Shopify, set up access the modern way. Our guide on how to connect Shopify to n8n in 2026 walks through the Dev Dashboard custom-app method that this workflow relies on.
What you need
- An n8n instance, cloud or self-hosted (a free self-hosted install is fine).
- A Shopify store connected to n8n the 2026 way (Developer Dashboard). See the 2026 connection guide.
- A Google account for Google Sheets and Gmail.
- A birthday sheet with three columns:
Name,Email,Birthday(stored asMM-DD).
Build time: about 30 minutes from scratch, or under 10 minutes if you import the template and drop in your credentials.
Node-by-node list
The workflow is a clean straight line of five nodes. Nothing branches, which keeps it easy to reason about and easy to fix if a birthday email ever fails to arrive.
┌─────────────────────────────────────────────────────────────┐ │ SHOPIFY BIRTHDAY DISCOUNT CODE EMAIL │ │ │ │ [Schedule Trigger] daily at 08:00 │ │ ↓ │ │ [Google Sheets] read all birthday rows │ │ ↓ │ │ [Code] keep today's birthdays, build unique code + dates │ │ ↓ │ │ [HTTP Request] Shopify GraphQL: create discount code │ │ ↓ │ │ [Gmail] send the birthday email with the code │ └─────────────────────────────────────────────────────────────┘
| # | Node | Type | Job |
|---|---|---|---|
| 1 | Schedule Trigger | scheduleTrigger |
Fire once a day at 8am |
| 2 | Google Sheets | googleSheets |
Read the birthday list |
| 3 | Code | code |
Filter to today, build code and dates |
| 4 | Create Discount | httpRequest |
Call Shopify GraphQL to mint the code |
| 5 | Gmail | gmail |
Email the customer their code |
Step-by-step build
1 Schedule Trigger
Add a Schedule Trigger node. Set it to a fixed interval of once per day and choose an hour that suits your audience, for example 8:00 in your store’s timezone. This node is the only entry point, so nothing else runs until the schedule fires.
Tip: Set the workflow timezone under Settings so 8am means 8am for your customers, not for the server. A morning email lands better than one that arrives at 2am.
2 Google Sheets — read the list
Add a Google Sheets node, operation Get Row(s) in Sheet. Point it at your birthday spreadsheet and the tab that holds the list. Leave the filters empty so it returns every row; the next node does the date matching. A returned row looks like this:
{
"Name": "Emily Rodriguez",
"Email": "emily.rodriguez@gmail.com",
"Birthday": "07-15"
}
3 Code — find today’s birthdays
Add a Code node (run once for all items). This is the brain of the workflow. It compares each row’s birthday to today, and for every match it builds a unique code plus the start and end dates for the offer.
const today = new Date();
const mmdd = `${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`;
const out = [];
for (const item of $input.all()) {
const row = item.json;
const bday = String(row.Birthday || '').replace(/\//g, '-').slice(-5);
if (bday !== mmdd) continue;
const rand = Math.random().toString(36).slice(2, 7).toUpperCase();
const first = String(row.Name || 'FRIEND').split(' ')[0].toUpperCase().replace(/[^A-Z0-9]/g, '');
const starts = new Date(today); starts.setHours(0, 0, 0, 0);
const ends = new Date(starts); ends.setDate(ends.getDate() + 7);
out.push({ json: {
name: row.Name,
email: row.Email,
code: `BDAY-${first}-${rand}`,
title: `Birthday reward - ${row.Name}`,
startsAt: starts.toISOString(),
endsAt: ends.toISOString()
} });
}
return out;
If nobody has a birthday today, the node returns zero items and the rest of the workflow simply does not run, which is exactly what you want. On a match, one item leaves this node per customer:
{
"name": "Emily Rodriguez",
"email": "emily.rodriguez@gmail.com",
"code": "BDAY-EMILY-7K2QP",
"title": "Birthday reward - Emily Rodriguez",
"startsAt": "2026-07-15T00:00:00.000Z",
"endsAt": "2026-07-22T00:00:00.000Z"
}
Note: Store birthdays as MM-DD so the year never matters. The slice(-5) also accepts a full YYYY-MM-DD value, so either format in the sheet works.
4 HTTP Request — create the Shopify code
Add an HTTP Request node. This calls the Shopify GraphQL Admin API to create a real, working discount code with the values the Code node produced. Configure it like this:
- Method: POST
- URL:
https://YOUR_STORE.myshopify.com/admin/api/2026-04/graphql.json - Authentication: Generic credential, Header Auth, header name
X-Shopify-Access-Tokenwith your Admin API access token as the value - Send Body: on, Body Content Type: JSON
Paste this into the JSON body field. It sends the GraphQL mutation with variables pulled from the current item:
={{ JSON.stringify({
query: "mutation ($basic: DiscountCodeBasicInput!) { discountCodeBasicCreate(basicCodeDiscount: $basic) { codeDiscountNode { id } userErrors { field message } } }",
variables: { basic: {
title: $json.title,
code: $json.code,
startsAt: $json.startsAt,
endsAt: $json.endsAt,
customerSelection: { all: true },
customerGets: { value: { percentage: 0.15 }, items: { all: true } },
appliesOncePerCustomer: true,
usageLimit: 1
} }
}) }}
That creates a 15 percent code, valid for seven days, that works exactly once. Change 0.15 to set a different discount, or swap percentage for a fixed discountAmount if you prefer a flat sum off.
Tip: GraphQL returns a 200 status even when the discount is rejected. Watch the userErrors array in the response during testing; an empty array means the code was created cleanly.
5 Gmail — send the birthday email
Add a Gmail node, operation Send. Map the fields from the current item so each customer gets their own code:
- To:
={{ $json.email }} - Subject:
=Happy birthday, {{ $json.name }}! A gift from us 🎉 - Message: your birthday copy, with
={{ $json.code }}dropped in where the code should appear
A short, warm message converts best. Something like: “Happy birthday from all of us. Here is 15 percent off anything in the store as our gift. Use code BDAY-EMILY-7K2QP at checkout within the next seven days.” Keep it personal and get the code above the fold.
Common mistakes
- Storing the birth year in the match. If you compare full dates including the year, nobody ever matches. Match on
MM-DDonly, which the Code node already does. - Leaving the timezone unset. Without a workflow timezone, the 8am trigger and the “today” check both run in server time, and codes can be built for the wrong calendar day. Set the timezone once in Settings.
- Using a stale API version. Point the URL at a current version such as
2026-04. An old version can silently drop fields from the mutation. - Trusting the HTTP status alone. Shopify GraphQL answers 200 even on a rejected discount. Always check
userErrorsbefore you assume the code exists. - One shared code for everyone. That defeats the whole point. Let the Code node mint a fresh code per customer with a usage limit of one.
Cost at realistic volume
This is one of the cheapest automations you can run, because none of the moving parts bill per birthday.
| Piece | Cost | Notes |
|---|---|---|
| n8n (self-hosted) | $0 | One execution per day, tiny footprint |
| Shopify Admin API | $0 | Discount creation is included in your plan |
| Google Sheets | $0 | Free, well within read limits |
| Gmail | $0 | Free tier sends up to 500 emails a day |
Even a store with 20,000 customers rarely sees more than a few dozen birthdays on a single day, so you stay far below every free limit. If you run n8n Cloud instead of self-hosting, this is a single scheduled run per day, which barely dents the starter plan’s execution allowance. For most stores the true cost is zero.
🚀 Get the Shopify birthday 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 Shopify store customer birthdays by default?
No. Shopify has no native birthday field on the customer record. This workflow keeps birthdays in a Google Sheet that you fill from a signup form or a customer metafield, so the automation always has a reliable date to check each morning.
Is each birthday discount code unique?
Yes. The Code node builds a distinct code per customer, such as BDAY-EMILY-7K2QP, and the Shopify mutation sets a usage limit of one. A code cannot be shared, reused, or leaked to a coupon site because it only works once for one order.
Do I need a paid loyalty app for this?
No. The whole flow runs on Shopify, a free Google Sheet, n8n, and Gmail. There is no monthly app fee. Most birthday apps in the Shopify App Store charge fifteen to forty dollars a month for the same outcome you build here once.
What if two customers share the same birthday?
The workflow handles as many birthdays as land on a given day. The Code node returns one item per matching customer, and each item flows through the discount and email nodes separately, so everyone gets their own code and their own message.
Can I change the discount amount or expiry?
Yes. The percentage lives in the HTTP Request node as 0.15 for fifteen percent, and the expiry is set in the Code node as seven days from today. Edit either value once and every future birthday code follows the new rule automatically.