← Run 20260904-150307-2b65f658
Shopify to Meta ads conversion tracking implementation
task shopify-meta-capiSep 4, 2026

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.
Answer the model's full response$0.028 · 49.9s · 7.3k tok
# Meta Tracking Implementation Guide: Cedar & Coil **Brand:** Cedar & Coil **Product:** Arc Clip Lamp ($68.00 USD) **Target Audience:** Technical Marketers & Analytics Engineers **Status:** Draft-only pre-launch implementation --- ## 1. Recommended Architecture: Redundant Hybrid Model To build a conversion tracking foundation resilient against client-side restrictions (such as Apple’s Safari Intelligent Tracking Prevention, Firefox Enhanced Tracking Protection, mobile ad blockers, and network interruptions), Cedar & Coil must implement a **dual-channel hybrid architecture**: ``` [Customer Browser / Device] | +---> Browser Meta Pixel (Client-Side JS) --------+ | | | v [Shopify Storefront] [Meta Graph API / | Events Manager] | (Webhook / Server Event) ^ v | [Shopify Backend / Server] ---> Conversions API (CAPI) --+ (with identical event_id) ``` ### Why Both Channels Are Necessary * **Browser-Side (Meta Pixel):** The Meta Pixel runs directly inside the customer’s browser session. It directly accesses first-party client context: active browser session cookies (`_fbp`, `_fbc`), screen resolution, user agent, and real-time click IDs (`fbclid`). However, client-only tracking is fragile; ad blockers, network drops, and browser privacy controls block or degrade third-party JavaScript and truncate client-set cookie lifespans. * **Server-Side (Conversions API):** CAPI bypasses the browser completely. Events are sent server-to-server directly from Shopify's infrastructure to Meta's Graph API. Server requests are immune to ad blockers, DNS filters, and browser runtime errors. * **Deduplication:** Running both streams concurrently provides maximum signal resilience. When a client-side event is blocked, the server event still delivers the conversion. When both fire successfully, Meta uses matching deduplication keys to discard the redundant instance, preventing double-counting in reporting and campaign optimization. --- ## 2. Standard Event Catalog & Parameter Schema For the Arc Clip Lamp, tracking must capture every milestone in the purchase funnel. The table below outlines the four primary standard events, triggering criteria, and required parameters: | Standard Event | Storefront Trigger | Required & Key Parameters | Example Parameter Values | | :--- | :--- | :--- | :--- | | **`ViewContent`** | Arc Clip Lamp product detail page (`/products/arc-clip-lamp`) load. | `content_type`<br>`content_name`<br>`content_ids`<br>`content_category`<br>`value`<br>`currency` | `'content_type': 'product'`<br>`'content_name': 'Arc Clip Lamp'`<br>`'content_ids': ['arc-clip-lamp']`<br>`'content_category': 'Lighting'`<br>`'value': 68.00`<br>`'currency': 'USD'` | | **`AddToCart`** | User clicks the "Add to Cart" button or completes a slide-out cart action. | `content_type`<br>`content_name`<br>`content_ids`<br>`value`<br>`currency` | `'content_type': 'product'`<br>`'content_name': 'Arc Clip Lamp'`<br>`'content_ids': ['arc-clip-lamp']`<br>`'value': 68.00`<br>`'currency': 'USD'` | | **`InitiateCheckout`** | User clicks "Checkout" in the cart drawer and initiates Shopify checkout. | `content_type`<br>`content_ids`<br>`num_items`<br>`value`<br>`currency` | `'content_type': 'product'`<br>`'content_ids': ['arc-clip-lamp']`<br>`'num_items': 1`<br>`'value': 68.00`<br>`'currency': 'USD'` | | **`Purchase`** | Order confirmation (`order_status` page load / server order creation). | `content_type`<br>`content_ids`<br>`contents`<br>`num_items`<br>`value`<br>`currency` | `'content_type': 'product'`<br>`'content_ids': ['arc-clip-lamp']`<br>`'contents': [{'id': 'arc-clip-lamp', 'quantity': 1, 'item_price': 68.00}]`<br>`'num_items': 1`<br>`'value': 68.00`<br>`'currency': 'USD'` | ### Parameter Requirements for `Purchase` * **`value`**: Must reflect the actual monetary value (e.g., `68.00` for a single lamp, or dynamic cart total if multiple units/shipping are included). It must be a numeric float, never formatted with currency symbols or commas. * **`currency`**: Must be the 3-letter ISO-4217 code (e.g., `'USD'`). * **`content_ids`**: Must pass an array containing the exact SKU or Shopify variant ID (e.g., `['arc-clip-lamp']`). **Crucial:** The identifiers passed in `content_ids` must match the product IDs uploaded to the Meta Product Catalog so Dynamic Product Ads can correctly link events to the catalog item. --- ## 3. Deduplication Mechanics: Pixel vs. CAPI When Meta receives an event via both the browser Pixel and server CAPI, it evaluates two primary identifiers to determine if they represent the same user interaction: 1. **`event_name`**: The event type (e.g., `Purchase`). 2. **`event_id`**: A unique string generated for that specific customer action. ``` Browser Payload: { "event_name": "Purchase", "event_id": "shopify_order_1001" } Server Payload: { "event_name": "Purchase", "event_id": "shopify_order_1001" } ``` ### How Meta Processes the Pair * **Deduplication Window:** Meta maintains a 48-hour deduplication window from the first event receipt. * **Matching Logic:** If Meta receives a browser event and a server event within 48 hours containing the **exact same `event_name`** and **exact same `event_id`**, it recognizes them as duplicates. * **Data Consolidation:** Meta discards the redundant event for attribution and delivery reporting, while merging any supplementary parameters (e.g., combining high-confidence server identity signals with client-side click parameters). * **Generation Strategy:** * For funnel events (`ViewContent`, `AddToCart`), generate a unique UUID or timestamp-random string at runtime and pass that identical value to both `fbq('track', ...)` and the CAPI payload. * For `Purchase`, use the Shopify Order ID, Order Number, or Checkout Token (e.g., `shopify_order_5839201948`) as the `event_id` across both channels. --- ## 4. Customer Information Preparation (Normalization & Hashing) Meta’s Conversions API matches events to Meta accounts using the `user_data` object. Customer privacy regulations and Meta API specifications require personally identifiable information (PII) to be normalized and SHA-256 hashed prior to transmission, while certain technical identifiers remain unhashed. ### Normalization and Hashing Rules | Parameter | Key | Normalization Requirements | Hash Required? | | :--- | :--- | :--- | :--- | | **Email** | `em` | Strip leading/trailing whitespace; convert all characters to lowercase. | **Yes** (SHA-256) | | **Phone** | `ph` | Strip all non-numeric characters (spaces, dashes, parentheses, `+`). Include country code (e.g., `+1 (555) 019-2834` becomes `15550192834`). | **Yes** (SHA-256) | | **First Name** | `fn` | Strip whitespace; lowercase; strip punctuation. | **Yes** (SHA-256) | | **Last Name** | `ln` | Strip whitespace; lowercase; strip punctuation. | **Yes** (SHA-256) | | **City** | `ct` | Strip whitespace; lowercase; strip special characters. | **Yes** (SHA-256) | | **State/Province** | `st` | Use 2-letter state code lowercase (e.g., `ca` or `ny`). | **Yes** (SHA-256) | | **Zip/Postal Code** | `zp` | Strip whitespace; lowercase; for US, use first 5 digits. | **Yes** (SHA-256) | | **Country** | `country` | 2-letter ISO 3166-1 alpha-2 country code in lowercase (e.g., `us`). | **Yes** (SHA-256) | | **Client IP Address** | `client_ip_address` | Raw IPv4 or IPv6 address. | **No** (Do NOT hash) | | **Client User Agent** | `client_user_agent` | Raw browser user agent string. | **No** (Do NOT hash) | | **Click ID Cookie** | `fbc` | Raw `_fbc` cookie value (format: `fb.1.{timestamp}.{fbclid}`). | **No** (Do NOT hash) | | **Browser ID Cookie** | `fbp` | Raw `_fbp` cookie value (format: `fb.1.{timestamp}.{random}`). | **No** (Do NOT hash) | | **External ID** | `external_id` | Unique internal customer ID or Shopify Customer ID. | Optional / Raw | --- ## 5. Concrete Shopify Setup Path & Implementation ### Comparison: Native Meta App vs. Custom Infrastructure | Dimension | Native Meta Sales Channel App | Custom Implementation (e.g., GTM Server-Side + Cloudflare/AWS) | | :--- | :--- | :--- | | **Implementation Complexity** | Low. Managed directly within Shopify admin. | High. Requires server provisioning, container routing, and custom tag coding. | | **Deduplication Handling** | Automated. Shopify automatically synchronizes `event_id` between client pixel and server webhooks. | Manual. Developers must build token exchange and state management between client and server. | | **Shopify Checkout Compatibility** | Native integration with Shopify’s Checkout Extensibility and Web Pixels API. | Requires custom Web Pixels app extension to capture checkout milestones securely. | | **Maintenance & Overhead** | Zero infrastructure overhead; updates handled automatically by Meta and Shopify. | Ongoing maintenance costs for cloud servers (AWS/GCP/Cloudflare), domain routing, and API version upgrades. | | **Payload Customization** | Constrained to Meta’s standard Shopify mapping. | Complete control over every parameter and enrichment step. | ### Recommendation for Cedar & Coil For a single-product DTC store launching the Arc Clip Lamp ($68), the **Native Meta Sales Channel App set to "Maximum" data sharing** is strongly recommended. * **Why:** Setting Data Sharing to "Maximum" immediately activates both the browser Meta Pixel and the Conversions API via Shopify’s backend. It natively handles `event_id` generation, Shopify Checkout Extensibility sandboxing, and customer data normalization without introducing cloud infrastructure costs or maintenance overhead. --- ### Code Sketch: Server-Side `Purchase` Event Request If Cedar & Coil chooses a custom server-side webhook handler (e.g., via a Node.js microservice or Cloudflare Worker listening to Shopify's `orders/paid` webhook), use the following implementation: ```javascript import crypto from 'crypto'; /** * Normalizes and hashes strings using SHA-256 */ function hashData(value) { if (!value) return null; const normalized = String(value).trim().toLowerCase(); return crypto.createHash('sha256').update(normalized).digest('hex'); } /** * Normalizes and hashes phone numbers to E.164 digits-only representation */ function hashPhone(phone) { if (!phone) return null; const digitsOnly = String(phone).replace(/\D/g, ''); return crypto.createHash('sha256').update(digitsOnly).digest('hex'); } /** * Dispatches a Purchase event to Meta Conversions API */ async function sendMetaPurchaseEvent(order, clientContext) { const pixelId = process.env.META_PIXEL_ID; const accessToken = process.env.META_CAPI_ACCESS_TOKEN; const apiVersion = 'v19.0'; const endpoint = `https://graph.facebook.com/${apiVersion}/${pixelId}/events`; const payload = { data: [ { event_name: 'Purchase', event_time: Math.floor(new Date(order.created_at).getTime() / 1000), event_id: `shopify_order_${order.id}`, // Must match the browser event_id event_source_url: `https://cedarandcoil.com/orders/${order.token}`, action_source: 'website', user_data: { em: [hashData(order.email)], ph: [hashPhone(order.phone || order.billing_address?.phone)], fn: [hashData(order.billing_address?.first_name)], ln: [hashData(order.billing_address?.last_name)], ct: [hashData(order.billing_address?.city)], st: [hashData(order.billing_address?.province_code)], zp: [hashData(order.billing_address?.zip)], country: [hashData(order.billing_address?.country_code)], client_ip_address: clientContext.ip, // Unhashed client_user_agent: clientContext.userAgent, // Unhashed fbp: clientContext.fbpCookie || undefined, // Unhashed fbc: clientContext.fbcCookie || undefined // Unhashed }, custom_data: { currency: 'USD', value: 68.00, content_type: 'product', content_ids: ['arc-clip-lamp'], contents: [ { id: 'arc-clip-lamp', quantity: 1, item_price: 68.00 } ], num_items: 1, order_id: String(order.order_number) } } ] }; const response = await fetch(endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${accessToken}` }, body: JSON.stringify(payload) }); if (!response.ok) { const errorBody = await response.text(); throw new Error(`Meta CAPI dispatch failed: ${response.status} - ${errorBody}`); } return await response.json(); } ``` --- ## 6. End-to-End Validation Protocol Before Scaling Spend Before allocating live ad budget to the Arc Clip Lamp campaign, complete this four-step validation: 1. **Test Events Tool Verification:** * Navigate to **Meta Events Manager > Data Sources > [Your Pixel] > Test Events**. * If testing via browser: Enter `https://cedarandcoil.com` and trigger browsing, add-to-cart, and checkout actions while inspecting logs in real time. * If testing custom CAPI: Include `"test_event_code": "TESTXXXXX"` in the CAPI payload. Send a test `Purchase` event and ensure it appears immediately in the Test Events console under the "Server" source channel. 2. **Deduplication Confirmation:** * Trigger an event that fires both client-side and server-side (e.g., complete a test order on the storefront). * In the Test Events console, confirm that the event appears with both **Browser** and **Server** indicators grouped together under the same row, marked as deduplicated rather than appearing as two separate events. 3. **Event Match Quality (EMQ) Audit:** * After receiving initial test events, inspect the **Event Match Quality** score for `Purchase` in Events Manager. * Aim for an EMQ rating within the **Good** to **Great** range. Ensure parameters like `em`, `ph`, `fbp`, `fbc`, `client_ip_address`, and postal codes are populating without validation errors. 4. **Order Reconciliation:** * Place a live test purchase for the Arc Clip Lamp using a test credit card or 100% discount checkout. * Verify that: * The `order_id` in Shopify matches the `event_id` in Events Manager. * The parameter values pass cleanly (`value: 68.00`, `currency: USD`, `content_ids: ['arc-clip-lamp']`). * The Meta Pixel Helper Chrome extension reports green checkmarks on the checkout thank-you page with zero syntax warnings. --- ## 7. Consent and Regulatory Compliance All tracking implementations must adhere to global privacy frameworks (such as GDPR, ePrivacy Directive, and CCPA/CPRA): * **Shopify Customer Privacy Integration:** * For visitors in jurisdictions requiring opt-in consent (e.g., EEA, UK), ensure the Meta Pixel does not fire before affirmative user consent is registered. * Integrate the tracking setup with Shopify’s native Customer Privacy API or a certified Consent Management Platform (CMP). Event listeners should withhold `ViewContent`, `AddToCart`, and other tracking scripts until the user accepts tracking categories. * **Meta Limited Data Use (LDU) for US State Privacy (CCPA/CPRA):** * To comply with California, Colorado, and other US state regulations regarding the sale or sharing of personal data, configure Meta’s Limited Data Use mode. * When sending server events for opted-out users, pass the data processing options explicitly within the CAPI payload: ```json "data_processing_options": ["LDU"], "data_processing_options_country": 1, "data_processing_options_state": 1000 ``` *(Passing `country: 1` and `state: 1000` allows Meta to automatically detect whether the user is located in California or applicable states).* * **Data Minimization:** * Never pass raw, unhashed PII within custom parameters, URL query strings, or event names. * Ensure query string parameters (such as email addresses entered into form inputs) are stripped before page URLs are captured in `event_source_url`.
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.
✓The guide explicitly recommends a 'dual-channel hybrid architecture' with browser Pixel and server CAPI, explaining that CAPI is 'immune to ad blockers, DNS filters, and browser runtime errors' while the Pixel captures first-party client context.
events_mapped
All four standard events (ViewContent, AddToCart, InitiateCheckout, Purchase) are covered with key parameters, including value, currency, and content_ids on Purchase.
✓All four events (ViewContent, AddToCart, InitiateCheckout, Purchase) are listed in a table with parameters including value, currency, and content_ids, with Purchase also including 'contents' and 'num_items'.
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 code sketch includes event_name: 'Purchase', event_time computed from order.created_at, event_id derived from order.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 instructs navigating to 'Meta Events Manager > Data Sources > [Your Pixel] > Test Events' and explicitly checking that 'the event appears with both Browser and Server indicators grouped together under the same row, marked as deduplicated'.
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 Purchase row notes it fires on 'Order confirmation (order_status page load / server order creation)' and the code sketch clarifies the server-side handler listens to Shopify's 'orders/paid' webhook, indicating the webhook/server as the authoritative source.
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 attribution-recovery percentage is promised anywhere, and Section 7 frames consent (GDPR/CCPA, Meta LDU) as a hard constraint on what may be sent, e.g. 'ensure the Meta Pixel does not fire before affirmative user consent is registered.'
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.
✓The guide states Meta matches on 'the exact same event_name and exact same event_id' between browser and server payloads and 'discards the redundant event for attribution and delivery reporting.'
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.
✓For Purchase the event_id is derived deterministically as `shopify_order_${order.id}` tied to the stable Shopify Order ID/Token rather than a random per-send value, matching the guidance to 'use the Shopify Order ID, Order Number, or Checkout Token... across both channels.'
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.
✓event_time is computed as `Math.floor(new Date(order.created_at).getTime() / 1000)`, using the order's actual creation timestamp 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.
✓The hashData function trims and lowercases the value before SHA-256 hashing, and the table specifies email/name/address fields require SHA-256 hashing after normalization.
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).
✓The guide gives a decisive recommendation: 'the Native Meta Sales Channel App set to \"Maximum\" data sharing is strongly recommended' with concrete reasoning for a single-product DTC store.