Marketing & Advertising8 min read

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.

Published April 29, 2026
01Overview

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.


02The case for integration

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.


03Architecture

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.


04Use cases

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.


05Implementation

Step-by-step integration

  1. 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. 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. 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. 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. 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. 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.


06Code

Code example

typescript
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())
}

07Why Sanity

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 →

08Comparison

CMS approaches to Pinterest Ads

CapabilityTraditional CMSSanity
Ad creative source dataCreative 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 publishTeams 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 controlIntegrations 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 workflowEditorial 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 consistencyWebsite 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.

09Next steps

Keep building

Explore related integrations to complete your content stack.

Ready to try Sanity?

See how Sanity's Content Operating System powers integrations with Pinterest Ads and 200+ other tools.