How to Integrate Pinterest Ads with Your Headless CMS
Connect Pinterest Ads to your headless CMS so campaign teams can publish product Pins, creative copy, landing URLs, and UTM data from one structured source.
What is Pinterest Ads?
Pinterest Ads is Pinterest's paid advertising platform for promoting Pins across search results, home feeds, related Pins, and shopping surfaces. Brands use it to run awareness, traffic, conversion, and catalog-based campaigns, often for retail, home, food, beauty, fashion, travel, and lifestyle products. Its core capability is turning visual content and product intent signals into paid placements through campaigns, ad groups, promoted Pins, catalogs, audiences, and conversion tracking.
Why integrate Pinterest Ads with a headless CMS?
Pinterest campaigns get messy when ad creative lives in one tool, landing pages live in another, and product data lives somewhere else. A merchandiser updates a product image on the site, but the promoted Pin still uses last month's photo. A growth marketer changes a UTM parameter in a spreadsheet, but the landing page CTA in production doesn't match the ad copy. Multiply that by 12 markets, 40 product lines, and seasonal campaigns, and you get slow launches plus hard-to-audit mistakes.
Architecture overview
A practical Pinterest Ads integration starts when a marketer publishes a campaign creative document in Sanity Studio. The document might reference a product, a localized landing page, a 2:3 image asset, an audience segment, a Pinterest board ID, and a Pinterest ad group ID. A Sanity webhook fires on the publish mutation, or a Sanity Function runs directly on that content event. The handler uses GROQ to fetch exactly the fields Pinterest needs, including joined references such as product price, category, image URL, locale, and UTM values. It then calls Pinterest API v5 with an OAuth access token. A common flow is POST /v5/pins to create an organic Pin on the configured board, followed by POST /v5/ad_accounts/{ad_account_id}/ads to promote that Pin in a target ad group. The handler can write the returned pin_id and ad_id back to Sanity for audit trails and later updates. After Pinterest review and activation, the end user sees the promoted Pin in Pinterest search, feeds, or shopping surfaces, and the click lands on a page powered by the same structured content.
Common use cases
Launch promoted Pins from approved content
Publish a campaign creative in Sanity Studio, create the Pinterest Pin through API v5, and attach it to the right ad group in PAUSED status for final review.
Keep product ads aligned with product pages
Use the same product title, hero image, price message, and landing URL for Pinterest creative and the product detail page.
Run localized Pinterest campaigns
Query locale-specific copy, imagery, and URLs with GROQ, then send each market's creative to its matching Pinterest board and ad group.
Control tracking links at the source
Build destination URLs with campaign, content, medium, and term parameters from structured fields instead of spreadsheet copy-paste.
Step-by-step integration
- 1
Set up Pinterest Ads access
Create or use a Pinterest Business account, confirm the ad account ID, create a Pinterest developer app, and request OAuth scopes such as pins:read, pins:write, ads:read, and ads:write. Store the access token, ad account ID, default board ID, and test ad group ID as environment variables.
- 2
Install the integration dependencies
Pinterest API v5 is available over REST, so a TypeScript integration can use fetch for Pinterest calls and @sanity/client for Content Lake reads. Install @sanity/client, then run the handler in a Sanity Function, Next.js route, or other server-side runtime.
- 3
Model Pinterest-ready content in Sanity Studio
Create a schema for campaign creatives with fields such as title, description, image, landingPage, locale, pinterestBoardId, pinterestAdGroupId, campaignCode, status, pinId, and adId. Add validation for practical ad constraints, for example a required image, a destination URL, and a title under 100 characters.
- 4
Create the publish trigger
Add a Sanity webhook filtered to published Pinterest campaign creatives, or use a Sanity Function triggered by content mutations. The trigger should send the document _id to your handler so the handler can fetch fresh content with GROQ instead of trusting a partial payload.
- 5
Call Pinterest API v5
In the handler, fetch the creative from Sanity, create a Pin with POST /v5/pins, then create the ad with POST /v5/ad_accounts/{ad_account_id}/ads. Start ads as PAUSED unless your legal, brand, and budget rules allow automatic activation.
- 6
Test the full path
Use a test board, a low-risk ad group, and one unpublished campaign first. Confirm that the Pin image renders correctly, the destination URL includes the right UTM parameters, Pinterest returns pin_id and ad_id, and the IDs are saved back to the Sanity document for later updates.
Code example
import {createClient} from '@sanity/client'
const sanity = createClient({
projectId: process.env.SANITY_PROJECT_ID!,
dataset: process.env.SANITY_DATASET!,
apiVersion: '2025-02-19',
token: process.env.SANITY_READ_TOKEN!,
useCdn: false,
})
export default async function handler(req: Request) {
const {_id} = await req.json()
const creative = await sanity.fetch(`*[_id == $id][0]{
title,
description,
"imageUrl": image.asset->url,
"url": landingPage,
pinterestBoardId,
pinterestAdGroupId
}`, {id: _id})
if (!creative?.imageUrl) return new Response('Missing image', {status: 202})
const headers = {
Authorization: `Bearer ${process.env.PINTEREST_ACCESS_TOKEN}`,
'Content-Type': 'application/json',
}
const pinRes = await fetch('https://api.pinterest.com/v5/pins', {
method: 'POST',
headers,
body: JSON.stringify({
board_id: creative.pinterestBoardId,
title: creative.title,
description: creative.description,
link: creative.url,
media_source: {source_type: 'image_url', url: creative.imageUrl},
}),
})
if (!pinRes.ok) throw new Error(await pinRes.text())
const pin = await pinRes.json()
const adRes = await fetch(
`https://api.pinterest.com/v5/ad_accounts/${process.env.PINTEREST_AD_ACCOUNT_ID}/ads`,
{
method: 'POST',
headers,
body: JSON.stringify({
ad_group_id: creative.pinterestAdGroupId,
creative_type: 'REGULAR',
name: creative.title,
pin_id: pin.id,
status: 'PAUSED',
}),
}
)
if (!adRes.ok) throw new Error(await adRes.text())
return Response.json(await adRes.json())
}How Sanity + Pinterest Ads works
Build your Pinterest Ads integration on Sanity
Sanity gives you structured content, real-time publish events, GROQ queries, and server-side Functions for connecting Pinterest Ads to your campaign workflow.
Start building free →CMS approaches to Pinterest Ads
| Capability | Traditional CMS | Sanity |
|---|---|---|
| Ad creative source data | Creative fields often live inside page layouts, which makes Pin title, image, and URL extraction brittle. | Pinterest-ready fields can be modeled directly in Sanity Studio and read as typed JSON from the Content Lake. |
| Real-time sync on publish | Teams often export CSV files or wait for scheduled jobs before Pinterest creative changes are reflected. | Webhooks and Functions can trigger Pinterest API calls when content is published, updated, or deleted. |
| Field-level query control | Integrations may receive entire pages or rendered HTML, then filter out what they don't need. | GROQ can fetch campaign fields, product references, image URLs, and locale-specific copy in one targeted query. |
| Pinterest review workflow | Editorial approval and ad approval are usually separate, with little shared status tracking. | Sanity Studio can show editorial status, Pinterest pin_id, ad_id, sync errors, and review notes in one custom workspace. |
| Multi-channel campaign consistency | Website content and ad content often diverge because each channel has its own copy workflow. | One structured back end can feed landing pages, mobile experiences, Pinterest Ads, email, and AI agents. |
Keep building
Explore related integrations to complete your content stack.
Sanity + Google Ads
Sync campaign landing pages, product copy, and tracking parameters from structured content into paid search and Performance Max workflows.
Sanity + Meta Ads
Keep Instagram and Facebook ad creative aligned with the same product, campaign, and locale content used on your site.
Sanity + Mailchimp
Reuse approved campaign copy, product blocks, and audience-specific messages across email and paid social programs.