Pinterest Conversions API for ecommerce agencies: the setup that captures iOS 14.5+ buyers
Pinterest tag-only setups lose iOS purchase signal. The Pinterest Tag + Conversions API setup for ecommerce agencies, with the dedup pattern.
TL;DR
Pinterest's audience is mostly mobile, much of it on iOS — and iOS is exactly the cohort the Pinterest Tag observes worst. A tag-only setup misses a real share of Checkout events; how much depends on the store's traffic, so measure it for each client (below) instead of trusting a rule of thumb. The fix is Pinterest's Conversions API (rolled out globally in October 2022): 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 rises as the API carries the events and customer data the tag can't — 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 hits Pinterest harder than the average platform: its audience is mostly mobile, a large share of it on iOS, and iOS users who decline cross-app tracking can't be tied back to the ad that sent them. That signal is gone 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. How much desktop traffic that costs depends on the audience. - 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 under-counts Checkout / Purchase events on a Shopify or BigCommerce store — and the algorithm's bidding gets progressively worse as the feedback loop is starved. To size the gap for a client, compare a month of the tag's Checkout events with the store's online orders over the same days (leave out POS and subscription-renewal orders — they never load a confirmation page): the tag fires on every order confirmation it can see, so the difference is what it can't.
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',
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: 'Stavewright 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. Pinterest documents thecustom_datafields as strings: send'142.50', not142.50, and check the value in the test tool before you trust the revenue in reports.- 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. Read a low one as missing identifiers, not a verdict: it rises as the API sends more of the customer data below.
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. Send every one you have — each identifier an event carries gives Pinterest another way to match it.
- 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 says its Performance+ sales and leads campaigns perform best with 50+ conversion events a week, and suggests starting accounts below that on the Consideration objective instead (Pinterest). Smaller clients struggle here.
Run a weekly review of the score in Ads Manager. Phloz doesn't read Pinterest data: on a client's tracking map, the tag and the CAPI endpoint are Custom nodes you mark verified (or broken) on that review.
Step 5: Verify with Pinterest's Conversion Test Tool
Pinterest Ads Manager → Conversions → your dataset → Test events. Send a test event from your server. It should appear in the test feed within 30 seconds. (To validate a payload without recording anything, Pinterest also accepts ?test=true on the events endpoint — take it off before going live.)
Two reasons to do this on every deploy:
- Schema drift — Pinterest adds required fields from time to time (
action_sourceis required on every event today), and an integration written before one landed stops being accepted. The test tool surfaces schema rejections in plain English; in production, read the per-event statuses in the response rather than trusting the HTTP 200. - Access token rotation — a Pinterest access token lasts 30 days and its refresh token 60, renewed with each refresh (Pinterest); 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 to look for when you take over a Pinterest account:
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 its floor and 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. Once CAPI lands, the algorithm has more reliable feedback to optimize against — so test raising the budget and watch CPA to find the new ceiling. That's not a tracking metric — that's a margin-line metric.
If you're a Phloz user, Pinterest isn't a built-in node type, so the tag and the CAPI endpoint go on the client's map as Custom nodes — each gets a health state and a last-verified date, and the weekly audit flags either once nobody has verified it in 30 days. A client with a tag node and no CAPI node beside it is a gap you can see at a glance; the quality score stays a weekly check in Ads Manager.