PAID ADS SKILL
Attribution models
Which channel caused the sale: seven models and how each one lies, three measurement paradigms, reconciliation of platform, analytics and CRM numbers, and a first-party build track for stitching bookings to their source.
No key, no account needed
Claude Code
Cursor
CodexWindsurfany agent that reads SKILL.md
npx skills add addition-labs/skills --skill attribution
Run this in a terminal inside your project folder. Claude Code, Cursor and Codex then read the skill from where it lands.
- Step 01Open a terminal in your project folder
- Step 02Paste the command and press Enter
- Step 03Pick the agents to install to
- Step 04Ask the agent for the job; it reads the skill
attributionaddition-labs/skillsMIT licencev1.1.0updated 2026-09-05
Two pillars. Interpretation: choose a model, choose a paradigm (multi-touch, mix modelling, incrementality), and reconcile the dashboards that disagree. Build: instrument attribution yourself with an identify() call at conversion and a metadata passthrough for conversions that complete on a domain you do not own, such as a booking tool or hosted checkout.
The framing is plain about its limits. Attribution is directional, every model is an opinion, the gap between channel-reported and real conversions is normal, and when direct and branded search dominate, the skill reads it as a sign that top of funnel is working and tracking is hiding it; it is one reading, and existing demand or returning customers can produce the same picture.
The readout format ends with a table that de-duplicates against the source of truth instead of summing, and a first-touch versus last-touch comparison whose gap is the insight.
When to use it
The phrases that trigger it
Say any of these and an agent that has the skill installed will usually load it; you can also call it by name. The phrases are the skill’s own, from its description.
- attribution model
- first-touch vs last-touch
- multi-touch
- what’s my real CAC
- my dashboards disagree
- MMM
- incrementality
- geo lift
- self-reported attribution
- dark social
What’s inside
The playbook, section by section
Seven models and how each lies
First-touch, last-touch, last non-direct, linear, time-decay, position-based, data-driven, with the bias of each in one line.
Three paradigms
MTA needs clean user-level tracking that privacy has gutted; MMM needs two to three years of weekly data; incrementality is the gold standard and can only test a few things at a time.
Self-reported attribution
A "how did you hear about us" at the moment of conversion, pick-list plus free text, treated as a triangulation input.
Reconciliation
One source of truth for the count, never sum across platforms, read directional agreement, self-reported as tiebreaker, budget for the gap.
The identify() gap
The commonest first-party failure: nothing ever calls identify, so every customer appears from nowhere.
Third-party domain stitching
A capture-phase link decorator appends the anonymous id to the outbound URL; the tool’s webhook returns it; the handler merges identities and fires the conversion event.
Reference files the agent loads on demand
4 files in the skill folder, read only when an instruction calls for one.
attribution-models.md- Six models, one journey scored six ways, and data-driven attribution explained without the black box.
measurement-paradigms.md- Multi-touch attribution, marketing mix modelling and incrementality: what each can and cannot tell you.
by-business-type.md- Attribution defaults by business model: which source of truth, model and paradigm fit which cycle length.
first-party-tracking.md- A runbook for instrumenting and stitching attribution yourself when you control the site.
See it in action
One real run, in full
The request on the left went to the skill as installed. On the right is everything it returned, unedited; scroll inside the box to read it all.
Our client is a Shopify DTC brand running Google Ads and Meta. Both ad dashboards claim more paid conversions than Shopify records, and the two platforms together claim more than the store's total orders. Before we reallocate budget between them, help us choose an attribution model and reconcile the three reports. We do not have a CRM; Shopify is the order system.
Attribution Readout — 2026-09-11
Pillar: (A) Interpretation. You are choosing a model and reconciling three reports; you are not building first-party tracking. Nothing below needs engineering.
Business type: Ecommerce / DTC, short self-serve cycle, Shopify checkout, spend concentrated in Meta + Google. The DTC playbook applies throughout.
What I do not have: the actual numbers. You have not shared the Shopify order count, the Google Ads conversion count, the Meta conversion count, the date range, the attribution windows, or the spend. Every cell below that needs one of those is left as "—". The structure and the method are complete; you fill the cells, and the readout becomes the decision document.
The question
Should budget move between Google Ads and Meta, and in which direction?
Underneath it, the real question: how many of the orders each platform claims did it actually cause? Right now you cannot answer that, because both platforms are counting the same orders, and the sum exceeds the store total. That is not a bug in either dashboard. It is what platform attribution always does. The fix is not to make the three numbers match. They never will. The fix is to anchor on one number, de-dupe the other two against it, and then run one test that settles the overlap.
Do not reallocate on the current dashboards. Moving spend toward whichever platform reports the higher conversion count rewards whichever platform over-claims harder.
Source of truth
Shopify defines the conversion count. It is the system where the money is real: an order either exists there or it does not. You have no CRM, and for DTC you do not need one for this; the store is the backend.
Consequences, stated bluntly:
- The Shopify order total for the period is the ceiling. Paid orders cannot exceed it; paid orders plus organic, email, direct and everything else must equal it.
- Google Ads and Meta explain *where some of those orders came from*. They do not get to redefine *how many orders there were*.
- Never sum Google and Meta. If Google claims an order and Meta claims the same order, you have one order with two claimants. That is the whole reason your combined platform count is above the store total.
Two Shopify things to check before you fill in the table:
- Which Shopify number are you using? Total orders includes orders from every channel plus manual/draft orders and possibly POS. For this exercise use online-store orders for the exact same date range the ad platforms report on, and decide once whether refunds/cancellations are in or out. Use the same rule on all three reports.
- Shopify's own marketing attribution (Marketing / Sales attributed to marketing reports) uses its own model and window. It is a fourth opinion, useful as a last-non-direct-click view, but it is not the source of truth either. The order count is; Shopify's channel split is one more input.
What each source says
De-duped against the Shopify total, never summed. Columns adapted from the skill's template: there is no GA and no CRM here, so Shopify stands in for the CRM column, and Self-reported is empty until you install a survey.
| Channel | Platform-reported (own dashboard) | Shopify attributed (last non-direct click) | Self-reported survey | Our read |
|---|---|---|---|---|
| Google Ads | — | — | — (no survey yet) | — |
| Meta Ads | — | — | — (no survey yet) | — |
| Email / SMS | n/a | — | — | — |
| Organic search | n/a | — | — | — |
| Direct / unknown | n/a | — | — | — |
| Total orders (Shopify) | Google + Meta claims = — (must be > Shopify paid; that is your gap) | = — (the ceiling) |
How to fill it, in order:
Step 1. Align the counting rules before comparing anything. The three reports are currently measuring different things. Line them up:
| Setting | Google Ads | Meta | Shopify |
|---|---|---|---|
| Date range | same range, same timezone | same | same |
| What counts as a conversion | the Purchase action only; exclude add-to-cart, begin-checkout, and any secondary actions that are set to "include in Conversions" | the Purchase event only, from the pixel/CAPI dataset tied to this store | an order |
| Attribution window | check the account's click-through window and whether view-through / engaged-view conversions are in the column you are reading | check the ad-set attribution setting; a "1-day view" component means impressions with no click are being counted as conversions | order date |
| Attribution model | check whether the conversion action is on data-driven or last-click | Meta reports on its own model; there is no switch | last non-direct click within Shopify's window |
| Conversion date | Google reports by click/interaction date by default, not by conversion date | Meta reports by impression/click date | order date |
Until these match, the numbers are not even comparable, let alone reconcilable. The date-of-click vs date-of-order difference alone puts orders in different weeks across the three reports. Verify each window in the actual account settings rather than assuming a default; defaults change and accounts get edited.
Step 2. Strip what Shopify structurally cannot see. View-through conversions (Meta 1-day view, Google view-through/engaged-view) are conversions where the person never clicked. Shopify will never attribute those to the platform because there is no click to land on. Pull them out into their own row so the click-based numbers can be compared like with like. Keep the view-through counts visible; they are not fake, they are simply unverifiable from your side.
Step 3. De-dupe the click conversions against Shopify. With windows aligned and view-through separated, compare each platform's click conversions to Shopify's attributed orders for that channel. The remaining excess is the platform claiming orders that either (a) another channel closed after the click, (b) landed outside Shopify's window, (c) were modeled/estimated post-iOS rather than observed, or (d) were counted twice by the platform itself (duplicate purchase events from pixel + CAPI without deduplication is a common cause; that is an ads-skill fix, not an attribution one, but check it, because it inflates the platform count before any attribution logic runs).
Step 4. Report the gap, not a forced tie-out. The output sentence is: *"Google and Meta together claim — purchases. Shopify records — online orders in the same window, of which — are attributable to any paid click. The delta of — is view-through + over-claiming + modeled conversions + window mismatch. Here is how we allocate the overlap."*
Model comparison
The skill's side-by-side (first-touch vs last-touch) is built for long cycles. Yours is short, so the comparison is smaller, but it still exists and still carries the insight.
Recommended model: last non-direct click, applied consistently in one place, with Shopify as the order count.
Why this and not the alternatives:
- Last-touch / last non-direct click is defensible for quick-turn DTC. The closing click really is most of the story for an impulse or low-consideration purchase. It gets less defensible as AOV rises and consideration lengthens, because it over-credits retargeting and branded search. If this brand sells a considered, higher-AOV product, note that and lean harder on the survey and the test below.
- Data-driven (Google's default) is a black box that only sees Google's own touches and needs volume. It cannot see Meta, so it cannot arbitrate Google vs Meta, which is exactly the decision you are trying to make. Leave it on for in-platform bidding if you like; do not use it for cross-channel budget truth.
- First-touch, linear, time-decay, position-based add little on a journey that is often one or two touches long. The information they would carry (what created the demand) is better captured by the survey.
What to look at side by side: each platform's own claimed count against Shopify's last-non-direct-click count for that same platform. That gap is the model comparison for a DTC brand. A platform whose own number sits far above its Shopify-attributed number is either heavy on view-through and modeled conversions, or is taking credit for orders another channel closed. Meta prospecting and retargeting usually show the wider gap; Google Shopping and non-brand search usually the narrower. Confirm with your numbers rather than assuming.
One caveat to name now: if a large share of Shopify orders land as direct or branded search, that is not a channel. It is demand created somewhere else (often Meta, often organic/social/word of mouth) cashing out. Last-click will hand that credit to branded search and direct. Segment branded from non-branded Google spend before you compare Google to Meta, or Google will look better than it is.
Confidence & gaps
- The attribution gap is expected and permanent. Two platforms claiming more than the store's total is the normal state. You can shrink it and explain it; you cannot close it.
- Platform ROAS is fine for the algorithm, not for the budget. Post-iOS ATT both platforms model and estimate conversions and use generous windows. Reported ROAS runs above incremental ROAS. Keep it for in-platform optimization; do not let it decide the Google-vs-Meta split.
- View-through is unverifiable from Shopify. It is not zero, and it is not what the platform says either. Its true value only shows up in a holdout test.
- Self-reported: currently no signal. No post-purchase survey means dark social, organic TikTok/Instagram, word of mouth and podcast-style touches are invisible. Whatever they drive is landing in direct and branded search today.
- AI-search traffic arrives as direct or branded search and is invisible here. Named as a blind spot only; deeper work belongs to ai-seo.
- MMM is not the answer at this stage unless blended monthly spend is material (the reference puts the threshold around six figures a month) and you have two to three years of weekly data with real spend variation. Below that, good UTMs plus a survey plus one test does more.
- Confidence in a reallocation right now: low. The inputs disagree, the counting rules are not yet aligned, and there is no out-of-model check. Confidence rises to medium after Steps 1 to 4 above, and to high only after the incrementality test.
Recommendation
1. This week: align and de-dupe (Steps 1 to 4). Same date range, purchase-only conversion actions, view-through separated, click conversions compared to Shopify's attributed orders per platform. Fill the table. Pull the platform numbers into one sheet (Supermetrics or Coupler if you want it repeatable; a manual export is fine once). Confirm pixel + CAPI deduplication on Meta while you are in there.
2. Adopt one model and stop switching. Last non-direct click, read in Shopify, is the operating model. Platform dashboards stay open for in-platform optimization only. State this to the client in writing, including the sentence "every model is an opinion; this is the one we will be consistent with."
3. Install a one-question post-purchase survey on the Shopify order-confirmation page ("How did you first hear about us?", pick-list of your known channels plus a free-text "other"). Ask at the moment of purchase. This is the out-of-model check that tells you what is hiding in direct and branded search, and the cheapest tiebreaker you can get. Treat it as triangulation, not gospel; people credit the memorable touch.
4. The tiebreaker test worth running: an incrementality test on the channel with the widest platform-vs-Shopify gap. Two platforms fighting over the same orders is precisely the case the skill reserves incrementality for. Options, cheapest first:
- On/off pulse test: pause the disputed campaign type (retargeting is the usual candidate, then branded search) for a defined window and watch total Shopify orders, not platform conversions. Crude, but it directly answers "would these orders have happened anyway?"
- Geo holdout / geo-lift (Meta GeoLift, Google geo experiments) on the bigger of the two platforms if volume allows a clean split.
- Read the result as lift = exposed rate minus control rate, check the interval before believing the point estimate, and translate to incremental CPA = spend ÷ incremental orders. That number, not reported CPA, is what moves the budget. Expect it to be worse than either dashboard says; that is the point.
5. Reallocate only after step 4, and move budget in steps rather than a single swing. Re-read the de-duped table after each move and watch for directional agreement across the three sources; if Shopify, the survey and the platforms all say the same channel is trending up, trust the trend even though the absolute numbers will never match.
What I need from you to turn this into the actual allocation call: Shopify online-order count for the period; Google Ads purchase conversions with the window and model noted, view-through shown separately; Meta purchase conversions with the attribution setting noted, 1-day view shown separately; spend per platform; AOV; and whether branded search is split out. With those, the "—" cells fill in and the Recommendation section gets numbers and confidence levels attached.
What this run could not do
Every number. The request carried no order counts, conversions, spend, date range, windows or average order value, so the "what each source says" table is left empty with the fill-in method spelled out, and the self-reported column is empty because no survey exists yet. The template's GA and CRM columns do not exist for this store, so Shopify stands in for the CRM.
Method behind it
Where we would differ, and why
Our ROAS glossary explains why platform-reported return is the number every platform inflates and what to divide by instead. This skill is the long version: it names each dashboard’s bias and gives you the reconciliation table.
The skill anchors ecommerce on platform ROAS "but distrust it" and validates with MMM once spend is material. For most DTC stores below a few hundred thousand a year in ad spend, MMM never becomes feasible; the post-purchase survey and a geo holdout are the whole toolkit.
The data-driven attribution note says Google relaxed the minimums and made DDA the default. That is right; the earlier gate of 3,000 interactions and 300 conversions is retained as history, which is the right way to keep it.

SKILL.md
The file the agent reads
Written by Corey Haines and published under the MIT licence. Read the full file (3,093 words) on GitHub, at the commit we reviewed: coreyhaines31/marketingskills/skills/attribution/SKILL.md. The reference files are in the same folder.
Questions
Questions people ask before installing
We only have Shopify and two ad platforms. Is this skill overkill?
The reconciliation section is written for exactly that case: Shopify is the source of truth for the count, each platform reports the orders it claims a part in, and a post-purchase survey catches what pixels miss.
Do I need PostHog for the build track?
No. The pattern is identify plus merge plus a metadata passthrough on the third-party tool; PostHog and SavvyCal are the worked example.
Where does AI search traffic show up?
The skill names it as a blind spot: assistants influence buyers who then arrive via branded search or direct. It hands the deeper work to the ai-seo skill.



