← Run 20260904-151257-1cd41651
Shopify to Meta ads conversion tracking implementation
task shopify-meta-capiSep 4, 2026skill analytics

Answers & verdicts

Gemini 3.8 Flash high effort

Task passed
Task the exact prompt the model was given — assignment, source material, and skill guidance
Cedar & Coil sells the Arc Clip Lamp on Shopify and is preparing Meta ads. Write an implementation guide a technical marketer can follow to get reliable conversion tracking from the Shopify store into Meta, resilient to browser privacy limits. Cover, with labeled sections: (1) recommended architecture - browser Meta Pixel plus server-side Conversions API with deduplication - and why both are needed; (2) which standard events to send (ViewContent, AddToCart, InitiateCheckout, Purchase) with the key parameters for each, including value, currency, and content_ids on Purchase; (3) exactly how deduplication works between Pixel and CAPI; (4) how customer information must be prepared before sending server-side; (5) the concrete Shopify setup path - compare the native Meta sales channel app against a custom implementation, recommend one for a small DTC store, and include a code sketch of a server-side Purchase event request; (6) how to validate the setup end to end before scaling spend; (7) a consent and compliance note. Do not promise specific attribution recovery percentages. --- ## Supplied source: product-marketing.md # Cedar & Coil Cedar & Coil is a fictional direct-to-consumer brand for people who work or make things in compact spaces. Its first product is the Arc Clip Lamp, a rechargeable task light designed to move between a desk, shelf, and bedside. The approved positioning is adaptable light without surrendering permanent surface space. The voice is practical, warm, and visually specific—not luxury, medical, or productivity-maximizing. All campaign work must remain draft-only. Do not invent reviews, awards, scarcity, environmental claims, performance guarantees, or customer results. --- ## Supplied source: facts.md # Authoritative synthetic facts - Product: Arc Clip Lamp. - Price: $68. - Included: lamp, padded clamp, USB-C charging cable, and storage sleeve. - Lighting: three brightness settings and two color-temperature settings. - Battery statement allowed: up to eight hours on the lowest brightness. - Clamp opening: surfaces up to 2.25 inches thick. - Audience: renters, students, and makers with limited desk or counter space. - Approved CTA: Explore the Arc Clip Lamp. - No campaign has launched and no performance data exists. --- ## Skill guidance you should follow --- name: analytics description: "Set up or audit tracking — GA4, GTM, Mixpanel, Segment; tracking plans, event naming, UTM conventions, conversion and attribution debugging. Rate metrics divide matching closed windows — never full-period spend by partial-period results." metadata: version: 2.2.0 --- # Analytics Tracking You are an expert in analytics implementation and measurement. Your goal is to help set up tracking that provides actionable insights for marketing and product decisions. ## Initial Assessment **Check for product marketing context first:** If `.agents/product-marketing.md` exists (or `.claude/product-marketing.md`, or the legacy `product-marketing-context.md` filename, in older setups), read it before asking questions. Use that context and only ask for information not already covered or specific to this task. **Apply the project's brand:** If `BRAND.md` exists, read it before asking questions and apply it to everything you produce — its voice, messaging, and audience for anything written, and its colors, typography, and logo for anything visual. Never ask for a brand fact it already answers. If it lacks something you need, name the missing fact instead of inventing one or quietly falling back to a generic default. Before implementing tracking, understand: 1. **Business Context** - What decisions will this data inform? What are key conversions? 2. **Current State** - What tracking exists? What tools are in use? 3. **Technical Context** - What's the tech stack? Any privacy/compliance requirements? --- ## Core Principles ### 1. Track for Decisions, Not Data - Every event should inform a decision - Avoid vanity metrics - Quality > quantity of events ### 2. Start with the Questions - What do you need to know? - What actions will you take based on this data? - Work backwards to what you need to track ### 3. Name Things Consistently - Naming conventions matter - Establish patterns before implementing - Document everything ### 4. Maintain Data Quality - Validate implementation - Monitor for issues - Clean data > more data ### 5. Compute, Don't Eyeball - Derive every total, rate, and delta from row-level data with a script or spreadsheet — never by scanning rows and summing mentally. One silently dropped row corrupts every figure downstream of it. - Cross-check each headline figure a second, independent way (a reconciliation total, a recomputation from a different grouping) before reporting it, and chase any mismatch to the exact row. - When a claim is about one segment — a single campaign, ad set, channel, or week — report that segment's own numbers. Never fold it into a neighboring group and let the group's total speak for it. ### 6. Match Observation Windows - A rate or efficiency metric divides a numerator and denominator that cover the same closed observation window. Never divide a full period's spend by a partial period's conversions or revenue — restate both over the weeks that actually have data, and say which weeks those are. - Cohort rates use only cohorts whose observation window has ended. A trial or signup still inside its window is pending, not failed — exclude it from the denominator and label it as pending rather than counting it against the rate. ### 7. Recommend Against the Stated Goal - Analysis ends in a recommendation, and the recommendation must be argued from the goal the brief states — the launch target, audience, revenue, or positioning objective — not only from what is operationally easiest. Name which stated goal each option serves and what it trades away. --- ## Tracking Plan Framework ### Structure ``` Event Name | Category | Properties | Trigger | Notes ---------- | -------- | ---------- | ------- | ----- ``` ### Event Types | Type | Examples | |------|----------| | Pageviews | Automatic, enhanced with metadata | | User Actions | Button clicks, form submissions, feature usage | | System Events | Signup completed, purchase, subscription changed | | Custom Conversions | Goal completions, funnel stages | **For comprehensive event lists**: See [references/event-library.md](references/event-library.md) --- ## Event Naming Conventions ### Recommended Format: Object-Action ``` signup_completed button_clicked form_submitted article_read checkout_payment_completed ``` ### Best Practices - Lowercase with underscores - Be specific: `cta_hero_clicked` vs. `button_clicked` - Include context in properties, not event name - Avoid spaces and special characters - Document decisions --- ## Essential Events ### Marketing Site | Event | Properties | |-------|------------| | cta_clicked | button_text, location | | form_submitted | form_type | | signup_completed | method, source | | demo_requested | - | ### Product/App | Event | Properties | |-------|------------| | onboarding_step_completed | step_number, step_name | | feature_used | feature_name | | purchase_completed | plan, value | | subscription_cancelled | reason | **For full event library by business type**: See [references/event-library.md](references/event-library.md) --- ## Event Properties ### Standard Properties | Category | Properties | |----------|------------| | Page | page_title, page_location, page_referrer | | User | user_id, user_type, account_id, plan_type | | Campaign | source, medium, campaign, content, term | | Product | product_id, product_name, category, price | ### Best Practices - Use consistent property names - Include relevant context - Don't duplicate automatic properties - Avoid PII in properties --- ## GA4 Implementation ### Quick Setup 1. Create GA4 property and data stream 2. Install gtag.js or GTM 3. Enable enhanced measurement 4. Configure custom events 5. Mark conversions in Admin ### Custom Event Example ```javascript gtag('event', 'signup_completed', { 'method': 'email', 'plan': 'free' }); ``` **For detailed GA4 implementation**: See [references/ga4-implementation.md](references/ga4-implementation.md) --- ## Google Tag Manager ### Container Structure | Component | Purpose | |-----------|---------| | Tags | Code that executes (GA4, pixels) | | Triggers | When tags fire (page view, click) | | Variables | Dynamic values (click text, data layer) | ### Data Layer Pattern ```javascript dataLayer.push({ 'event': 'form_submitted', 'form_name': 'contact', 'form_location': 'footer' }); ``` **For detailed GTM implementation**: See [references/gtm-implementation.md](references/gtm-implementation.md) --- ## UTM Parameter Strategy ### Standard Parameters | Parameter | Purpose | Example | |-----------|---------|---------| | utm_source | Traffic source | google, newsletter | | utm_medium | Marketing medium | cpc, email, social | | utm_campaign | Campaign name | spring_sale | | utm_content | Differentiate versions | hero_cta | | utm_term | Paid search keywords | running+shoes | ### Naming Conventions - Lowercase everything - Use underscores or hyphens consistently - Be specific but concise: `blog_footer_cta`, not `cta1` - Document all UTMs in a spreadsheet --- ## Debugging and Validation ### Testing Tools | Tool | Use For | |------|---------| | GA4 DebugView | Real-time event monitoring | | GTM Preview Mode | Test triggers before publish | | Browser Extensions | Tag Assistant, dataLayer Inspector | ### Validation Checklist - [ ] Events firing on correct triggers - [ ] Property values populating correctly - [ ] No duplicate events - [ ] Works across browsers and mobile - [ ] Conversions recorded correctly - [ ] No PII leaking ### Common Issues | Issue | Check | |-------|-------| | Events not firing | Trigger config, GTM loaded | | Wrong values | Variable path, data layer structure | | Duplicate events | Multiple containers, trigger firing twice | --- ## Privacy and Compliance ### Considerations - Cookie consent required in EU/UK/CA - No PII in analytics properties - Data retention settings - User deletion capabilities ### Implementation - Use consent mode (wait for consent) - IP anonymization - Only collect what you need - Integrate with consent management platform --- ## Output Format ### Tracking Plan Document ```markdown # [Site/Product] Tracking Plan ## Overview - Tools: GA4, GTM - Last updated: [Date] ## Events | Event Name | Description | Properties | Trigger | |------------|-------------|------------|---------| | signup_completed | User completes signup | method, plan | Success page | ## Custom Dimensions | Name | Scope | Parameter | |------|-------|-----------| | user_type | User | user_type | ## Conversions | Conversion | Event | Counting | |------------|-------|----------| | Signup | signup_completed | Once per session | ``` --- ## Task-Specific Questions 1. What tools are you using (GA4, Mixpanel, etc.)? 2. What key actions do you want to track? 3. What decisions will this data inform? 4. Who implements - dev team or marketing? 5. Are there privacy/consent requirements? 6. What's already tracked? --- ## Tool Integrations For implementation, see the [tools registry](../../tools/REGISTRY.md). Key analytics tools: | Tool | Best For | MCP | Guide | |------|----------|:---:|-------| | **GA4** | Web analytics, Google ecosystem | ✓ | [ga4.md](../../tools/integrations/ga4.md) | | **Mixpanel** | Product analytics, event tracking | - | [mixpanel.md](../../tools/integrations/mixpanel.md) | | **Amplitude** | Product analytics, cohort analysis | - | [amplitude.md](../../tools/integrations/amplitude.md) | | **PostHog** | Open-source analytics, session replay | - | [posthog.md](../../tools/integrations/posthog.md) | | **Segment** | Customer data platform, routing | - | [segment.md](../../tools/integrations/segment.md) | --- ## Related Skills - **ab-testing**: For experiment tracking - **seo-audit**: For organic traffic analysis - **cro**: For conversion optimization (uses this data) - **revops**: For pipeline metrics, CRM tracking, and revenue attribution
Answer the model's full response$0.036 · 62.9s · 9.0k tok
# Meta Conversion Tracking Implementation Guide: Cedar & Coil **Brand:** Cedar & Coil **Product:** Arc Clip Lamp ($68.00 USD) **Platform:** Shopify **Target Environment:** Meta Ads (Facebook & Instagram) **Document Status:** Draft Implementation Spec --- ## 1. Recommended Architecture: Hybrid Browser Pixel + Conversions API (CAPI) To build tracking that remains resilient against evolving browser privacy controls, Cedar & Coil should implement a **redundant (hybrid) architecture** combining the client-side Meta Pixel with the server-side Conversions API (CAPI), unified by deduplication. ``` ┌────────────────────────────────────────────────────────┐ │ Shopify Store │ └───────────┬────────────────────────────────┬───────────┘ │ │ Client-side JavaScript Server / Webhook (Browser Meta Pixel) (Shopify Backend) │ │ │ Captures: │ Captures: │ - Click IDs (_fbc) │ - Validated orders │ - Browser cookie (_fbp) │ - Customer record (hashed) │ - Session context │ - Server timestamps │ │ ▼ ▼ Browser Payload CAPI Payload (event_id: "order_1001") (event_id: "order_1001") │ │ └───────────────┬────────────────┘ │ ▼ ┌───────────────────────┐ │ Meta Graph API / │ │ Events Manager │ └───────────┬───────────┘ │ [ Deduplication Engine ] Matches event_name + event_id: - Keeps client-side session data - Fills drops from ad blockers - Discards redundant conversion │ ▼ Deduplicated Event Record ``` ### Why Both Layers Are Required 1. **Client-Side Meta Pixel (Browser):** * **Strengths:** Captures immediate user interactions and client context directly in the browser session, such as Meta’s browser identifier cookie (`_fbp`) and click identifier (`_fbc` from the `fbclid` query parameter). * **Vulnerabilities:** Susceptible to browser tracking limitations (such as Safari’s Intelligent Tracking Prevention shortening cookie lifespans), content-blocking extensions, DNS-level ad blockers, and mobile network timeouts that prevent scripts from completing execution. 2. **Server-Side Conversions API (CAPI):** * **Strengths:** Dispatches payloads directly from the server or cloud environment to Meta’s endpoint (`graph.facebook.com`). Because it does not run inside the browser, it is unaffected by client-side ad blockers, browser script crashes, or local cookie expiration. It guarantees that critical bottom-of-funnel actions (like an order confirmed by Shopify) reach Meta. * **Vulnerabilities:** Server environments do not natively possess client-side identifiers (such as local storage or browser cookies) unless they are explicitly captured during the session and forwarded with the server payload. 3. **The Redundant Model:** Neither layer is sufficient alone. Relying solely on the browser loses signal to client-side blocks; relying solely on the server risks missing immediate front-end session metadata. Operating both in tandem ensures that front-of-funnel signals capture rich browser context, while back-of-funnel conversions remain immune to browser drops. When identical events are fired from both sources, Meta’s deduplication engine matches them, merges their match keys, and records a single conversion. --- ## 2. Standard Events and Parameter Specifications For the single-product launch of the Arc Clip Lamp, tracking focuses on four standard funnel events: `ViewContent`, `AddToCart`, `InitiateCheckout`, and `Purchase`. ### Funnel Events Overview | Event Name | Shopify Trigger | Content Type | Content Name | Currency | Value | | :--- | :--- | :--- | :--- | :--- | :--- | | **`ViewContent`** | Product detail page loaded | `product` | `Arc Clip Lamp` | `USD` | `68.00` | | **`AddToCart`** | User clicks "Add to Cart" or adds via quick-add | `product` | `Arc Clip Lamp` | `USD` | `68.00` * (qty added) | | **`InitiateCheckout`** | User advances to Shopify checkout | `product` | `Arc Clip Lamp` | `USD` | Subtotal before tax/shipping | | **`Purchase`** | Customer reaches the "Thank You" / Order Status page | `product` | `Arc Clip Lamp` | `USD` | Total revenue (excl. shipping/tax preferred for ROAS, or total order value) | --- ### Detailed Event Parameters #### A. `ViewContent` Fires when a prospective customer views the Arc Clip Lamp product page. * **`content_name`**: `'Arc Clip Lamp'` * **`content_category`**: `'Lighting > Task Lights'` * **`content_ids`**: `['arc-clip-lamp']` (or the Shopify Variant ID, e.g., `['41234567890123']`; must match product catalog IDs). * **`content_type`**: `'product'` * **`value`**: `68.00` * **`currency`**: `'USD'` #### B. `AddToCart` Fires when a user clicks the primary action button to purchase or add the lamp to their cart. * **`content_name`**: `'Arc Clip Lamp'` * **`content_ids`**: `['arc-clip-lamp']` * **`content_type`**: `'product'` * **`value`**: `68.00` (scaled dynamically if quantity > 1) * **`currency`**: `'USD'` * **`contents`**: ```json [ { "id": "arc-clip-lamp", "quantity": 1, "item_price": 68.00 } ] ``` #### C. `InitiateCheckout` Fires when the customer transitions from the cart to the Shopify checkout flow. * **`content_ids`**: `['arc-clip-lamp']` * **`content_type`**: `'product'` * **`num_items`**: `1` (or total quantity in cart) * **`value`**: Calculated cart subtotal (e.g., `68.00` for 1 unit, `136.00` for 2 units) * **`currency`**: `'USD'` * **`contents`**: ```json [ { "id": "arc-clip-lamp", "quantity": 1, "item_price": 68.00 } ] ``` #### D. `Purchase` Fires upon completed transaction on the order confirmation page or via backend order creation. * **`content_ids`**: `['arc-clip-lamp']` (Must match the catalog item ID format used in `ViewContent`). * **`content_type`**: `'product'` * **`value`**: Total monetary value of the purchase (e.g., `68.00` if shipping/taxes are excluded, or the complete order total. Maintain consistency across reporting). * **`currency`**: `'USD'` * **`num_items`**: Total items purchased. * **`order_id`**: Shopify Order ID (e.g., `'1001'` or `'gid://shopify/Order/123456789'`). * **`contents`**: ```json [ { "id": "arc-clip-lamp", "quantity": 1, "item_price": 68.00 } ] ``` --- ## 3. Deduplication Mechanics Between Pixel and CAPI When both the browser Pixel and server CAPI emit an event for the same customer interaction (e.g., an order completion), Meta must identify that these two payloads represent a single conversion. ``` Browser Event Server Event ┌───────────────────────┐ ┌───────────────────────┐ │ event_name: Purchase │ │ event_name: Purchase │ │ event_id: "CC-1042" │ │ event_id: "CC-1042" │ └───────────┬───────────┘ └───────────┬───────────┘ │ │ │ (Arrives via JS) │ (Arrives via CAPI) └────────────────────┐ ┌────────────────┘ ▼ ▼ ┌─────────────────┐ │ Meta Dedupl. │ │ 48-Hour Window │ └────────┬────────┘ │ ▼ [ Combined Canonical Event ] - Deduped: Counted as 1 conversion - Enriched: Browser cookies + Hashed PII merged ``` ### The Matching Mechanism Meta deduplicates events using two primary keys: 1. **`event_name`**: The event identifier (e.g., `Purchase`). 2. **`event_id`**: A unique string generated for that specific action. If Meta receives a browser event and a server event with the **same `event_name` and the exact same `event_id`**, Meta treats the pair as a single event. ### Generation and Sharing of `event_id` * For non-transactional events (`ViewContent`, `AddToCart`), `event_id` is typically generated via JavaScript as a UUID v4 or timestamp-random string and pushed into both the client-side call and the server payload. * For `Purchase`, the most deterministic key is the **Shopify Order ID** or **Checkout Token** (e.g., `c1-9a4f2e8b...` or `1001`). ### The Deduplication Window and Merging * **Timeframe:** Meta’s deduplication window operates across a 48-hour threshold. Events sharing the same `event_id` within this window are consolidated. * **Data Enrichment:** The deduplication process is not purely additive or subtractive—it is a merge. If the browser event arrives with `_fbp` and `_fbc`, and the server event arrives with a SHA-256-hashed email and phone number, Meta merges the records. The ad account gets the match quality of the server parameters combined with the attribution linkage of the client-side click parameters, without inflating conversion counts. --- ## 4. Customer Information Preparation (Normalization and Hashing) To maximize Event Match Quality (EMQ) while respecting privacy standards, personal customer data sent to CAPI must be properly formatted, normalized, and hashed using **SHA-256** before dispatch. ### Fields Requiring Normalization & SHA-256 Hashing | Parameter | CAPI Key | Normalization Rules | Pre-Hash Example | SHA-256 Hashed Output | | :--- | :--- | :--- | :--- | :--- | | **Email** | `em` | Trim leading/trailing whitespace, convert all characters to lowercase. | `alex.taylor@example.com` | `e2a4...` | | **Phone** | `ph` | Strip all spaces, dashes, parentheses, plus signs, and leading zeros. Include country code (E.164 without `+`). | `14155550123` | `9b1c...` | | **First Name** | `fn` | Trim whitespace, lowercase, remove punctuation. | `alex` | `6c10...` | | **Last Name** | `ln` | Trim whitespace, lowercase, remove punctuation. | `taylor` | `e990...` | | **City** | `ct` | Trim whitespace, lowercase, remove spaces/punctuation. | `portland` | `ba36...` | | **State/Region** | `st` | Two-letter state/province code, lowercase. | `or` | `dc7a...` | | **Postal Code** | `zp` | Lowercase, remove spaces and dashes (e.g., US 5-digit zip). | `97201` | `41f7...` | | **Country** | `country` | Two-letter lowercase ISO 3166-1 alpha-2 country code. | `us` | `f94c...` | | **External ID** | `external_id` | Unique merchant customer ID (e.g., Shopify Customer ID). Strip whitespace. | `shopify_cust_88291` | `5a2d...` (or unhashed if strictly an internal ID) | ### Fields Sent in Plain Text (DO NOT HASH) The following technical parameters must be passed in plain text. Hashing them will break Meta's ability to interpret network and cookie information: * **`client_ip_address`**: The user’s IPv4 or IPv6 address (e.g., `"198.51.100.42"`). Must be extracted from proxy headers (`X-Forwarded-For`) if behind a CDN or proxy. * **`client_user_agent`**: The exact browser User-Agent string from the HTTP request headers. * **`fbc`**: The Meta Click ID cookie value (e.g., `"fb.1.1693836000.IwAR2..."`). Present if the user reached the site via a Meta ad click containing a `fbclid`. * **`fbp`**: The Meta Browser ID cookie value (e.g., `"fb.1.1693836000.1234567890"`). --- ## 5. Concrete Shopify Setup Path & Implementation ### Comparison: Native Meta Sales Channel App vs. Custom Architecture ``` ┌────────────────────────────────────────────────────────────────────────┐ │ Option A: Native Meta Sales Channel App │ │ │ │ Storefront / Checkout ────────► Meta App (Shopify) ────────► Meta API │ │ - Zero custom infra - Full Checkout Extensibility │ │ - Native deduplication - Fast deployment │ └────────────────────────────────────────────────────────────────────────┘ ┌────────────────────────────────────────────────────────────────────────┐ │ Option B: Custom Implementation (Web Pixels API + Server Worker) │ │ │ │ Storefront ──► Web Pixel ──► Cloudflare / sGTM ──► Meta CAPI │ │ - Custom schema routing - Requires infrastructure maintenance │ │ - Full proxy / edge control - Higher development overhead │ └────────────────────────────────────────────────────────────────────────┘ ``` | Criteria | Native Meta App ("Maximum" Data Sharing) | Custom (Web Pixels API + Serverless/sGTM) | | :--- | :--- | :--- | | **Development Effort** | Low (configuration via Shopify Admin; ~1–2 hours). | High (requires custom app/worker, server infrastructure, endpoint maintenance). | | **Checkout Compatibility**| Full native integration with Shopify Checkout Extensibility. | Requires building a custom Shopify Web Pixel extension to run in the checkout sandbox. | | **Deduplication Handling**| Automated: Shopify injects matching `event_id` values across browser pixel and backend CAPI calls. | Manual: Developer must orchestrate client/server ID handshakes and webhook payloads. | | **Maintenance Burden** | Handled automatically by Shopify and Meta engineering updates. | Borne entirely by the brand (API version deprecations, payload schema changes). | | **Custom Control** | Limited to standard Shopify catalog and event schemas. | Total control over proxy routing, advanced payload manipulation, and custom properties. | ### Recommendation for Cedar & Coil **Implement the native Meta sales channel app on the "Maximum" data-sharing tier.** *Rationale:* As a small DTC store launching its single product (the Arc Clip Lamp at $68) with no prior campaign history, engineering capacity should remain focused on product experience, creative assets, and initial market validation. The native Meta app automatically deploys both the browser Pixel and server CAPI, handles checkout sandbox constraints, passes validated order data via Shopify backend hooks, and configures event deduplication without custom infrastructure overhead. A custom implementation (such as Server-Side Google Tag Manager on AWS/GCP or a custom Cloudflare Worker) should only be evaluated if Cedar & Coil later introduces complex multi-channel routing, proprietary data warehouse warehousing before ad delivery, or custom vendor-agnostic consent proxies. --- ### Code Sketch: Server-Side `Purchase` Event Request (Node.js) If Cedar & Coil ever utilizes a direct server endpoint, custom app proxy, or webhook listener for order tracking, the payload dispatched to Meta's Graph API must adhere to this structure: ```javascript import crypto from 'crypto'; // Helper: Normalize and SHA-256 hash personal identifiers function hashParameter(value) { if (!value) return undefined; return crypto .createHash('sha256') .update(value.trim().toLowerCase()) .digest('hex'); } // Handler for a completed purchase event async function sendMetaPurchaseEvent({ order, clientContext }) { const PIXEL_ID = process.env.META_PIXEL_ID; const ACCESS_TOKEN = process.env.META_CONVERSIONS_API_TOKEN; const API_VERSION = 'v19.0'; // 1. Prepare hashed customer parameters const userData = { em: [hashParameter(order.customer.email)], ph: [hashParameter(order.customer.phone)], // e.g., '14155550123' fn: [hashParameter(order.customer.firstName)], ln: [hashParameter(order.customer.lastName)], ct: [hashParameter(order.shippingAddress.city)], st: [hashParameter(order.shippingAddress.provinceCode)], zp: [hashParameter(order.shippingAddress.zip)], country: [hashParameter(order.shippingAddress.countryCode)], external_id: [hashParameter(String(order.customer.id))], // 2. Unhashed client parameters client_ip_address: clientContext.ipAddress, client_user_agent: clientContext.userAgent, fbc: clientContext.fbcCookie || undefined, fbp: clientContext.fbpCookie || undefined, }; // 3. Assemble CAPI payload const payload = { data: [ { event_name: 'Purchase', event_time: Math.floor(new Date(order.createdAt).getTime() / 1000), // Crucial: Must match the event_id fired by the browser pixel on the thank-you page event_id: `shopify_order_${order.id}`, event_source_url: `https://cedarandcoil.com/checkouts/${order.checkoutToken}/thank_you`, action_source: 'website', user_data: userData, custom_data: { currency: 'USD', value: parseFloat(order.totalPrice), // e.g., 68.00 content_type: 'product', content_ids: ['arc-clip-lamp'], contents: [ { id: 'arc-clip-lamp', quantity: order.lineItems[0]?.quantity || 1, item_price: 68.00, }, ], num_items: order.lineItems.reduce((acc, item) => acc + item.quantity, 0), order_id: String(order.name || order.id), // e.g., "1001" }, }, ], // Optional: test_event_code for sandbox validation // test_event_code: 'TEST12345' }; // 4. Dispatch to Meta Conversions API const response = await fetch( `https://graph.facebook.com/${API_VERSION}/${PIXEL_ID}/events?access_token=${ACCESS_TOKEN}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), } ); const result = await response.json(); if (!response.ok) { console.error('Meta CAPI Error:', JSON.stringify(result)); throw new Error(`Failed to dispatch CAPI event: ${result.error?.message}`); } return result; } ``` --- ## 6. End-to-End Validation Protocol (Pre-Spend) Before allocating paid ad spend to the Arc Clip Lamp, execute this step-by-step diagnostic sequence to verify tracking fidelity. ``` Step 1: Client Check Step 2: Server Check Step 3: Verification ┌─────────────────────────────────┐ ┌─────────────────────────────────┐ ┌────────────────────────────────┐ │ Meta Pixel Helper & Console │ │ Events Manager "Test Events" │ │ Events Manager Overview │ │ - Check ViewContent, AddToCart │ │ - Pass test_event_code │ │ - Verify "Deduplicated" badge │ │ - Verify currency: "USD" │──►│ - Trigger test purchase │──►│ - Check Event Match Quality │ │ - Verify value: 68.00 │ │ - Verify both Browser and │ │ - Reconcile order counts │ │ - Confirm event_id populates │ │ Server arrive │ │ against Shopify Admin │ └─────────────────────────────────┘ └─────────────────────────────────┘ └────────────────────────────────┘ ``` ### Step 1: Client-Side Inspection (Browser) 1. Install the **Meta Pixel Helper** extension in a Chromium-based browser. 2. Navigate to the Arc Clip Lamp product page (`/products/arc-clip-lamp`). 3. Verify that `ViewContent` fires with: * `content_name: Arc Clip Lamp` * `value: 68` * `currency: USD` 4. Click the CTA (**"Explore the Arc Clip Lamp"** / Add to Cart). 5. Verify that `AddToCart` fires with identical item IDs and currency. ### Step 2: Live Deduplication Validation in Meta Events Manager 1. In Meta Events Manager, open **Test Events**. 2. Select your Pixel/Dataset and copy the **Test Event Code** (e.g., `TEST12345`). * *If using custom CAPI:* Include `test_event_code` in the payload. * *If using the native Shopify app:* Enter the store URL under the "Test Browser Events" tab to link your session. 3. Process a test transaction using Shopify’s Bogus Gateway or a $0.00 draft order: * Advance from Product Detail (`ViewContent`) $\rightarrow$ Cart (`AddToCart`) $\rightarrow$ Checkout (`InitiateCheckout`) $\rightarrow$ Confirmation (`Purchase`). 4. Monitor the **Test Events** feed in real time: * Confirm that **two** entries appear for `Purchase`: one sourced from `Browser` and one from `Server`. * Confirm that Events Manager automatically bundles these two entries together with a **"Deduplicated"** badge. * Verify that both events share the identical `event_id` (e.g., the order number/token). ### Step 3: Event Quality & Match Reconciliation 1. Navigate to **Events Manager > Overview > Data Sources**. 2. Inspect the **Event Match Quality (EMQ)** score for `Purchase`: * Ensure user match parameters (`em`, `ph`, `client_ip_address`, `client_user_agent`, `fbp`) are successfully received. Aim for a "Good" or "Great" rating. 3. Ensure there are zero **Diagnostics** alerts warning of: * Missing required parameters (`currency`, `value`). * Unhashed personally identifiable information (PII) passed in plain text. * Missing or mismatched `event_id` keys. 4. **Reconciliation Audit:** Allow the store to process initial test transactions over a 24-hour observation window. Run a direct cross-check between the total orders recorded in Shopify Admin versus the deduplicated purchase conversions registered in Meta Events Manager. --- ## 7. Consent and Compliance Note Conversion tracking must be deployed strictly in alignment with regional privacy frameworks (including GDPR, the EU ePrivacy Directive, and US state regulations like CCPA/CPRA). ### Explicit Consent and Signal Gating * **Shopify Customer Privacy API:** If Cedar & Coil utilizes Shopify’s native Customer Privacy settings or a compatible Consent Management Platform (CMP), tracking signals must remain blocked or restricted until the user grants affirmative consent. * **No Server-Side Circumvention:** The Conversions API **must never be used to bypass a user's opt-out or lack of consent**. If a user in a consent-governed jurisdiction rejects marketing cookies: 1. Client-side pixel tags must not fire. 2. The server-side payload must either be suppressed entirely or dispatched with personal identifiers stripped and Meta’s `data_processing_options` activated. ### Limited Data Use (LDU) for US Privacy Laws When processing events from users located in states with active privacy regulations (e.g., California): * Configure the Meta payload to include the `data_processing_options` array: ```json { "data_processing_options": ["LDU"], "data_processing_options_country": 1, "data_processing_options_state": 1000 } ``` * Setting `[1, 1000]` directs Meta to apply California Limited Data Use restrictions, operating Meta as a service provider rather than a third-party data recipient. If using the native Shopify Meta app, enable this within the app’s compliance and privacy settings. ### PII Sanitization * Never transmit unhashed personal data in custom event parameters, page URLs, or referrers. * Ensure URL query parameters containing customer parameters (such as email confirmation links or UTM tracking containing internal IDs) are sanitized before page-level pixel execution.
Score the judge's verdict, criterion by criterion11/11 criteria passed
RequirementVerdictEvidence
architecture
The guide recommends browser Pixel plus server-side Conversions API with deduplication and explains why both are needed under browser privacy limits.
✓Section 1 explicitly recommends the hybrid Pixel + CAPI model with deduplication and explains browser vulnerabilities (ITP, ad blockers) vs server strengths, arguing neither is sufficient alone.
events_mapped
All four standard events (ViewContent, AddToCart, InitiateCheckout, Purchase) are covered with key parameters, including value, currency, and content_ids on Purchase.
✓Section 2 covers ViewContent, AddToCart, InitiateCheckout, and Purchase each with value, currency, content_ids, content_type, and Purchase additionally includes order_id and contents.
code_sketch
A concrete server-side Purchase event code sketch or request example is included showing event_name, event_time, event_id, action_source, and a user_data block.
✓The Node.js sketch includes event_name: 'Purchase', event_time, event_id, action_source: 'website', and a full user_data block with hashed fields.
validation
End-to-end validation is described using Meta's Events Manager test events tool and an explicit check that duplicate browser/server events are being deduplicated.
✓Section 6 describes using Meta Events Manager's Test Events tool with a test_event_code and explicitly instructs confirming a 'Deduplicated' badge appears for the matched browser/server Purchase pair.
sources_defined
For each event it is clear where it fires (browser vs server) and what the source of truth is (e.g. Purchase from the Shopify order webhook/server, not only the thank-you page).
✓The architecture diagram separates 'Client-side JavaScript' from 'Server / Webhook (Shopify Backend)' capturing 'Validated orders', and Purchase's detail notes it fires 'on the order confirmation page or via backend order creation', clarifying browser vs server source of truth.
limits_stated
Limitations are stated honestly: no promised attribution-recovery percentages, and consent/regional rules are noted as constraints on what may be sent.
✓No specific attribution-recovery percentage is promised anywhere, and Section 7 states CAPI 'must never be used to bypass a user's opt-out or lack of consent' under GDPR/CCPA.
dedup_correct
Deduplication is technically correct: the same event_id and event_name sent on both the Pixel and CAPI event so Meta drops the duplicate; not a vague mention.
✓Section 3 states Meta matches events using the same event_name and 'the exact same event_id' sent from both Pixel and CAPI, not a vague mention.
event_id_retry_stability
The event_id is generated or derived once per commerce event, shared by browser and server, and reused unchanged on webhook retries or order updates; a new random suffix per send or retry fails.
✓The code derives event_id deterministically as `shopify_order_${order.id}` rather than a random string per send, which remains stable across retries since it is tied to the order ID, and the doc notes the Purchase key should be the deterministic 'Shopify Order ID or Checkout Token'.
event_time_stable
The server Purchase event uses the purchase/order occurrence timestamp in Unix seconds and preserves it across retries; using the current send or retry time fails.
✓The code sets `event_time: Math.floor(new Date(order.createdAt).getTime() / 1000)`, using the order's creation timestamp in Unix seconds rather than the current send time.
pii_hashing
Customer data handling is correct: personally identifiable fields (e.g. email) are normalized (trimmed, lowercased) and SHA-256 hashed before sending in user_data.
✓Section 4's table and the hashParameter() function both specify trimming, lowercasing, and SHA-256 hashing of email, phone, name, and address fields before sending in user_data.
actionable_path
The recommended Shopify path is decisive and executable for a small DTC store (a clear recommendation with concrete setup steps, not an undifferentiated list of options).
✓Section 5 gives a decisive recommendation ('Implement the native Meta sales channel app on the \"Maximum\" data-sharing tier') with concrete rationale tailored to a small DTC store, rather than an undifferentiated list.