Pinterest Conversions API for ecommerce agencies: the setup that captures iOS 14.5+ buyers
Pinterest tag-only setups in 2026 lose 35-55% of iOS purchase signal — and Pinterest's audience over-indexes on iOS. Here's the Pinterest Tag + Conversions API setup we ship to ecommerce agency clients, including the dedup pattern, the recommended event source, and the dataset-quality score that decides whether the algorithm trusts your data.
TL;DR
Pinterest's audience skews iOS-heavy (~65% mobile, of which ~55% iOS) — and iOS is exactly the cohort the Pinterest Tag observes worst. Tag-only setups in 2026 miss 35-55% of Checkout events for typical ecommerce clients. The fix is Pinterest's Conversions API (rolled out 2023, hardened in 2024-2025): dual-stack Tag + API, deduplicated by event_id, fired from your ecommerce platform's webhook (Shopify / WooCommerce / BigCommerce native integrations exist but ship them carefully). The dataset-quality score in Pinterest Ads Manager goes from typical 4-6 (pixel-only) to 8-9 (dual-stack done right) — and that score is what gates Pinterest's optimization confidence. Below: the exact setup, the platform-specific gotchas, and the four pre-shipped Shopify/Woo paths to skip.
Pinterest is the ad platform most ecommerce agencies treat as a side channel — until a client's spend starts climbing because the discovery-style placements actually move volume on certain product categories (home, beauty, fashion, food, parenting). Once spend crosses ~$5K/mo on Pinterest, signal-quality matters as much as it does on Meta. And until the Conversions API is wired up, signal quality is structurally capped.
This is the agency-shaped Pinterest setup. It deliberately mirrors the architecture of Meta Pixel + CAPI, TikTok Pixel + Events API, and LinkedIn Insight Tag + Conversions API — once you've shipped one, the others go faster. Pinterest-specific notes are flagged inline.
Why pixel-only fails on Pinterest specifically
Three forces:
- iOS 14.5+ ATT opt-out rates that hit Pinterest harder than the average platform — Pinterest's audience is ~65% mobile, ~55% of mobile is iOS, and ~70% of those opt out of cross-app tracking. Stack the percentages: you're missing identifiable signal on roughly 25% of all sessions before any other erosion.
- Browser tracking protection on desktop. Pinterest's pixel hits
s.pinimg.com/ct/core.jsandct.pinterest.com/v3/; both are blocked or degraded by Brave, Firefox ETP, Safari ITP. ~15-20% of desktop traffic on a typical ecom site. - Mobile-app-to-web attribution is the quiet killer on Pinterest. Pinterest users tap a Pin in the iOS app → the in-app browser opens the merchant site → conversion fires in a webview that doesn't share cookies with the user's main browser. Pinterest's pixel doesn't see the same
_pin_unauthcookie it set on the user's last visit. The conversion looks like a brand-new user.
Stacked, a Pinterest-pixel-only setup is missing 35-55% of Checkout / Purchase events on a typical Shopify or BigCommerce store. The algorithm's bidding gets progressively worse over time as the feedback loop is starved.
The setup that works
Five steps, mostly familiar from Meta/TikTok with Pinterest-specific gotchas.
Step 1: Install the Pinterest Tag with event_id on every event
Standard GTM setup; the non-default piece is the event_id parameter on every conversion event:
// In a Custom HTML tag fired on Purchase events:
window.pintrk('track', 'checkout', {
value: 142.50,
order_quantity: 2,
currency: 'USD',
line_items: [
{
product_name: 'Linen Throw Pillow',
product_id: 'SKU-1234',
product_price: 71.25,
product_quantity: 2,
},
],
// Critical for dedup against the Conversions API call:
event_id: 'order_2026_08_xyz789',
});
event_id is what Pinterest deduplicates against. Use the order ID from the platform (Shopify order ID, Stripe payment intent ID, your own order UUID) — same string passed to both the Tag and the API call.
Pinterest accepts these standard event names: pagevisit, viewcategory, search, addtocart, checkout, signup, lead, custom. Your CRM-or-ecom-platform's lead/checkout webhook will dictate which ones you fire server-side.
Step 2: Fire the Conversions API server-side
Pinterest accepts events at https://api.pinterest.com/v5/ad_accounts/{ad_account_id}/events. The shape:
// Node.js, fired on Shopify "orders/paid" webhook:
const response = await fetch(
`https://api.pinterest.com/v5/ad_accounts/${PINTEREST_AD_ACCOUNT_ID}/events`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${PINTEREST_ACCESS_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
data: [
{
event_name: 'checkout',
action_source: 'web',
event_time: Math.floor(Date.now() / 1000), // SECONDS, not ms
event_id: 'order_2026_08_xyz789', // MUST match the Tag event_id
event_source_url: 'https://merchant.com/order/confirmation/12345',
partner_name: 'phloz', // optional but recommended
user_data: {
em: [sha256(email.toLowerCase().trim())],
ph: [sha256(normalizePhone(phone))],
ge: [sha256(gender)],
db: [sha256(birthDate)], // YYYYMMDD
ln: [sha256(lastName.toLowerCase())],
fn: [sha256(firstName.toLowerCase())],
ct: [sha256(city.toLowerCase().replace(/[^a-z]/g, ''))],
st: [sha256(state.toLowerCase())],
zp: [sha256(zipCode)],
country: [sha256(country.toLowerCase())],
client_ip_address: clientIp,
client_user_agent: userAgent,
external_id: [sha256(customerId)],
},
custom_data: {
currency: 'USD',
value: '142.50', // STRING, not number
content_ids: ['SKU-1234'],
content_name: 'Linen Throw Pillow',
content_category: 'Home / Bedding',
content_brand: 'Acme Home',
num_items: 2,
order_id: '12345',
},
},
],
}),
}
);
Three Pinterest-specific gotchas worth memorising:
event_timeis in seconds, not milliseconds. Most other platforms (Meta, TikTok, LinkedIn) use milliseconds. Pinterest is the odd one out. Send millis and the API returns 200 but the event is silently rejected because it's "in the year 56,000 AD."valueis a string, not a number.'142.50'works.142.50returns 200 with the value silently set to 0. This is the single most common breakage mode in Pinterest CAPI implementations.- All
user_datafields are arrays of hashes — even when you have only one value.em: [hash]notem: hash. Single-string values are accepted with 200 but produce 0 match-quality.
Step 3: Use Shopify / WooCommerce native integrations if available — but verify
Pinterest ships native Conversions API integrations for Shopify, WooCommerce, BigCommerce, Magento, and a handful of others. The Shopify integration is a checkbox in the Pinterest app inside the Shopify admin; it auto-wires the API events and handles dedup against the on-page Pinterest Tag.
The native integrations are a reasonable starting point but not what we recommend for serious-volume agency clients, because:
- Limited event customization. The Shopify native integration sends a fixed payload. If your client has custom checkout fields, custom product taxonomy, or a non-standard order flow (subscription / pre-order), the native event payload misses signal that improves match quality.
- No visibility into failures. If the integration's access token expires or Pinterest changes the API surface, the Shopify side surfaces nothing useful. The first sign is dataset-quality score dropping in Pinterest Ads Manager — weeks later.
- Hard dependency on Shopify maintaining the integration. Native integrations are updated on Shopify's release cadence, not yours. Pinterest API quirks (the
event_timeseconds issue above, for example) take weeks to fix in native integrations after Pinterest changes them.
For agency clients spending under ~$5K/mo on Pinterest, the native Shopify integration is fine. Above that threshold, ship a custom server-side handler from the platform's webhook (Shopify orders/paid, WooCommerce woocommerce_payment_complete, etc.) so you control the payload and the failure surfaces.
Step 4: Match events in Pinterest Ads Manager + watch the dataset-quality score
Pinterest Ads Manager → Conversions → your dataset → Quality Score. The score is 1-10. Pinterest publicly says "5+ is acceptable"; we've found 8+ is what actually unlocks confident bid optimization.
Score is driven by:
- Match rate — % of events where Pinterest can match the hashed user data to a Pinterest user. Best signals: hashed email + hashed phone + IP + user agent. The full bundle gets you to ~40-50% match rate; dropping any one drops match rate by ~10pp.
- Event coverage — % of conversions that have BOTH Tag and CAPI events received. Pinterest weights events with both signals more heavily for optimization.
- Freshness — % of events fired within an hour of the conversion. Webhook-driven events are usually within seconds; batch-import (e.g. nightly Shopify export) drops this score.
- Volume — Pinterest needs ~50 events/week per dataset for reliable modeling. Smaller clients struggle here; combine
add_to_cart+checkoutinto a single optimization signal if needed.
Run a weekly review of the score. We track this per-client in Phloz's tracking map — the dataset-quality node turns red when the score drops below 7.
Step 5: Verify with Pinterest's Conversion Test Tool
Pinterest Ads Manager → Conversions → your dataset → Test events. Send a test event from your server (a partner_name: 'phloz_test' flag works to mark it as test). It should appear in the test feed within 30 seconds.
Two reasons to do this on every deploy:
- Schema drift — Pinterest occasionally adds required fields (the most recent:
action_sourcebecame required in Q1 2025, and old integrations silently broke). The test tool surfaces schema rejections in plain English. The production API just returns 200 and silently drops. - Access token rotation — Pinterest tokens last 30 days by default; the refresh-token flow extends to 60 days, but if you don't implement refresh, the token expires and events stop. The test tool catches this immediately on the next deploy.
Five common breakage modes
These are the bugs we see at agency-takeover audits on Pinterest specifically:
valuesent as a number, not a string — covered above. Symptom: dataset shows correct event count, but ROAS reporting is 0. Fix is one type cast.event_timein milliseconds — events accepted, never appear in the dataset. Symptom: Tag-only events visible, CAPI events missing despite 200 response.- Single-value
user_datafields not wrapped in arrays — match quality stays at 0-2 forever. Match-quality score never improves. Fix: wrap every user_data field in[ ]. - Hashed values not lowercased / trimmed before hashing — same root cause as the LinkedIn equivalent.
john.doe@gmail.comandJohn.Doe@gmail.comproduce different SHA256 hashes; Pinterest can match the lowercased one to a user, not the mixed-case one. - Native Shopify integration silently disabled — Shopify app re-installations or admin permission changes can disable the Pinterest app's API permissions. The integration UI shows green; events stop flowing. Catch this with a weekly "events received in the last 7d" check, not by trusting the UI status.
Where Pinterest fits in an ecom agency's tracking discipline
For ecommerce agency clients with a Pinterest spend, the order of priority for tracking discipline:
- Meta CAPI — usually the largest spend, the longest-tenured pixel, the most leverage from getting it right.
- Google Ads + GA4 — required for measurement regardless of spend size, every ecom client has it.
- Pinterest CAPI — the specific home/beauty/fashion/food categories where Pinterest is meaningful, usually only after the Meta + Google stack is healthy.
- TikTok CAPI — mostly DTC clients with a content angle.
- LinkedIn CAPI — almost never, for ecom; reserve for B2B clients.
The reason to ship Pinterest CAPI when you do ship it: the pixel-only signal cap is tight enough that it caps how much spend Pinterest can absorb profitably. We've seen clients lift Pinterest spend 2-3x after CAPI lands because the algorithm now has reliable feedback to optimize against. That's not a tracking metric — that's a margin-line metric.
If you're a Phloz user and you've got a Pinterest-spending client without CAPI yet, the typed tracking map will flag it: every Pinterest pixel node with no paired CAPI node shows up red on the agency's overview. Phloz's whole reason for existing is that gap-finding shouldn't require an audit — it should be visible at a glance, every Monday.