A unified campaign automation stack: one customer record, permission attached, every tool reading from it
TL;DR
Difficulty: Intermediate
A unified stack is one record of each customer and each event, with permission stored on the record, and every tool reading from it.
- Five jobs: collect events, keep the record, send email, reach ad audiences, move data between them.
- Consent is a field with source, wording and time, checked per purpose before anything leaves.
- For a small shop the bill is mostly the email tool and the tag server. Buying usually beats building until volume pricing makes the break even short.
- A daily check of counts in and out is the best value part of the whole stack.
- In Ireland the rules are the GDPR and the ePrivacy Regulations 2011, enforced by the DPC.
Most small shops run several marketing tools that each keep their own version of the customer and of who agreed to what. This article shows how to make one record the source for all of them, with consent attached, and what that costs to build, buy, run and leave, worked through for an invented tea shop in Limerick.
One customer, one record, and every tool reads from it
Most small shops do not have a marketing stack. They have a collection of subscriptions that each grew up on their own. The email tool knows who opened what. The ad accounts know who clicked. The shop knows who paid. Nobody knows all three, and nobody knows for certain who said yes to what.
A unified campaign automation stack fixes that with one idea. There is one record of each customer, and one record of each thing they did, and every tool that acts (the email tool, the ad platforms, the analytics) reads from those records instead of keeping its own version. The permission each person gave travels with their record, so a tool can only see the people it is allowed to see.
I do not automate campaigns in isolation, and this article is the reason why. It is about the architecture: which pieces you need, what each costs, whether to build or buy them, what breaks, and who owns the data when you leave a vendor. The pieces themselves each have their own article, and I link to them as we go rather than repeat them.
Throughout I use one invented business. Milk Market Tea Co is an online loose leaf tea shop in Limerick, run by Róisín, on Shopify, at milkmarkettea.example. It takes about 1,000 orders a month at an average of €28, keeps about €14 of each order after the cost of the tea, packaging and An Post, and has 6,000 contacts in its email tool. It spends about €3,000 a month on Meta and €2,000 on Google. Nobody real, and every number is made up so I can show every step.
The stack is five jobs, not five products
The old version of this article listed products: Zapier, Segment, Python, the Google Ads API, Postmark, BigQuery. Products change every year, the jobs do not. There are five.
- Collect events. Something records what visitors and customers do, page views, add to baskets, purchases, along with the consent state of the browser at that moment. That is the subject of my article on event tracking and consent mode, and server side tagging is one way of doing it.
- Keep the record. One place holds one row per customer, with their identifiers, their orders and their permissions. For a small shop that is often the shop platform plus the email tool. For a bigger one it is a data warehouse.
- Send email. An email service provider (ESP), such as Klaviyo or Postmark, sends the messages.
- Reach ad audiences. Customer lists and conversion data go to Google and Meta, which is the subject of triggering ads from email activity and of auto bidding on first party data.
- Move data between them. Native integrations, a tool like Zapier, or your own code on webhooks and serverless functions.
The order matters. Everything flows from collection, through the record, to the tools that act, and permission is checked at the record, before anything leaves.
The decision step is the heart of it: one question, asked per purpose, before any data leaves. A yes sends the person to that one tool. A no keeps them in the shop's own order records, which are needed to run the shop anyway. The last step is the boring one that saves the most money, and it has its own section further down.
Worked example: Milk Market's five jobs
Róisín writes the five jobs down and puts what she already pays for next to each one.
- Collect events: the Shopify store, its consent banner, and Google's tags.
- Keep the record: Shopify's customer list, which Klaviyo copies through its Shopify integration. Klaviyo documents that it brings customer profile and order data in, and that it can add customers who accept email marketing at checkout to a list.1
- Send email: Klaviyo.
- Reach ad audiences: the Meta and Google apps for Shopify, plus Klaviyo's audience sync.
- Move data between them: two Zapier automations, one that posts big orders to her phone and one that copies wholesale enquiries into a spreadsheet.
She already has a stack. What she lacks is one answer to "who may receive what", because three tools each hold a version of it.
Consent is a field on the record, not a setting in a tool
Under the GDPR, where you rely on consent you must be able to show that the person consented, and withdrawing must be as easy as giving it.2 That one sentence decides the architecture. If the proof of consent lives inside an email tool, the ad sync cannot see it, and if a person withdraws in one tool, the other tools keep using the old answer.
So each permission is a field on the customer record, with what was agreed, where, when and with which wording. There are two kinds, and they behave differently.
Permission for email belongs to a person. In Ireland, regulation 13 of the ePrivacy Regulations 2011 (S.I. No. 336 of 2011) says marketing email to an individual needs their consent, with one exception for your own customers in regulation 13(11): you got their email address from them in the context of a sale, you market only your own products of a kind similar to what they bought, you gave them a clear, easy and free way to object when you collected the details and in every message since, and the sale was no more than 12 months before the email.3 So the record also needs the date of the last purchase, because the exception runs out.
Permission for cookies and tags belongs to a browser. Regulation 5(3) of the same Regulations says nobody may store information on a user's device, or read information already stored there, without the user's consent and clear, comprehensive information about the purpose, and regulation 5(5) exempts only what carries a communication or is strictly necessary for a service the user explicitly asked for.4 The banner answer is a snapshot on each event, not a fact about the person. The regulator that enforces both is the Data Protection Commission (DPC). The 2011 Regulations still name the Data Protection Commissioner, and the Data Protection Act 2018 transferred all of the Commissioner's functions to the Commission and reads every such reference as one to the Commission.5 The details of what needs a yes are in my article on event tracking and consent mode, and how to ask for email permission without losing sign ups is in GDPR versus growth.
The ad platforms add their own layer. Google's EU user consent policy covers end users in the European Economic Area, which includes Ireland, as well as the UK and Switzerland, and asks for legally valid consent to use personal data for ad personalisation, with records kept of it.6 For customer list uploads, Google's API refuses the request if the ad_user_data or ad_personalization consent field is denied.7 So the record needs a separate field for ad audiences, because a customer can happily want your newsletter and still not want to be matched to their Facebook account.
Worked example: Jo's record, three destinations
Jo buys a tin of Irish breakfast tea, ticks the marketing box at checkout, and a week later opens the preference centre and switches off "use my email to show me ads". Her record in Róisín's store now reads:
{
"customer_id": "c_10482",
"email": "jo@example.com",
"orders": 1,
"consents": {
"email_marketing": {
"state": "granted",
"basis": "consent",
"source": "checkout",
"wording": "checkout_box_v3",
"at": "2026-10-14T19:02:11Z"
},
"ad_audiences": {
"state": "denied",
"source": "preference_centre",
"at": "2026-10-21T08:15:40Z"
}
}
}
The nightly sync asks the question from the diagram once per destination.
- Email tool:
email_marketingis granted, so Jo stays on the newsletter list. - Meta and Google customer lists:
ad_audiencesis denied, so Jo is not uploaded to either, not even to the list of recent buyers that is used to exclude people from prospecting ads. - Analytics: nothing on the person record decides this. Each of Jo's page views carries the banner answer her browser gave at the time, and the tags respect that.
Step two has a price. Jo may now see an advert inviting her to try Milk Market for the first time, because Róisín cannot tell Meta to leave her out. That is the rule working, not failing. The alternative, uploading her anyway "only for exclusion", is a judgement for a lawyer, and Google's own consent field would refuse it in any case.
What the stack costs a month, and the orders that pay for it
The bill for a small shop is mostly subscriptions, and most of them price by size: contacts, events or tasks. Here is what each vendor's own page says, checked in November 2026.
Klaviyo bills by active profiles, which it defines as any contact you can market to. Its free plan covers up to 250 active profiles, and the paid Email plan starts at 20 US dollars a month for 500 profiles, rising on a slider as the count grows.8 RudderStack, which collects events and routes them to tools, is free up to 250,000 events a month, and its Growth plan is 265 US dollars a month for one million events.9 Zapier's Pro plan is 29.99 US dollars a month on monthly billing for 750 tasks, a task being one successful action.10 A server side tagging container on Google Cloud Run costs about 45 US dollars a month per server, and Google recommends at least two.11 BigQuery, Google's warehouse, includes 1 TiB of query processing a month free.12 Twilio Segment, the best known of the event routers, publishes no prices on its pricing page and quotes by monthly tracked users instead.13
Worked example: Milk Market's monthly bill
Most of these prices are in dollars. For round arithmetic I convert at €0.75 to the dollar, which is an assumption for the example, so check the rate on the day. Róisín's 6,000 profiles put her well above Klaviyo's first step, and for this example I take her slider price as €110 a month. Read your own off the slider, because it moves with your count.
Her site gets 30,000 sessions a month at about eight events each:
Here is sessions a month and is events per session, so 240,000 events, just under RudderStack's free 250,000. Then the bill, line by line:
- Klaviyo: €110.
- Zapier Pro: 29.99 dollars at €0.75 each is €22.49.
- RudderStack: €0, inside the free tier.
- BigQuery: inside the free query allowance, and I count €1 for storage of a few gigabytes as the example's assumption.
- Server side tagging: two servers at 45 dollars, at €0.75 each, is €67.50.
Here is Klaviyo, Zapier, RudderStack, BigQuery and the tag server, all in euro a month, so about €201.
Each bar is one tool, and the vertical axis is what it costs Róisín a month in euro. The takeaway is that the email tool and the tag server are nearly nine tenths of the bill, and the warehouse, the part people fear, is close to free at this size. RudderStack's bar is zero only while she stays under 250,000 events.
Is €201 worth it? The number of extra orders whose margin covers it is a simple ratio:
Here is the break even number of extra orders a month, is the monthly cost of the stack in euro, and is the margin per order in euro, what is left after the cost of the goods, packaging and postage. It is a rate like any other, explained in Foundations: ratios and rates.
For Milk Market:
Here is the monthly cost and the margin per order, both in euro. So 15 extra orders a month, 1.5% of her 1,000, pays for the whole stack. That is a low bar, which is exactly why it is worth checking honestly with a holdout group rather than assuming it. The methods are in my guide to digital marketing testing methods. Notice what the formula leaves out: the time to set it up and keep it running. That is the next section.
Build or buy: the one off cost against the monthly one
Every piece can be bought as a subscription or built as your own code on a warehouse. The subscription is quick to start and costs every month. Your own code is slow to start and costs little to run. Both need looking after, and people forget to count the upkeep of the thing they bought.
The comparison is a one off cost against a monthly saving. If building costs more up front but less each month, it catches up after
Here is the break even point in months, and are the one off setup costs of each option in euro, and and are their full monthly costs in euro, subscription or hosting plus upkeep time. If is not larger than , building never catches up. It is a ratio of a one off amount to a monthly rate, the idea in Foundations: ratios and rates. Over a horizon of several years, money later is worth less than money now, which pushes the break even further out, as Foundations: discounting explains.
Worked example: Milk Market's routing layer, two ways
Milk Market's traffic grows to 600,000 events a month, past RudderStack's free tier. Róisín compares two ways of collecting events and sending customer lists to Google and Meta. To price time I assume a day of senior engineering at €550, a round figure for the example, not anyone's quote.
Buy: RudderStack Growth at 265 dollars, which at €0.75 each is €198.75 a month. Three days to set up and a quarter of a day a month to keep an eye on it.
Here is the setup days and the day rate in euro.
Here is the subscription in euro and the days of upkeep a month.
Build: her own small collector writing into BigQuery, with nightly sync jobs. Fifteen days to set up, about €10 a month to host (the example's assumption), and half a day a month of upkeep.
Here is the setup days at euro each.
Here is hosting in euro and the days of upkeep a month.
Then the break even:
Here is the extra setup cost of building and is the monthly saving, so building catches up after 129 months, nearly 11 years. For Milk Market, buying wins by a distance.
The horizontal axis is months since the decision, the vertical axis is the total spent so far in euro, setup included. The gap closes by only €51.25 a month, which is why the lines look almost parallel. Now change one number. Suppose Milk Market triples again and the subscription quote rises to €700 a month. becomes , and
Here is the new monthly saving, and building pays back in under a year. The lesson is not "build" or "buy". Volume priced subscriptions grow with you and your own code mostly does not, so the answer flips at a size you can calculate in advance.
Small ad accounts cannot target with customer lists yet
One cost does not appear on any invoice: the features you cannot use. Google's Customer Match policy says targeting and bid adjustments with customer lists need 90 days of Google Ads history and more than 50,000 US dollars of lifetime spend. Accounts below that, with good policy and payment history, can still use customer lists for exclusions and in observation.14 Klaviyo's documentation repeats the same thresholds for its Google sync.15
The same Klaviyo page has a detail worth reading twice. When you market to the EEA, which includes every customer on an Irish list, Klaviyo asks you to agree that you only send audiences that have consented to ad targeting, then sends the consent as granted for every profile in the sync. It states that the setting does not check each profile's consent.15 The filter has to be in the segment you sync, which is exactly why the consent field belongs on the record.
An example: Milk Market has spent about €28,000 on Google Ads over its life, roughly 37,000 dollars at the example's rate, so it is under the threshold. Róisín's buyer list can exclude recent customers from her Google prospecting campaigns, which is useful, but it cannot target them. On Meta, a customer file audience can be used to target, and its documentation sets no spend threshold.16 So a stack that is "one audience, sent everywhere" does different things on each platform, and her plan has to say so, or she will spend a week wondering why the Google campaign will not serve.
What breaks, and what it costs when it does
A stack fails quietly. Nothing crashes. A sync stops, a field goes missing, an event is renamed, and the tools carry on with stale data. The useful way to price that is expected value: how likely each failure is in a month, times what it costs when it happens.
Here is the expected cost of failures in a month, in euro, is the probability that failure happens in a given month, is what it costs when it does, in euro, and adds the products over every failure on the list. The idea is in Foundations: expected value.
The common failures, from the vendors' own documentation:
- Duplicates. Shopify says your app might receive the same webhook more than once and tells you to skip any delivery whose
X-Shopify-Webhook-Idyou have already seen.17 Meta deduplicates browser and server events only when the event name and id match, and only within 48 hours.18 Without that, purchases count twice and the bidding chases a ghost. - Deprecations. Since 1 April 2026, Google's older Customer Match services in the Google Ads API fail for projects with no Customer Match activity between October 2025 and March 2026, and Google points to the Data Manager API instead.7 Code that worked last year can stop this year without anyone touching it.
- Renames and missing fields. A theme update renames the purchase event, or a new sync job forgets to copy the consent field. These are not in any vendor's documentation, because they are yours.
Worked example: Milk Market's expected monthly breakage
Róisín lists three failures. The probabilities and costs are the example's assumptions, chosen to be plausible, not measured.
- The Meta exclusion list of recent buyers stops updating for a week. Likelihood 10% a month. A week of Meta spend is euro, and she assumes 12% of it reaches recent buyers when the list is stale, so .
- A theme update renames the purchase event and Google's bidding runs blind for five days. Likelihood 5%. Cost €350.
- A new sync job leaves out the consent field and refusers are uploaded to an audience. Likelihood 2%. Cost two days of clean up and review, , before any question of trust or the DPC.
Here , and are the monthly likelihoods and , and the costs in euro, so is about €48 a month. Now she adds a daily check that compares counts in with counts out, alarms when an audience has not changed for a day, and refuses to upload any row without a consent field. Each failure is now caught within a day. The first costs a seventh as much, €12. The second costs a fifth, €70. The third is blocked before upload, costing half a day, €275.
Here is the expected monthly cost with the check in place, about €10. The check saves about €38 a month and takes a day to build, so it pays back in about 15 months on money alone. The part it really buys is the third line: the failure you cannot fully price is the one it stops.
Owning the record means you can leave
Data ownership sounds like a legal question. In practice it is a test: could you switch your email tool next month and take everything with you?
The law sets the floor. Under the GDPR a vendor that processes your customers' data for you does so under a contract, and that contract must say the vendor deletes or returns all the personal data at your choice when the service ends.19 It does not say in what shape. That is where the architecture comes in. If the only full copy of the consent history lives inside one vendor, leaving means trusting their export. If your own record holds it, the vendor holds a copy and you hold the original. Choosing and checking those vendors is its own job, covered in vetting vendors before they undermine your compliance.
Worked example: Róisín leaves her email tool
Suppose Róisín wants to move off Klaviyo. Klaviyo's list and segment export to a CSV file can include each profile's email and SMS consent status and consent timestamp, but it cannot export the full event history.20 The events come out through the API instead, which returns 200 events a page by default and up to 1,000.21
If her consent history lives only in Klaviyo, the CSV gives her the current state and a timestamp, but not the wording, the source or the earlier changes. If she keeps the record in her own store, as in Jo's example, nothing is lost, and her orders already sit in Shopify and her warehouse. Same vendor, very different week.
Where custom code earns its place
None of this means writing everything yourself. In the old version of this article I described the split I use, and it still holds. Zapier or n8n are fine glue for reactions that are not critical and do not need to happen within the second. When the logic becomes real, checking margin before a discount, filtering on returns, I write it in Python or Node, against the record.
On one shop I worked on, the win back rule had three conditions: no order in 45 days, a lifetime value above 100, and the last item not returned. The email tool on that project could not see returns, so the rule ran as a scheduled job against the warehouse and sent each email through Postmark. The old article showed that code, and it was wrong: it used another vendor's address and message format. Postmark's API takes a POST to https://api.postmarkapp.com/email with the server token in the X-Postmark-Server-Token header.22 Marketing mail also belongs on a broadcast stream, which Postmark keeps on separate infrastructure from transactional mail and which requires an opt out link.23
An example: the job for Milk Market, with the consent check where it belongs, before the send.
import os
import requests
def send_winback(customer):
consent = customer["consents"]["email_marketing"]
if consent["state"] != "granted":
return "skipped: no email permission"
response = requests.post(
"https://api.postmarkapp.com/email",
headers={
"Accept": "application/json",
"X-Postmark-Server-Token": os.environ["POSTMARK_SERVER_TOKEN"],
},
json={
"From": "roisin@milkmarkettea.example",
"To": customer["email"],
"Subject": "Your Irish breakfast is nearly out",
"HtmlBody": render_winback(customer),
"MessageStream": "winback",
},
timeout=10,
)
response.raise_for_status()
return "sent"
Here winback is a broadcast stream Róisín created in Postmark, and render_winback builds the message with its unsubscribe link. Jo, with her email permission granted, would get it. A customer whose email_marketing state is denied returns at the first if, and no amount of clever segmentation upstream can change that.
What I would set up first
In order, for a shop of Milk Market's size:
- Put the consent fields on the customer record, with source, wording and time. Everything else depends on it.
- Use the native integrations between the shop, the email tool and the ad platforms, and filter every synced segment on the consent fields.
- Add the daily check that compares counts in and out. It is the least glamorous part and the best value.
- Add server side tagging or an event router when the browser setup is right and there is a question it answers.
- Build your own code only where the break even says so, or where the logic is genuinely yours, like the win back rule.
And if you are below a few hundred orders a month with one email tool, steps one and two are the whole project. The rest is a well engineered answer to a question you do not have yet.
The tools are rented, the record is yours
The glue is not in the tools. It is in the orchestration, and the orchestration rests on one record of each customer that says who they are, what they did and what they allowed. With that in place, every tool becomes replaceable, every sync can be checked, and every new channel starts from the same permissions. Without it, each subscription you add is another place for the truth to drift.
Footnotes
-
Klaviyo, Getting started with Shopify, Klaviyo Help Center, 2026, https://help.klaviyo.com/hc/en-us/articles/115005080407
-
Regulation (EU) 2016/679, General Data Protection Regulation, Article 7, conditions for consent, paragraphs 1 and 3, EUR-Lex, 2016, https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=CELEX:32016R0679
-
European Communities (Electronic Communications Networks and Services) (Privacy and Electronic Communications) Regulations 2011, S.I. No. 336 of 2011, regulation 13(1) and (11), Irish Statute Book, 2011, https://www.irishstatutebook.ie/eli/2011/si/336/made/en/print
-
European Communities (Electronic Communications Networks and Services) (Privacy and Electronic Communications) Regulations 2011, S.I. No. 336 of 2011, regulation 5(3) and (5), Irish Statute Book, 2011, https://www.irishstatutebook.ie/eli/2011/si/336/made/en/print
-
Data Protection Act 2018, section 14, transfer of functions of Data Protection Commissioner to Commission, Irish Statute Book, 2018, https://www.irishstatutebook.ie/eli/2018/act/7/enacted/en/print, read with regulation 17 of S.I. No. 336 of 2011, https://www.irishstatutebook.ie/eli/2011/si/336/made/en/print
-
Google, EU user consent policy, Google, 2026, https://www.google.com/about/company/user-consent-policy/
-
Google, Get started with Customer Match, Google Ads API documentation, Google for Developers, 2026, https://developers.google.com/google-ads/api/docs/remarketing/audience-segments/customer-match/get-started
-
Klaviyo, Pricing, Klaviyo, 2026, https://www.klaviyo.com/uk/pricing
-
RudderStack, Pricing, RudderStack, 2026, https://www.rudderstack.com/pricing/
-
Zapier, Plans and pricing, Zapier, 2026, https://zapier.com/pricing
-
Google, Cloud Run setup guide for server side tagging, Tag Platform, Google for Developers, 2026, https://developers.google.com/tag-platform/tag-manager/server-side/cloud-run-setup-guide
-
Google Cloud, Try BigQuery using the sandbox, BigQuery documentation, 2026, https://docs.cloud.google.com/bigquery/docs/sandbox
-
Twilio, Customer data pricing (Segment), Twilio, 2026, https://www.twilio.com/en-us/pricing/customer-data
-
Google, Customer Match policy, Google Ads Help, 2026, https://support.google.com/google-ads/answer/6299717
-
Klaviyo, Getting started with Google Ads, Klaviyo Help Center, 2026, https://help.klaviyo.com/hc/en-us/articles/6353315757211
-
Meta, Customer file Custom Audiences, Marketing API documentation, Meta for Developers, 2026, https://developers.facebook.com/docs/marketing-api/audiences/guides/custom-audiences
-
Shopify, Ignore duplicate webhooks, Shopify developer documentation, 2026, https://shopify.dev/docs/apps/build/webhooks/ignore-duplicates
-
Meta, Handling duplicate Pixel and Conversions API events, Meta for Developers, 2026, https://developers.facebook.com/docs/marketing-api/conversions-api/deduplicate-pixel-and-server-events
-
Regulation (EU) 2016/679, General Data Protection Regulation, Article 28, processor, paragraph 3(g), EUR-Lex, 2016, https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=CELEX:32016R0679
-
Klaviyo, How to export a list or segment to a CSV file, Klaviyo Help Center, 2026, https://help.klaviyo.com/hc/en-us/articles/115005078687
-
Klaviyo, Get Events, Klaviyo developer documentation, 2026, https://developers.klaviyo.com/en/reference/get_events
-
Postmark, Sending email with API, Postmark developer documentation, 2026, https://postmarkapp.com/developer/user-guide/send-email-with-api
-
Postmark, Message streams, Postmark, 2026, https://postmarkapp.com/message-streams