[object Object]

← back to Consulting Designerwallcoverings Com

attribution prep (DTD-A): per-channel UTM+coupon scheme (data/attribution-scheme.json), attribution-spec + gtag theme-install docs, inert G-XXXX gtag snippet; GA4 property + gtag-install gated to pending-approval

a4ad6c614058c21e65261646314c860ef5f0487f · 2026-07-26 15:30:19 -0700 · Steve Abrams

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Files touched

Diff

commit a4ad6c614058c21e65261646314c860ef5f0487f
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sun Jul 26 15:30:19 2026 -0700

    attribution prep (DTD-A): per-channel UTM+coupon scheme (data/attribution-scheme.json), attribution-spec + gtag theme-install docs, inert G-XXXX gtag snippet; GA4 property + gtag-install gated to pending-approval
    
    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---
 data/attribution-scheme.json | 160 +++++++++++++++++++++++++++++++++++++++++++
 docs/attribution-spec.md     | 135 ++++++++++++++++++++++++++++++++++++
 docs/gtag-theme-install.md   |  58 ++++++++++++++++
 snippets/gtag.html           |  65 ++++++++++++++++++
 4 files changed, 418 insertions(+)

diff --git a/data/attribution-scheme.json b/data/attribution-scheme.json
new file mode 100644
index 0000000..c6f0840
--- /dev/null
+++ b/data/attribution-scheme.json
@@ -0,0 +1,160 @@
+{
+  "_meta": {
+    "title": "Designer Wallcoverings — per-channel UTM + coupon attribution scheme",
+    "purpose": "Attribution-before-optimization (DTD verdict A). Every link a DW social/marketing channel emits carries a deterministic UTM stamp, and every offer carries a per-channel coupon code, so both click-path AND redemption-path conversions map back to the originating channel in GA4 + Shopify — even when link params are stripped (dark social, in-app browsers).",
+    "engagement": "DW consulting engagement, TK-19",
+    "authored": "2026-07-26",
+    "authored_by": "yolo-worker (SAFE-ONLY prep, no live writes)",
+    "destination_store": "designer-laboratory-sandbox.myshopify.com (LIVE Designer Wallcoverings Shopify store — legacy misnomer, treat as production)",
+    "storefront_domain": "www.designerwallcoverings.com",
+    "ga4_status": "Property provisioned for the main store per dw-analysis.json; measurement ID (G-XXXX) not yet rolled out. This scheme + the gtag snippet + the two pending-approval memos close that gap.",
+    "channels_connected": 7
+  },
+
+  "utm_convention": {
+    "case": "lowercase-kebab for campaign/content/term; lowercase for source/medium",
+    "encoding": "URL-encode all values; no spaces, no uppercase, no punctuation other than hyphen",
+    "params": {
+      "utm_source": "the channel key (facebook, instagram, tiktok, youtube, bluesky, threads, linkedin). One canonical token per platform — never 'fb', 'ig', 'yt' in the URL; the short forms are only used inside coupon codes.",
+      "utm_medium": "the traffic class. Controlled vocabulary: 'social' (organic feed/post), 'social-bio' (link-in-bio / profile link), 'social-story' (stories/reels/shorts swipe-ups), 'paid-social' (boosted/paid placements), 'social-dm' (direct-message / outreach links). Paid uses 'paid-social' so GA4 default-channel-grouping files it under Paid Social, not Organic Social.",
+      "utm_campaign": "campaign slug: <yyyy>-<qN>-<theme>, e.g. 2026-q3-elitis-launch, 2026-q3-staged-draft-drip, always-on-brand. Reuse the same slug across channels for one campaign so GA4 can compare channels within a campaign.",
+      "utm_content": "creative / placement variant for A/B and post-level attribution: <format>-<descriptor>, e.g. reel-grasscloth-bedroom, carousel-thibaut-5, pin-damask-hero. Optional but recommended.",
+      "utm_term": "reserved for paid keyword/audience on paid-social only; omit for organic."
+    },
+    "builder_template": "https://www.designerwallcoverings.com/{path}?utm_source={source}&utm_medium={medium}&utm_campaign={campaign}&utm_content={content}",
+    "notes": [
+      "Shopify preserves UTM params through to checkout and records them on the order (landing_site + referring params), so GA4 (client-side) AND Shopify (server-side order) both capture the same stamp.",
+      "For the ~50 sister-site microsite fleet used as a discovery network, add utm_source=<microsite-slug>&utm_medium=referral-microsite when they link into the flagship store — kept out of this file's per-channel table but same convention.",
+      "Always link to a canonical https://www.designerwallcoverings.com/... URL (not a myshopify.com URL) so cookies + GA4 hostname stay consistent."
+    ]
+  },
+
+  "coupon_convention": {
+    "why": "Link-based UTM is lost on dark social, pasted links, and in-app browsers that strip query strings. A unique per-channel discount code is a second, redemption-based attribution path: the code itself names the channel at checkout, independent of any URL param.",
+    "format": "DW-<CHANNELCODE>-<OFFER>",
+    "channel_codes": {
+      "facebook": "FB",
+      "instagram": "IG",
+      "tiktok": "TT",
+      "youtube": "YT",
+      "bluesky": "BS",
+      "threads": "TH",
+      "linkedin": "LI"
+    },
+    "offer_tokens": {
+      "SAMPLE": "free / discounted memo sample offer",
+      "10": "10% off order",
+      "15": "15% off order",
+      "TRADE": "to-the-trade design-pro incentive (LinkedIn / B2B lean)"
+    },
+    "examples": ["DW-IG-10", "DW-TT-SAMPLE", "DW-LI-TRADE", "DW-YT-15"],
+    "rules": [
+      "One code per (channel x offer) so redemptions bucket cleanly by channel.",
+      "Codes are created as Shopify discount codes — GATED, drafted in pending-approval, never created live by this prep pass.",
+      "Report redemptions from Shopify Admin > Discounts, cross-referenced with GA4 coupon (item-level 'coupon' param on purchase events) for a two-source check.",
+      "Keep offer economics identical across channels within a campaign so channel comparison isn't confounded by a richer offer on one platform."
+    ]
+  },
+
+  "channels": [
+    {
+      "key": "facebook",
+      "label": "Facebook Pages",
+      "connected": true,
+      "accounts": 80,
+      "profile": "https://www.facebook.com/DesignerWallcoverings/",
+      "utm_source": "facebook",
+      "utm_medium_default": "social",
+      "utm_medium_paid": "paid-social",
+      "coupon_code": "DW-FB-10",
+      "notes": "80 connected Pages (sister-site fleet). For per-Page attribution, extend utm_content with the page slug, e.g. utm_content=post-<pageslug>-<creative>. Meta strips fbclid but preserves utm_* on outbound link clicks."
+    },
+    {
+      "key": "instagram",
+      "label": "Instagram",
+      "connected": true,
+      "accounts": 34,
+      "profile": "https://www.instagram.com/designerwallcoverings/",
+      "utm_source": "instagram",
+      "utm_medium_default": "social-bio",
+      "utm_medium_story": "social-story",
+      "utm_medium_paid": "paid-social",
+      "coupon_code": "DW-IG-10",
+      "notes": "Primary click path is link-in-bio (social-bio) since feed posts aren't clickable; Stories/Reels use social-story. In-app browser frequently strips query params — the DW-IG-10 coupon is the reliable fallback attribution here. 34 accounts: use utm_content to carry the account handle if multi-account posting."
+    },
+    {
+      "key": "tiktok",
+      "label": "TikTok",
+      "connected": true,
+      "accounts": 1,
+      "profile": "https://www.tiktok.com/@designerwallcoverings",
+      "utm_source": "tiktok",
+      "utm_medium_default": "social-bio",
+      "utm_medium_paid": "paid-social",
+      "coupon_code": "DW-TT-SAMPLE",
+      "notes": "TikTok in-app browser is aggressive about stripping params — coupon attribution (DW-TT-SAMPLE) is essential. If TikTok Shop is later connected, that becomes its own server-side attribution surface separate from this UTM path."
+    },
+    {
+      "key": "youtube",
+      "label": "YouTube",
+      "connected": true,
+      "accounts": 1,
+      "profile": "https://www.youtube.com/@DesignerWallcoverings",
+      "utm_source": "youtube",
+      "utm_medium_default": "social",
+      "utm_medium_story": "social-story",
+      "utm_medium_paid": "paid-social",
+      "coupon_code": "DW-YT-15",
+      "notes": "Description links + pinned-comment links carry full UTM (YouTube preserves query strings). Shorts use social-story. Good candidate for utm_content=video-<slug> for per-video attribution."
+    },
+    {
+      "key": "bluesky",
+      "label": "Bluesky",
+      "connected": true,
+      "accounts": 1,
+      "profile": "",
+      "utm_source": "bluesky",
+      "utm_medium_default": "social",
+      "coupon_code": "DW-BS-10",
+      "notes": "Bluesky link cards preserve UTM. No paid surface — organic 'social' only. Low volume expected; still stamp so it's measurable rather than lumped into 'direct/unknown'."
+    },
+    {
+      "key": "threads",
+      "label": "Threads",
+      "connected": true,
+      "accounts": 1,
+      "profile": "",
+      "utm_source": "threads",
+      "utm_medium_default": "social",
+      "coupon_code": "DW-TH-10",
+      "notes": "Meta property; UTM preserved on outbound clicks but the Threads in-app browser can strip params, so DW-TH-10 backstops. Keep utm_source=threads distinct from facebook/instagram so Meta channels are separable in GA4."
+    },
+    {
+      "key": "linkedin",
+      "label": "LinkedIn",
+      "connected": true,
+      "accounts": 1,
+      "profile": "https://www.linkedin.com/company/designerwallcoverings/",
+      "utm_source": "linkedin",
+      "utm_medium_default": "social",
+      "utm_medium_paid": "paid-social",
+      "coupon_code": "DW-LI-TRADE",
+      "notes": "B2B / to-the-trade lean — offer token is TRADE (design-pro incentive) rather than a consumer % off. LinkedIn preserves UTM cleanly. Ideal for utm_campaign=always-on-trade + utm_content=article-<slug>."
+    }
+  ],
+
+  "ga4_events_to_configure": {
+    "note": "Enhanced measurement covers page_view, scroll, outbound click, site search, video, file download automatically. The commerce events below must be sent by the Shopify theme's dataLayer/gtag and then marked as key events (conversions) in GA4 Admin. Configuration is GATED (memo a); this list is the spec for that config.",
+    "standard_ecommerce": ["view_item", "add_to_cart", "begin_checkout", "add_shipping_info", "add_payment_info", "purchase"],
+    "dw_custom": ["request_sample", "sample_added_to_cart", "trade_account_signup", "email_signup", "quote_request"],
+    "key_events_conversions": ["purchase", "request_sample", "begin_checkout", "trade_account_signup", "email_signup"],
+    "coupon_capture": "On the purchase event, pass the item-level/coupon field with the redeemed discount code (e.g. DW-IG-10) so GA4 attributes revenue to the channel by coupon, matching the coupon_convention above."
+  },
+
+  "reporting_views": [
+    "GA4 Traffic acquisition, grouped by Session source / medium — validates the utm_source/utm_medium taxonomy is landing correctly.",
+    "GA4 Free-form exploration: Session source/medium (dimension) x Key events + Purchase revenue (metrics) — the core social-to-revenue attribution table across all 7 channels.",
+    "Shopify Admin > Discounts: redemptions per DW-<CHANNEL>-<OFFER> code — the redemption-path cross-check.",
+    "Campaign roll-up: filter by utm_campaign to compare channels head-to-head within one campaign (e.g. 2026-q3-elitis-launch across FB/IG/TT/YT/LI)."
+  ]
+}
diff --git a/docs/attribution-spec.md b/docs/attribution-spec.md
new file mode 100644
index 0000000..b95a552
--- /dev/null
+++ b/docs/attribution-spec.md
@@ -0,0 +1,135 @@
+# Designer Wallcoverings — Attribution Spec
+
+**Engagement:** DW consulting engagement (TK-19)
+**Date:** 2026-07-26
+**Status:** SPEC / PREP ONLY — no GA4 property created, no live theme touched, no Shopify discount created. Those steps are gated for Steve's approval (see `~/.claude/yolo-queue/pending-approval/`).
+**Machine-readable companion:** [`data/attribution-scheme.json`](../data/attribution-scheme.json)
+**Guiding decision:** DTD verdict **A — attribution before optimization**. You cannot optimize a channel mix you cannot measure; instrument first, then optimize.
+
+---
+
+## 1. The problem this solves
+
+DW has **7 connected marketing channels** (Facebook, Instagram, TikTok, YouTube, Bluesky, Threads, LinkedIn) driving traffic to the flagship **LIVE Shopify store** (`designer-laboratory-sandbox.myshopify.com`, served at `www.designerwallcoverings.com`). Today none of that traffic is attributable to revenue: the GA4 property is provisioned but **no measurement ID is installed**, and links carry no consistent UTM stamp. Every social conversion currently lands in "Direct / unknown."
+
+Two attribution paths close the gap, and we run **both** because each fails where the other survives:
+
+| Path | Mechanism | Survives | Fails when |
+|------|-----------|----------|------------|
+| **Click path (UTM)** | `utm_*` query params on every outbound link, read by GA4 | Description links, bio links, link cards | In-app browsers / dark social strip query strings |
+| **Redemption path (coupon)** | Unique per-channel Shopify discount code | Any checkout, params stripped or not | Customer doesn't use a code |
+
+Together they give a two-source triangulation: GA4 says "this session came from Instagram," Shopify says "this order redeemed `DW-IG-10`."
+
+---
+
+## 2. UTM taxonomy
+
+Every link a DW channel emits to the store is stamped:
+
+```
+https://www.designerwallcoverings.com/{path}
+    ?utm_source={source}
+    &utm_medium={medium}
+    &utm_campaign={campaign}
+    &utm_content={content}
+```
+
+**Rules**
+- **Lowercase** `source`/`medium`; **lowercase-kebab** for `campaign`/`content`. No spaces, no punctuation but hyphens. URL-encode everything.
+- Always link to a canonical `www.designerwallcoverings.com/...` URL — never a raw `*.myshopify.com` URL — so GA4 hostname and cookies stay consistent.
+- Reuse **one `utm_campaign` slug across channels** for a single campaign so GA4 can compare channels within it.
+
+### `utm_source` — one canonical token per channel
+
+`facebook` · `instagram` · `tiktok` · `youtube` · `bluesky` · `threads` · `linkedin`
+
+(The short forms `fb`/`ig`/`yt` are **only** used inside coupon codes, never in URLs.)
+
+### `utm_medium` — controlled vocabulary
+
+| Value | Use |
+|-------|-----|
+| `social` | Organic feed / post |
+| `social-bio` | Link-in-bio / profile link (IG, TikTok primary path) |
+| `social-story` | Stories / Reels / Shorts |
+| `paid-social` | Boosted / paid placement — files under **Paid Social** in GA4's default channel grouping, not Organic |
+| `social-dm` | Direct-message / outreach links |
+
+### `utm_campaign` — slug format
+
+`<yyyy>-<qN>-<theme>` — e.g. `2026-q3-elitis-launch`, `2026-q3-staged-draft-drip`, or `always-on-brand` for evergreen.
+
+### `utm_content` — creative / placement variant (optional, recommended)
+
+`<format>-<descriptor>` — e.g. `reel-grasscloth-bedroom`, `carousel-thibaut-5`, `video-<slug>`. For multi-account channels (FB = 80 Pages, IG = 34 accounts) carry the account/page slug here for per-account attribution.
+
+### `utm_term`
+
+Reserved for paid keyword/audience on `paid-social` only. Omit for organic.
+
+---
+
+## 3. Per-channel table
+
+| Channel | `utm_source` | Default `utm_medium` | Coupon code | Notes |
+|---------|-------------|----------------------|-------------|-------|
+| Facebook (80 Pages) | `facebook` | `social` | `DW-FB-10` | Per-Page: carry page slug in `utm_content`. |
+| Instagram (34 accts) | `instagram` | `social-bio` | `DW-IG-10` | Feed posts unclickable → bio link is primary; in-app browser strips params, coupon is the reliable fallback. |
+| TikTok | `tiktok` | `social-bio` | `DW-TT-SAMPLE` | Aggressive param stripping → coupon essential. |
+| YouTube | `youtube` | `social` | `DW-YT-15` | Description + pinned-comment links carry full UTM; Shorts → `social-story`. |
+| Bluesky | `bluesky` | `social` | `DW-BS-10` | Organic only, no paid surface. Low volume but still measurable vs "direct." |
+| Threads | `threads` | `social` | `DW-TH-10` | Meta property; keep source distinct from FB/IG so Meta channels separate in GA4. |
+| LinkedIn | `linkedin` | `social` | `DW-LI-TRADE` | B2B / to-the-trade lean → TRADE incentive instead of consumer % off. |
+
+**Microsite fleet (~50 sister sites):** when they link into the flagship, stamp `utm_source=<microsite-slug>&utm_medium=referral-microsite`. Same convention, out of the per-channel table.
+
+---
+
+## 4. Coupon scheme
+
+**Format:** `DW-<CHANNELCODE>-<OFFER>`
+
+- **Channel codes:** FB · IG · TT · YT · BS · TH · LI
+- **Offer tokens:** `SAMPLE` (memo sample), `10` / `15` (% off), `TRADE` (design-pro incentive)
+- **One code per (channel × offer)** so redemptions bucket cleanly by channel.
+- Keep offer economics **identical across channels within a campaign** so channel comparison isn't confounded.
+- Codes are Shopify discount codes — **GATED**, drafted for approval, never created by this prep pass.
+- Report from **Shopify Admin → Discounts** (redemptions per code) cross-referenced with GA4's item-level `coupon` param on `purchase`.
+
+---
+
+## 5. GA4 events & key events
+
+**Automatic (enhanced measurement):** `page_view`, `scroll`, outbound `click`, `view_search_results`, `video_*`, `file_download`.
+
+**Commerce events the Shopify theme must send** (via gtag / dataLayer): `view_item`, `add_to_cart`, `begin_checkout`, `add_shipping_info`, `add_payment_info`, `purchase`.
+
+**DW custom events:** `request_sample`, `sample_added_to_cart`, `trade_account_signup`, `email_signup`, `quote_request`.
+
+**Mark as Key Events (conversions):** `purchase`, `request_sample`, `begin_checkout`, `trade_account_signup`, `email_signup`.
+
+**Coupon capture:** on `purchase`, pass the redeemed discount code in the `coupon` field so GA4 attributes revenue to the channel by coupon, matching §4.
+
+> Event configuration is part of the **gated** GA4 setup (memo a). This section is the spec that setup implements.
+
+---
+
+## 6. Reporting views
+
+1. **GA4 → Reports → Acquisition → Traffic acquisition**, grouped by *Session source / medium* — validates the taxonomy is landing correctly.
+2. **GA4 → Explore → Free form:** *Session source/medium* × *Key events + Purchase revenue* — the core social-to-revenue table across all 7 channels.
+3. **Shopify Admin → Discounts:** redemptions per `DW-<CHANNEL>-<OFFER>` — redemption-path cross-check.
+4. **Campaign roll-up:** filter by `utm_campaign` to compare channels head-to-head within one campaign.
+
+---
+
+## 7. What's gated (not done here)
+
+This spec is prep. The following are drafted to `~/.claude/yolo-queue/pending-approval/` and require Steve's go:
+
+- **`attribution-ga4-property.md`** — create the GA4 property + web data stream, obtain the `G-XXXX` measurement ID, configure key events. (Checks for the already-provisioned property first — idempotent.)
+- **`attribution-gtag-install.md`** — install the gtag snippet (`snippets/gtag.html`) into the LIVE Shopify theme once the real measurement ID exists.
+- **Shopify discount codes** — creating the seven `DW-*` codes is a live Shopify write and would be drafted separately when Steve wants the coupon path armed.
+
+Local rebuild + commit only. **No deploy** — deploy of the portal is noted in the GA4 memo.
diff --git a/docs/gtag-theme-install.md b/docs/gtag-theme-install.md
new file mode 100644
index 0000000..9ded0ea
--- /dev/null
+++ b/docs/gtag-theme-install.md
@@ -0,0 +1,58 @@
+# gtag → Shopify theme insertion instructions
+
+**Snippet file:** [`snippets/gtag.html`](../snippets/gtag.html)
+**Target:** the LIVE Designer Wallcoverings Shopify theme (`designer-laboratory-sandbox.myshopify.com`).
+**Status:** GATED. Editing the live theme is customer-facing and production. Do **not** perform these steps autonomously — they are drafted in `~/.claude/yolo-queue/pending-approval/attribution-gtag-install.md` for Steve's approval. This file is the exact runbook that memo references.
+
+> ⚠️ **Prerequisite:** the real `G-XXXX` measurement ID must exist first (from the gated GA4-property step). Installing the placeholder `G-XXXX` collects nothing. Do GA4 property → get ID → replace placeholder → then install.
+
+---
+
+## Option A — Shopify's native GA4 integration (preferred, lowest risk)
+
+Shopify has a first-party GA4 connection that wires purchase + checkout events server-side without editing `theme.liquid`:
+
+1. Shopify Admin → **Online Store → Preferences → Google Analytics** (or **Settings → Customer events**).
+2. Paste the **`G-XXXX`** measurement ID into the Google Analytics 4 field / connect the Google & YouTube channel's GA property.
+3. This auto-sends `page_view`, `view_item`, `add_to_cart`, `begin_checkout`, and `purchase` with the standard ecommerce schema.
+4. Add any **DW custom events** (`request_sample`, `trade_account_signup`, `email_signup`) as a **Custom pixel** under Settings → Customer events, or via theme event handlers.
+
+**Why preferred:** survives theme updates, no Liquid edit, purchase event carries the order's discount code in `coupon` automatically. Use this unless a custom `<head>` tag is specifically required.
+
+---
+
+## Option B — manual gtag in `theme.liquid` (when a raw tag is required)
+
+1. **Back up first.** Shopify Admin → Online Store → Themes → ⋯ → **Duplicate** the live theme (so there's a one-click rollback). Do not edit the only copy.
+2. Themes → ⋯ → **Edit code** → open `layout/theme.liquid`.
+3. Paste the entire contents of `snippets/gtag.html` **inside `<head>`**, immediately after the `<meta charset>` / `<meta name="viewport">` lines and **before** any other `<script>`.
+   - Alternatively, add the file as a snippet named `gtag` and include it with `{% render 'gtag' %}` at the top of `<head>`.
+4. **Replace both `G-XXXX` occurrences** with the real measurement ID.
+5. **Save.** Shopify recompiles the theme immediately (this is live the moment you save).
+6. Confirm `cookie_domain` matches the storefront apex (`designerwallcoverings.com`).
+
+---
+
+## Verification (either option)
+
+1. **GA4 DebugView:** GA4 Admin → DebugView. Load `www.designerwallcoverings.com` with the GA Debugger extension (or `?_gl=` debug) → confirm `page_view` arrives in real time.
+2. **Realtime report:** GA4 → Reports → Realtime → confirm your session with the correct property.
+3. **Tag presence:** `curl -s https://www.designerwallcoverings.com/ | grep -o 'G-[A-Z0-9]\{8,\}'` → returns the real ID, not `G-XXXX`.
+   - Or run the analytics skill's verifier: `bash ~/.claude/skills/analytics/scripts/verify_rollout.sh`.
+4. **UTM round-trip:** open a stamped link (`?utm_source=instagram&utm_medium=social-bio&utm_campaign=test`) → GA4 Realtime → confirm source/medium = instagram / social-bio.
+5. **Coupon round-trip (after codes exist):** place a test order with `DW-IG-10` → confirm the `coupon` field appears on the `purchase` event and the redemption shows in Shopify Admin → Discounts.
+
+---
+
+## Rollback
+
+- **Option A:** clear the measurement ID field / disconnect the GA property. Instant.
+- **Option B:** Themes → publish the duplicated backup theme, OR remove the pasted block from `theme.liquid` and Save.
+
+---
+
+## Notes
+
+- The placeholder `snippets/gtag.html` is intentionally inert (`G-XXXX`) so it can live in the repo without collecting data or risking a wrong-property leak.
+- Enhanced measurement (scroll, outbound click, site search, video, file download) is toggled **in the GA4 web data stream settings**, not in this snippet.
+- Never commit the real measurement ID as the only copy in a public place; it's low-sensitivity but keep the repo's committed snippet on the placeholder and substitute at install time.
diff --git a/snippets/gtag.html b/snippets/gtag.html
new file mode 100644
index 0000000..8f7b6e0
--- /dev/null
+++ b/snippets/gtag.html
@@ -0,0 +1,65 @@
+{%- comment -%}
+  Designer Wallcoverings — GA4 gtag.js snippet
+  ============================================
+  PLACEHOLDER measurement ID: G-XXXX  ← replace with the real ID from the GA4 property
+  (obtained via the gated `attribution-ga4-property` step) BEFORE this goes live.
+
+  Placement: paste the block below as high in the <head> of `layout/theme.liquid`
+  as possible (immediately after the <meta charset> / <meta viewport> lines,
+  before other scripts). See docs/gtag-theme-install.md for exact instructions.
+
+  This snippet loads gtag and sends the automatic page_view. Enhanced measurement
+  (scroll, outbound click, site search, video, file download) is toggled ON in the
+  GA4 web data stream — no extra code needed for those.
+
+  The Shopify ecommerce events (view_item / add_to_cart / begin_checkout / purchase)
+  and the DW custom events (request_sample, trade_account_signup, email_signup) are
+  sent separately — see the commented reference block at the bottom of this file and
+  docs/attribution-spec.md §5. Do NOT hardcode order data here; Shopify's checkout /
+  Customer Events (web pixel) is the correct surface for purchase-level events.
+{%- endcomment -%}
+
+<!-- Google tag (gtag.js) — GA4 -->
+<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXX"></script>
+<script>
+  window.dataLayer = window.dataLayer || [];
+  function gtag(){dataLayer.push(arguments);}
+  gtag('js', new Date());
+
+  gtag('config', 'G-XXXX', {
+    // Preserve UTM params through internal navigation so source/medium survives to checkout.
+    'linker': { 'accept_incoming': true },
+    // DW store hostname — keeps attribution consistent across www + checkout.
+    'cookie_domain': 'designerwallcoverings.com'
+  });
+</script>
+<!-- End Google tag -->
+
+{%- comment -%}
+  ─────────────────────────────────────────────────────────────────────────────
+  REFERENCE ONLY — commerce + custom events (do not enable until GA4 is live).
+  These illustrate the event shape from §5 of the attribution spec. In Shopify,
+  prefer the Customer Events / web-pixel surface for purchase so the coupon field
+  is populated from the real order discount code (DW-<CHANNEL>-<OFFER>).
+
+  // Product page:
+  gtag('event', 'view_item', {
+    currency: 'USD',
+    value: {{ product.price | divided_by: 100.0 }},
+    items: [{ item_id: '{{ product.selected_or_first_available_variant.sku }}',
+              item_name: {{ product.title | json }} }]
+  });
+
+  // Purchase (from checkout / web pixel) — note the coupon field for channel attribution:
+  gtag('event', 'purchase', {
+    transaction_id: '{{ order.name }}',
+    value: {{ order.total_price | divided_by: 100.0 }},
+    currency: 'USD',
+    coupon: '{{ order.discount_applications.first.title }}',  // e.g. DW-IG-10
+    items: [ /* line items */ ]
+  });
+
+  // DW custom event example (sample request button handler):
+  // gtag('event', 'request_sample', { item_id: SKU, item_name: TITLE });
+  ─────────────────────────────────────────────────────────────────────────────
+{%- endcomment -%}

← 2a832f2 Traffic & Search Reality section: GSC 28d totals, 51% organi  ·  back to Consulting Designerwallcoverings Com  ·  TK-17 Phase 0: per-line GO/NO-GO decision sheet for the 22,9 f0b7063 →