Connect Pinterest Ads to your V0-generated Next.js app by creating a server-side API route that calls the Pinterest Ads API using an OAuth 2.0 access token. Store your Pinterest app credentials in Vercel environment variables, then fetch campaign performance metrics — impressions, clicks, spend, and conversions — to display in a custom visual analytics dashboard built with V0.
Visualizing Pinterest Ads Performance in a V0 Dashboard
Pinterest is a unique advertising platform where users actively seek inspiration and shopping ideas — making it particularly effective for e-commerce, home decor, fashion, food, and lifestyle brands. Pinterest Ads analytics tell a different story than other platforms: visually-driven metrics like close-up rates and save rates matter alongside standard click-through rates. Building a custom analytics dashboard with V0 gives you the flexibility to surface the metrics that matter most for Pinterest's visual format.
The Pinterest Ads API v5 is the current version, providing access to ad accounts, campaigns, ad groups, ads, and analytics. Authentication uses OAuth 2.0 — either a long-lived access token for server-side integrations or a full OAuth flow for multi-account tools. For a single-account analytics dashboard, using a long-lived token generated in the Pinterest Developer portal is the simplest approach.
V0 excels at generating dashboard layouts with data tables, charts, and metric cards. For Pinterest specifically, the visual nature of the platform lends itself to showing Pin thumbnails alongside performance data — a design choice that makes your analytics dashboard feel native to Pinterest. This tutorial walks through fetching campaign analytics, calculating key metrics, and displaying them in a V0-generated dashboard.
Integration method
Pinterest Ads API uses OAuth 2.0 for authentication. Integration happens through a Next.js API route that exchanges your access token for Pinterest API calls to fetch ad account data, campaign metrics, and performance analytics. The access token and app credentials are stored in Vercel environment variables, and all API calls are made server-side to keep credentials out of the browser.
Prerequisites
- A V0 account at v0.dev with a Next.js project created
- A Pinterest Business account with active ad campaigns
- A Pinterest Developer app registered at developers.pinterest.com
- A Pinterest Ads API access token (generated in the Developer portal or via OAuth flow)
- Your Pinterest ad account ID from the Ads Manager
- A Vercel account connected to your V0 project for deployment
Step-by-step guide
Generate the Ads Analytics Dashboard UI with V0
Generate the Ads Analytics Dashboard UI with V0
Open V0 and describe the Pinterest Ads analytics dashboard you want to build. Pinterest's visual format means a good dashboard design should incorporate some visual elements alongside the numbers — Pin thumbnails, color-coded performance indicators, and chart visualizations suited to campaign data. Ask V0 to generate a dashboard with metric summary cards at the top showing total spend, impressions, clicks, and conversions, followed by a sortable campaign data table below. Include a date range picker so users can filter by last 7 days, last 30 days, or a custom range. Ask for a spend trend line chart using recharts (V0 handles this library well). Request status badge components for campaign status (active, paused, archived) with color coding. Make sure V0 generates proper loading skeletons since API calls have latency, and request empty state components for when no campaigns are found. Once the UI is generated, review it in the V0 preview and refine any layout issues before moving on to the API routes.
Build a Pinterest Ads analytics dashboard with Pinterest's red (#E60023) as the accent color. Include: 4 metric cards at the top (Total Spend, Impressions, Clicks, CTR), a date range selector, a campaign performance table with columns for Campaign Name, Status, Budget, Spend, Impressions, Clicks, and CTR, and a spend-over-time line chart below. Add sorting on all table columns. Show skeleton rows while loading data from /api/pinterest-ads/campaigns.
Paste this in V0 chat
Pro tip: Ask V0 to use Pinterest's brand red (#E60023) as the accent color for CTAs and highlights — it makes the dashboard feel appropriately on-brand for Pinterest analytics.
Expected result: A Pinterest-styled analytics dashboard with metric cards, a data table, and chart area renders in the V0 preview.
Get a Pinterest Ads API Access Token
Get a Pinterest Ads API Access Token
Before writing any code, you need an access token for the Pinterest Ads API. There are two ways to obtain one. The first and simplest method for a single-account dashboard is to generate a long-lived token directly in the Pinterest Developer portal: go to developers.pinterest.com, log in, navigate to My Apps, create a new app, then use the app's credentials to generate an access token via the OAuth token endpoint. The token has the ads:read scope for fetching analytics data. The second method is implementing a full OAuth 2.0 authorization code flow for multi-account tools — this is more complex and requires redirect URI handling. For most analytics dashboards managing a single Pinterest Ads account, the long-lived token approach is sufficient. In the Pinterest Developer portal, go to your app settings, click 'Generate access token', select the ads:read scope, and copy the token that is generated. This token is tied to your Pinterest account and gives read access to all ad accounts associated with it. Store it securely — treat it like an API key.
Pro tip: Pinterest access tokens expire after a year by default. Plan for token refresh by implementing the OAuth refresh token flow if you need long-term unattended access to the API.
Expected result: You have a Pinterest Ads API access token with the ads:read scope ready to add to Vercel.
Create the Pinterest Ads API Routes
Create the Pinterest Ads API Routes
Create a Next.js App Router route handler at app/api/pinterest-ads/campaigns/route.ts that calls the Pinterest Ads API v5 to fetch campaign performance data. The Pinterest Ads API base URL is https://api.pinterest.com/v5. To fetch campaigns, call GET /ad_accounts/{ad_account_id}/campaigns. To fetch analytics for those campaigns, call GET /ad_accounts/{ad_account_id}/campaigns/analytics with date range parameters in YYYY-MM-DD format. The analytics endpoint returns metrics per campaign per day. You will need your Pinterest ad account ID — find it in Ads Manager (the number in the URL when you are viewing your ad account). Your route handler should accept query parameters for startDate and endDate and pass them to the Pinterest analytics endpoint. Combine the campaign list (for names and budgets) with the analytics data (for performance metrics) by joining on campaignId. Return a unified array of campaign objects with both static fields and performance metrics to your frontend. Always authenticate using the Bearer token: set the Authorization header to Bearer ${process.env.PINTEREST_ACCESS_TOKEN}.
1// app/api/pinterest-ads/campaigns/route.ts2import { NextRequest, NextResponse } from 'next/server';34const PINTEREST_API = 'https://api.pinterest.com/v5';5const AD_ACCOUNT_ID = process.env.PINTEREST_AD_ACCOUNT_ID;67function getHeaders() {8 return {9 'Authorization': `Bearer ${process.env.PINTEREST_ACCESS_TOKEN}`,10 'Content-Type': 'application/json',11 };12}1314export async function GET(request: NextRequest) {15 const { searchParams } = new URL(request.url);16 const startDate = searchParams.get('startDate') || getDefaultStartDate();17 const endDate = searchParams.get('endDate') || getTodayDate();1819 try {20 // Fetch campaigns list21 const campaignsResponse = await fetch(22 `${PINTEREST_API}/ad_accounts/${AD_ACCOUNT_ID}/campaigns?page_size=25`,23 { headers: getHeaders(), next: { revalidate: 300 } }24 );2526 if (!campaignsResponse.ok) {27 return NextResponse.json(28 { error: `Pinterest API error: ${campaignsResponse.status}` },29 { status: campaignsResponse.status }30 );31 }3233 const campaignsData = await campaignsResponse.json();3435 // Fetch analytics for the date range36 const analyticsUrl = new URL(37 `${PINTEREST_API}/ad_accounts/${AD_ACCOUNT_ID}/campaigns/analytics`38 );39 analyticsUrl.searchParams.set('start_date', startDate);40 analyticsUrl.searchParams.set('end_date', endDate);41 analyticsUrl.searchParams.set('columns', 'SPEND_IN_DOLLAR,IMPRESSION_1,CLICK_TYPE_URL_CLICK,TOTAL_CONVERSIONS');42 analyticsUrl.searchParams.set('granularity', 'TOTAL');4344 const analyticsResponse = await fetch(analyticsUrl.toString(), {45 headers: getHeaders(),46 });47 const analyticsData = await analyticsResponse.json();4849 // Merge campaigns with analytics50 const analyticsMap = new Map(51 (analyticsData || []).map((a: Record<string, unknown>) => [a.campaign_id, a])52 );5354 const campaigns = (campaignsData.items || []).map((c: Record<string, unknown>) => {55 const analytics = analyticsMap.get(c.id) as Record<string, unknown> | undefined;56 return {57 id: c.id,58 name: c.name,59 status: c.status,60 budget: c.daily_budget,61 spend: analytics?.SPEND_IN_DOLLAR || 0,62 impressions: analytics?.IMPRESSION_1 || 0,63 clicks: analytics?.CLICK_TYPE_URL_CLICK || 0,64 conversions: analytics?.TOTAL_CONVERSIONS || 0,65 ctr: analytics?.IMPRESSION_166 ? ((analytics.CLICK_TYPE_URL_CLICK as number) / (analytics.IMPRESSION_1 as number) * 100).toFixed(2)67 : '0.00',68 };69 });7071 return NextResponse.json({ campaigns });72 } catch (error) {73 console.error('Pinterest Ads error:', error);74 return NextResponse.json({ error: 'Failed to fetch campaigns' }, { status: 500 });75 }76}7778function getDefaultStartDate() {79 const d = new Date();80 d.setDate(d.getDate() - 30);81 return d.toISOString().split('T')[0];82}8384function getTodayDate() {85 return new Date().toISOString().split('T')[0];86}Pro tip: The Pinterest analytics endpoint requires at least one column in the 'columns' parameter. Start with SPEND_IN_DOLLAR, IMPRESSION_1, and CLICK_TYPE_URL_CLICK as the core metrics.
Expected result: Calling /api/pinterest-ads/campaigns returns a JSON array of campaign objects with spend, impressions, clicks, and CTR for the date range.
Add Environment Variables in Vercel
Add Environment Variables in Vercel
In the Vercel Dashboard, navigate to your project and click Settings → Environment Variables. Add the following variables. PINTEREST_ACCESS_TOKEN: the long-lived OAuth access token generated from the Pinterest Developer portal. PINTEREST_AD_ACCOUNT_ID: your Pinterest ad account ID — a numeric string found in the URL when viewing your Ads Manager account (e.g., if the URL is ads.pinterest.com/advertiser/123456789/, your account ID is 123456789). Neither of these variables should have the NEXT_PUBLIC_ prefix since they are used only in server-side route handlers and must never appear in browser-accessible JavaScript. Set these variables for all environment scopes: Production, Preview, and Development. For Development, you can use the same credentials since there is no separate sandbox environment for Pinterest Ads (you will be reading real campaign data). After adding the variables, redeploy your Vercel project. Verify the integration is working by navigating to /api/pinterest-ads/campaigns in your browser — you should see real campaign data returned.
Pro tip: Pinterest's access token can be verified by calling the Pinterest API test endpoint: GET https://api.pinterest.com/v5/user_account — it should return your Pinterest user information if the token is valid.
Expected result: PINTEREST_ACCESS_TOKEN and PINTEREST_AD_ACCOUNT_ID are configured in Vercel environment variables and the API route returns live campaign data.
Common use cases
Campaign Performance Dashboard
A D2C e-commerce brand uses V0 to build a Pinterest Ads analytics dashboard showing campaign spend, ROAS, and top-performing Pins with thumbnail previews, updated daily.
Create a Pinterest Ads dashboard with a date range picker and campaign filter dropdown at the top. Show metric cards for total spend, total impressions, average CTR, and total conversions. Below, a campaign table with campaign name, status badge, budget, spend, impressions, clicks, and CTR. Sort by spend descending by default. Fetch from /api/pinterest-ads/campaigns.
Copy this prompt to try it in V0
Pin Performance Analysis
A content creator analyzes which of their promoted Pins perform best. The V0 dashboard shows Pin thumbnails alongside engagement metrics to identify winning creatives for budget allocation.
Build a Pin performance page with a masonry grid of promoted Pin cards. Each card shows the Pin thumbnail image, Pin title, ad group name, and metrics: saves, close-ups, clicks, and spend. Allow sorting by any metric. Add a 'Top Performers' section highlighting the 3 Pins with the best click-through rate this week.
Copy this prompt to try it in V0
Weekly Ads Report Generation
A marketing agency uses V0 to build a client-facing Pinterest Ads report page that automatically pulls the past week's campaign data and displays it in a clean, shareable format.
Create a weekly Pinterest Ads report page with a header showing client logo, report period, and total ad spend. Display a summary section with week-over-week change indicators for impressions, clicks, and conversions. Add a campaign breakdown table and a spend-over-time line chart. Include an export to PDF button.
Copy this prompt to try it in V0
Troubleshooting
Pinterest API returns 401 Unauthorized
Cause: The PINTEREST_ACCESS_TOKEN is invalid, expired, or does not have the ads:read scope.
Solution: Regenerate the access token in the Pinterest Developer portal. Make sure to select the ads:read scope when generating. Verify the token is correctly copied without trailing whitespace into the Vercel environment variable.
Pinterest API returns 403 Forbidden on analytics endpoint
Cause: The access token belongs to a user who does not have access to the specified ad account, or the ad account ID is incorrect.
Solution: Verify the PINTEREST_AD_ACCOUNT_ID matches the numeric ID in your Ads Manager URL. The Pinterest account that generated the access token must be an admin or analyst on that ad account.
Analytics endpoint returns an empty array with no data
Cause: No campaigns ran during the specified date range, or the date format is incorrect. Pinterest requires YYYY-MM-DD format for date parameters.
Solution: Verify the date format in your API route uses YYYY-MM-DD (e.g., '2026-03-01', not '03/01/2026'). Check the Ads Manager to confirm campaigns were active during the date range being queried.
1// Correct date format2const startDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString().split('T')[0]; // '2026-03-01'Campaign spend shows $0 for active campaigns
Cause: The analytics endpoint column name for spend is SPEND_IN_DOLLAR — using the wrong column name returns null or zero.
Solution: Double-check the exact column names in the Pinterest API documentation. Spend is SPEND_IN_DOLLAR (not SPEND or COST). Add console.log of the raw API response in development to confirm what field names Pinterest returns.
Best practices
- Store PINTEREST_ACCESS_TOKEN and PINTEREST_AD_ACCOUNT_ID in Vercel environment variables without the NEXT_PUBLIC_ prefix
- Cache Pinterest analytics responses with next: { revalidate: 300 } to reduce API calls since campaign data does not change minute-by-minute
- Use YYYY-MM-DD date format for all Pinterest API date parameters
- Implement pagination for large ad accounts with many campaigns using the Pinterest API's page_size and bookmark parameters
- Display CTR as a percentage (e.g., 2.35%) rather than a decimal (0.0235) for more intuitive dashboard readability
- Show week-over-week or period-over-period percentage changes alongside absolute numbers to make performance trends immediately visible
- Include a campaign status filter since Pinterest Ads accounts often have many paused or archived campaigns alongside active ones
Alternatives
Twitter Ads focuses on text-based engagement targeting rather than Pinterest's visual shopping intent, making it better for awareness and conversation-driven campaigns.
Reddit Ads targets interest-based communities with text and image formats, suited for reaching niche audiences rather than Pinterest's broadly visual shopping intent.
LinkedIn Ads is better for B2B targeting and professional audiences, while Pinterest Ads excels for consumer lifestyle, e-commerce, and visual product categories.
Frequently asked questions
Where do I find my Pinterest ad account ID?
Your Pinterest ad account ID is the numeric string in the URL when you are logged into Pinterest Ads Manager. For example, if your URL is https://ads.pinterest.com/advertiser/123456789/overview/, your ad account ID is 123456789. It is also visible in Ads Manager under account settings.
Does the Pinterest Ads API have a sandbox or test environment?
Pinterest does not offer a separate sandbox environment for the Ads API. API calls read from and write to your real Pinterest Ads account. Use a test ad account with minimal or paused campaigns during development to avoid accidentally modifying active campaigns.
What metrics does Pinterest Ads API provide?
Pinterest Ads API provides impressions, clicks, spend, saves (Pins saved to boards), close-up views (zoomed-in engagements), outbound clicks (to your website), video views, add-to-cart events, checkouts, and custom conversion events. Visual engagement metrics like close-ups and saves are unique to Pinterest and often more meaningful than click rates alone.
Can I use the Pinterest Ads API to create and manage campaigns?
Yes, the Pinterest Ads API v5 supports both read and write operations. With the ads:write scope, you can create campaigns, ad groups, and ads programmatically. For the analytics dashboard in this tutorial, the ads:read scope is sufficient.
How do I handle accounts with hundreds of campaigns in the API?
The Pinterest Ads API returns paginated results with a default page size of 25. To fetch all campaigns, implement cursor-based pagination: check for a bookmark in the API response and include it as a bookmark parameter in your next request until no more pages exist. For very large accounts, consider fetching only active campaigns in the initial load.
Can V0 generate a pin thumbnail grid for ad creative analysis?
Yes. Prompt V0 to generate a masonry or responsive grid layout showing Pinterest Pin thumbnails with overlay performance metrics. V0 will use the Next.js Image component for the thumbnails and position metric badges using absolute positioning with Tailwind. Wire up the Pin image URL from the Pinterest API's pin_id field which resolves to a thumbnail URL.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation