Pinterest Conversions API
Datafly Signal delivers events to Pinterest server-to-server using the Conversions API (CAPI). This provides reliable conversion tracking for Pinterest ad campaigns without relying on the Pinterest Tag client-side script, improving measurement accuracy and ad performance optimisation.
Why route Pinterest through Datafly Signal
- Conversions survive ad blockers and tracking prevention. A browser tag served from an advertising domain is blocked outright for part of your traffic, and Safari’s ITP shortens the cookies it can set. Signal sends the event from your own server, so the conversions Pinterest optimises against are not filtered by the browser.
- Email and phone number are hashed before leaving your infrastructure. Signal normalises (trim and lowercase) and applies SHA-256 inside your own deployment, so Pinterest receives match keys rather than raw personal data.
- Client IP and user agent are carried in the payload. Both are taken from the original visitor request rather than your server, which is what Pinterest needs to attribute the event to the right session.
- Click identifiers are captured and replayed. Signal stores
click_idfirst-party at collection time and attaches them to the conversion later, so attribution survives even when the original landing cookie has expired. - Delivery is batched, rate-limited, and retried. Signal buffers to Kafka, respects the Pinterest rate limit, and retries on 429 or transient failure rather than dropping the event.
- Presets for Retail and Automotive. The mapping starts from a working configuration for your vertical instead of a blank field map.
- One consent decision governs every destination. Pinterest is gated by the same consent state as the rest of your stack, so a withdrawal applies everywhere at once.
- No vendor tag on the page. Removing it removes its page weight and its independent access to your visitors.
Prerequisites
Before configuring Pinterest CAPI in Signal, you need a Pinterest Business account, an Ads Manager account with a Pinterest Tag, and API credentials. Follow the steps below to set everything up.
Step 1: Create a Pinterest Business Account
- Go to pinterest.com/business/create and click Create Account.
- Enter your email, password, business name, and website URL.
- Complete the business profile by selecting your business type and industry.
- If you already have a personal Pinterest account, convert it to a business account at Settings > Account management > Convert to business account.
Step 2: Set Up Pinterest Ads Manager
- Navigate to ads.pinterest.com and sign in with your business account.
- If prompted, complete the billing setup by adding a payment method under Billing > Payment method.
- Note your Ad Account ID — a numeric ID (e.g.
549764982399) visible in the URL bar or under Ads > Overview > Account Settings.
Your Ad Account ID is different from your profile ID. It is a numeric string found in the Ads Manager URL: https://ads.pinterest.com/advertiser/549764982399/...
Step 3: Create a Pinterest Tag
The Pinterest Tag is required even when using the Conversions API — it defines the container for your conversion events.
- In Ads Manager, go to Conversions (left sidebar) > Set up the Pinterest tag.
- Choose Conversions API as your setup method.
- Note the Tag ID displayed on the setup page.
- Under Conversion Access Token, click Generate New Token.
- Copy the Conversion Access Token immediately — you will need this for Signal configuration.
Store the Conversion Access Token securely. You can regenerate it at any time, but doing so will invalidate the previous token and require updating your Signal configuration.
Step 4: Generate an API Access Token
The API access token authenticates server-to-server requests to the Pinterest Conversions API.
- Go to developers.pinterest.com and sign in with your Pinterest business account.
- Click My apps > Create app (or select an existing app).
- Enter an app name (e.g. “Datafly Signal”) and a description.
- Once the app is created, go to the OAuth section.
- Generate a token with the
ads:writescope. This scope is required for sending conversion events. - Copy the access token — it typically starts with
pina_.
Pinterest API tokens can expire depending on how they are generated. For production use, set up token refresh via the OAuth flow or generate a long-lived token through the Pinterest developer portal. Check the token expiry in your app settings.
Configure in Signal
Now that you have your Ad Account ID, API access token, and Conversion Access Token, configure the integration in Signal.
Configuration Fields
| Field | Required | Description |
|---|---|---|
ad_account_id | Yes | Your Pinterest Ad Account ID (numeric). Found in Pinterest Ads Manager under Account Settings. |
access_token | Yes | Pinterest API access token with ads:write scope. Generated via the Pinterest developer portal. Typically starts with pina_. |
conversion_token | Yes | Conversion access token for the Pinterest Tag. Found in Ads Manager under Conversions > Conversion Access Token. Typically starts with ct_. |
Management UI Setup
- Go to Integrations > Add Integration > Pinterest Conversions API.
- Choose a preset: Retail, Automotive, Default or Insurance (see Presets and event mapping).
- Enter your
ad_account_id,access_token, andconversion_token. - Select consent categories (typically
advertising). - Click Save.
Management API Setup
curl -X POST http://localhost:8084/v1/admin/integrations \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"source_id": "src_abc123",
"vendor": "pinterest",
"name": "Pinterest Conversions API",
"enabled": true,
"config": {
"ad_account_id": "549764982399",
"access_token": "pina_ABC123...",
"conversion_token": "ct_ABC123..."
},
"consent_categories": ["advertising"]
}'API Endpoint
POST https://api.pinterest.com/v5/ad_accounts/{ad_account_id}/eventsEvents are sent as a JSON array in the data field, with authentication via the Authorization: Bearer header.
Presets
| Preset | Use case |
|---|---|
Retail (ecommerce) | Shopping campaigns: product views, search, add to cart and wishlist, checkout start, payment and purchase, with content IDs and contents from your items. |
| Automotive | Vehicle search, views, saves, configuration, finance quotes, test drives, dealer contact, reservations, purchases and service bookings. |
| Default | The cross-vertical key events: page, product view, search, add to cart, lead, sign-up and purchase. |
| Insurance | Quote and lead events as lead, policy views, checkout, payment and policy purchase as checkout. |
Every preset sends server to server with API v5, the visitor’s IP address and user agent, and personal data only as SHA-256 hashes.
Identity signals
Pinterest matches a server event to a Pinterest user with the signals below. The more a visitor carries, the better the match rate.
Sent automatically
| Signal | Pinterest field | Source |
|---|---|---|
| Pinterest click ID | user_data.click_id | The epik parameter Signal captures from a Pinterest ad click (vendor_ids.epik). The most important signal for click attribution. |
| IP address | user_data.client_ip_address | The visitor’s request, not your server. |
| User agent | user_data.client_user_agent | The visitor’s request. |
Hashed personal data
Pinterest only matches on these values, so Signal sends each one as an array of SHA-256 hashes (the shape Pinterest’s API defines), never in plain text:
| Pinterest field | What is hashed |
|---|---|
em | Email, trimmed and lower-cased (the identify trait, else the event’s email property) |
ph | Phone, digits only with the country code (shaped to E.164 first, then the + removed) |
fn, ln | First and last name, trimmed and lower-cased |
external_id | Your user ID |
Hashing happens in your own deployment before the event leaves it. See Personal data by integration.
How to send user data
Call datafly.identify() when a user logs in, registers or submits a form:
datafly.identify("user-123", {
email: "jane.doe@example.com",
phone: "+44 7700 900123",
first_name: "Jane",
last_name: "Doe"
});Presets and event mapping
Event names are Pinterest’s own (page_visit, view_category, search, add_to_cart, add_to_wishlist, initiate_checkout, add_payment_info, checkout, lead, signup, contact, schedule, customize_product): an event name outside that list is rejected. checkout is Pinterest’s purchase event, so only a completed purchase is sent as checkout.
Content IDs and contents come from your items[] (canonical), else the legacy products[], else a single flat item_id / product_id (automotive: then the legacy vehicle_id). value is your event’s value (else the legacy revenue): the total including tax and shipping, as the event specs define it. Pinterest recommends the pre-tax, pre-shipping value; to send that, edit the value mapping in the installed blueprint.
Retail preset (ecommerce)
Full retail funnel for the Pinterest Conversions API: page_visit, view_category, search, add_to_wishlist, add_to_cart, initiate_checkout, add_payment_info and checkout (Pinterest’s purchase event) with contents, content IDs, value, currency and order ID.
| Signal event | Pinterest event | Fields the preset sets |
|---|---|---|
page | page_visit | event_id. |
view_item_list | view_category | contents, content_ids, event_id. |
search | search | event_id, search_string. |
view_search_results | search | contents, content_ids, event_id, search_string. |
view_item | page_visit | contents, content_ids, event_id, value, currency. |
add_to_wishlist | add_to_wishlist | contents, content_ids, event_id, value, currency. |
add_to_cart | add_to_cart | contents, content_ids, event_id, value, currency. |
begin_checkout | initiate_checkout | contents, content_ids, event_id, value, currency. |
add_payment_info | add_payment_info | event_id, value, currency. |
purchase | checkout | contents, content_ids, event_id, value, currency, order_id, num_items. |
sign_up | signup | event_id. |
generate_lead | lead | event_id, value, currency. |
Automotive preset (automotive)
Vehicle funnel: searches, vehicle page visits and saves, configurator (customize_product), finance and dealer leads, test-drive and service bookings (schedule), reservations and purchases.
| Signal event | Pinterest event | Fields the preset sets |
|---|---|---|
page | page_visit | event_id. |
vehicle_searched | search | event_id, search_string. |
vehicle_viewed | page_visit | contents, content_ids, event_id, value, currency. |
vehicle_saved | add_to_wishlist | contents, content_ids, event_id, value, currency. |
configure_vehicle | customize_product | contents, content_ids, event_id. |
finance_quote_requested | lead | contents, content_ids, event_id, value, currency. |
test_drive_booked | schedule | contents, content_ids, event_id, value, currency. |
dealer_contacted | contact | contents, content_ids, event_id. |
generate_lead | lead | contents, content_ids, event_id, value, currency. |
vehicle_reserved | initiate_checkout | contents, content_ids, event_id, value, currency. |
purchase | checkout | contents, content_ids, event_id, value, currency, order_id, num_items. |
service_appointment_booked | schedule | contents, content_ids, event_id, value, currency. |
Default preset (default)
Pinterest Conversions API core funnel: page visits, search, add to cart, leads, sign-ups and checkouts, with hashed email, phone and name, the _epik click ID, IP and user agent, and an event ID for tag deduplication.
| Signal event | Pinterest event | Fields the preset sets |
|---|---|---|
page | page_visit | event_id. |
view_item | page_visit | contents, content_ids, event_id, value, currency. |
search | search | event_id, search_string. |
add_to_cart | add_to_cart | contents, content_ids, event_id, value, currency. |
generate_lead | lead | event_id, value, currency. |
sign_up | signup | event_id. |
purchase | checkout | contents, content_ids, event_id, value, currency, order_id, num_items. |
Insurance preset (insurance)
Insurance quote and policy funnel: quote requests and leads as lead, contact requests, checkout, payment info and policy purchases as checkout with the policy number as event ID and order ID.
| Signal event | Pinterest event | Fields the preset sets |
|---|---|---|
page | page_visit | event_id. |
view_item | page_visit | contents, content_ids, event_id, value, currency. |
get_quote | lead | event_id, value, currency. |
quote_requested | lead | event_id, value, currency. |
generate_lead | lead | event_id, value, currency. |
lead_submitted | lead | event_id, value, currency. |
contact_requested | contact | event_id. |
begin_checkout | initiate_checkout | contents, content_ids, event_id, value, currency. |
add_payment_info | add_payment_info | event_id, value, currency. |
purchase | checkout | contents, content_ids, event_id, value, currency, order_id, num_items. |
policy_purchased | checkout | contents, content_ids, event_id, value, currency, order_id, num_items. |
sign_up | signup | event_id. |
Example: purchase
A Retail purchase with two items from a known visitor, as Signal sends it to POST https://api.pinterest.com/v5/ad_accounts/<ad_account_id>/events:
{
"data": [
{
"action_source": "web",
"custom_data": {
"content_ids": [
"STK-7421"
],
"contents": [
{
"id": "STK-7421",
"item_brand": "BMW",
"item_category": "SUV",
"item_name": "BMW X3 xDrive30e",
"item_price": 49995,
"quantity": 1
}
],
"currency": "GBP",
"num_items": 1,
"order_id": "ORD-10042",
"value": 49995
},
"event_id": "ORD-10042",
"event_name": "checkout",
"event_source_url": "https://shop.example.co.uk/checkout?gclid=g-123",
"event_time": 1790155800,
"user_data": {
"click_id": "ep-123",
"client_ip_address": "203.0.113.7",
"client_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 Version/18.0 Safari/605.1.15",
"em": [
"86e0b9e56c17cc4d12387e1949b85053fbe73bc3ce5a1188713a9d300cc6133d"
],
"external_id": [
"40ba61f5c6b64e4f3f389c4b7a244f2b176115cbf452d1d81cf9bf70ebdf739d"
],
"fn": [
"81f8f6dde88365f3928796ec7aa53f72820b06db8664f5fe76a7eb13e24546a2"
],
"ln": [
"799ef92a11af918e3fb741df42934f3b568ed2d93ac1df74f1b8d41a27932a6f"
],
"ph": [
"033134b911b137918338415ee3d20a064b24773d36a3b02e8b99fdd3fcd6b4cd"
]
}
}
],
"partner_name": "datafly"
}Example: product view
{
"data": [
{
"action_source": "web",
"custom_data": {
"content_ids": [
"PKT-001"
],
"contents": [
{
"id": "PKT-001",
"item_brand": "NorthEdge",
"item_category": "Women > Jackets",
"item_name": "Parka Jacket",
"item_price": 129.99,
"quantity": 1
}
],
"currency": "GBP",
"value": 129.99
},
"event_id": "evt-spec-0001",
"event_name": "page_visit",
"event_source_url": "https://shop.example.co.uk/checkout?gclid=g-123",
"event_time": 1790155800,
"user_data": {
"click_id": "ep-123",
"client_ip_address": "203.0.113.7",
"client_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 Version/18.0 Safari/605.1.15",
"em": [
"86e0b9e56c17cc4d12387e1949b85053fbe73bc3ce5a1188713a9d300cc6133d"
],
"external_id": [
"40ba61f5c6b64e4f3f389c4b7a244f2b176115cbf452d1d81cf9bf70ebdf739d"
],
"fn": [
"81f8f6dde88365f3928796ec7aa53f72820b06db8664f5fe76a7eb13e24546a2"
],
"ln": [
"799ef92a11af918e3fb741df42934f3b568ed2d93ac1df74f1b8d41a27932a6f"
],
"ph": [
"033134b911b137918338415ee3d20a064b24773d36a3b02e8b99fdd3fcd6b4cd"
]
}
}
],
"partner_name": "datafly"
}Action source
action_source is web for events from Datafly.js, app_ios for the iOS SDK and app_android for the Android SDK.
Testing Your Integration
Step 1: Send Test Events
- Add the Pinterest integration in Signal with your credentials.
- Trigger events on your website (page views, add-to-cart, purchase).
- Check the Signal event debugger to confirm events are being delivered successfully.
Step 2: Verify in Pinterest Ads Manager
- In Pinterest Ads Manager, go to Conversions > Events tab.
- You should see server events arriving with an “API” source indicator.
- Events typically appear within 1-2 minutes of being sent.
- Click on individual events to inspect the payload and parameter details.
Step 3: Check Event Match Rate
- In the Conversions dashboard, review the Event Match Rate metric.
- A higher match rate means Pinterest can attribute more events to user profiles.
- If the rate is low, ensure
epikclick IDs andpin_unauthcookies are being captured, and add user identity signals viadatafly.identify().
Pinterest’s Event Match Rate is the equivalent of Meta’s EMQ score. Sending both epik (click ID) and pin_unauth (browser ID) alongside hashed email significantly improves match rates.
Deduplication
Each event carries an event_id: the event’s deduplication ID (event_id passed to datafly.track(), else Signal’s message ID), and on checkout the order ID (transaction_id, else order_id). If you still run the Pinterest Tag in the browser during a migration, give the tag the same ID so Pinterest counts the conversion once:
const eventId = crypto.randomUUID();
pintrk('track', 'add_to_cart', { event_id: eventId, value: 129.99, currency: 'GBP' });
datafly.track('add_to_cart', { event_id: eventId, value: 129.99, currency: 'GBP', items: [...] });For a purchase, pass the order ID as the tag’s event_id. Once the server events are verified you can remove the tag.
Partner name
The delivery sends partner_name: "datafly" at the top of every request. Pinterest reads partner_name on each event and only for registered partners (ss-<name>); the top-level field has no effect on attribution (#1582).
Troubleshooting
| Problem | Solution |
|---|---|
| Events not appearing in Ads Manager | Verify all three credentials are correct: ad_account_id, access_token, and conversion_token. Check that the access token has ads:write scope. |
401 Unauthorized errors | The access token has expired or been revoked. Generate a new token in the Pinterest developer portal. |
403 Forbidden errors | The access token does not have ads:write scope, or the token’s app does not have access to the specified ad account. |
Invalid ad_account_id error | The ad account ID is incorrect or does not belong to the authenticated user. Verify the ID in Ads Manager. |
| Low Event Match Rate | Add user identity signals via datafly.identify(). Ensure epik click IDs are being captured from Pinterest ad URLs and _pin_unauth cookies are being set. |
| Duplicate events in reporting | If running both client-side and server-side, ensure matching event_id values for deduplication. |
Events showing as custom | The event name may not be mapping to a standard Pinterest event. Check the event mapping table above and ensure your Datafly.js calls use the expected event names. |
conversion_token errors | The conversion token may be invalid or regenerated. Generate a new token in Ads Manager under Conversions > Conversion Access Token. |
Rate Limits
| Limit | Value |
|---|---|
| Events per API call | 1,000 (batched) |
| Default rate limit (Signal) | 100 requests/second |
| Default burst limit (Signal) | 200 requests/second |
Pinterest allows up to 1,000 events per batch request. Signal batches events automatically when throughput is high to maximise efficiency. For most deployments, the default rate limit settings are sufficient.