Marketing & Advertising8 min read

How to Integrate Google Ads with Your Headless CMS

Connect structured campaign content to Google Ads so product launches, offers, landing pages, and ad copy can publish once and sync to ads without copy-paste work.

Published April 29, 2026
01 β€” Overview

What is Google Ads?

Google Ads is Google’s advertising platform for running search, display, shopping, video, app, and Performance Max campaigns across Google properties and partner inventory. Marketing teams, growth teams, agencies, and commerce companies use it to create campaigns, manage budgets, target audiences, and measure conversions. Its core capability is matching ads to intent, especially in Google Search, where campaign data, landing pages, keywords, assets, and bidding rules all need to stay accurate.


02 β€” The case for integration

Why integrate Google Ads with a headless CMS?

Google Ads works best when campaign content matches the page, product, or offer a person lands on. That gets hard when your landing page copy lives in one place, your promo details live in a spreadsheet, and your ad headlines are typed directly into Google Ads. A price changes from $49 to $39, but the ad still says $49. A landing page gets unpublished, but the final URL is still active in a campaign. Those small gaps can waste budget fast.


03 β€” Architecture

Architecture overview

A typical flow starts when an editor publishes or updates a campaign document in Sanity Studio. A webhook listens for publish events, or a Sanity Function runs directly on the content mutation. The sync code receives the document ID, uses @sanity/client to query the Content Lake with GROQ, and returns only the fields needed by Google Ads, such as campaign name, ad group resource name, final URL, headlines, descriptions, labels, start date, end date, and status. The Function then calls the Google Ads API through an OAuth refresh token, developer token, customer ID, and optional manager account login customer ID. For example, it can create a responsive search ad inside an existing ad group, update ad assets, apply labels, or pause an ad when the Sanity document is archived. After Google serves the ad, the end user clicks from Google Search or another Google Ads surface to the landing page powered by the same structured content.


04 β€” Use cases

Common use cases

πŸ”Ž

Search ad copy from approved campaign content

Sync headline and description variants from Sanity into Google Ads responsive search ads after legal, brand, and regional review.

πŸ›οΈ

Product promo ads tied to live product data

Use product references, prices, promo dates, and landing URLs from the Content Lake to keep Google Ads offers aligned with current product pages.

πŸ“

Localized ads for regional landing pages

Generate location-specific final URLs, headlines, and labels for hundreds of city or store pages without maintaining a spreadsheet.

⏸️

Automatic pausing for expired offers

Pause or label ads when a Sanity campaign document reaches its end date, is unpublished, or changes approval status.


05 β€” Implementation

Step-by-step integration

  1. 1

    Set up Google Ads API access

    Create or choose a Google Ads account, request a developer token in the Google Ads API Center, create a Google Cloud OAuth client, and generate a refresh token for the Google Ads user that can edit the target customer account. If you use a manager account, capture the login customer ID too.

  2. 2

    Install the SDK and Sanity client

    In your sync service or Sanity Function project, install google-ads-api and @sanity/client. Store GOOGLE_ADS_DEVELOPER_TOKEN, GOOGLE_ADS_CLIENT_ID, GOOGLE_ADS_CLIENT_SECRET, GOOGLE_ADS_REFRESH_TOKEN, GOOGLE_ADS_CUSTOMER_ID, and SANITY_API_TOKEN as environment variables.

  3. 3

    Model campaign content in Sanity Studio

    Create a campaign schema with fields such as title, finalUrl, adGroupResourceName, headlines, descriptions, approvalStatus, startDate, endDate, regions, product references, and googleAdsResourceName. Add validation for Google Ads limits, such as 30 characters for responsive search ad headlines and 90 characters for descriptions.

  4. 4

    Create the sync trigger

    Use a Sanity webhook filtered to published campaign documents, or use a Sanity Function triggered by content mutations. Pass the document ID to the sync handler so it can fetch the latest published content from the Content Lake.

  5. 5

    Call the Google Ads API

    Use GROQ to fetch the campaign document and referenced product or landing page data, then call Google Ads API mutate operations to create or update ads, assets, labels, or status. Keep the first version conservative, for example create paused ads that a marketer reviews in Google Ads before enabling.

  6. 6

    Test with a safe campaign and verify the landing page

    Run the integration against a test customer account or a low-budget campaign. Confirm character limits, final URLs, tracking templates, policy review status, and click paths from the ad to the page powered by Sanity.


06 β€” Code

Code example

typescriptgoogle-ads-sync.ts
import {createClient} from '@sanity/client';
import {GoogleAdsApi} from 'google-ads-api';

const sanity = createClient({
  projectId: process.env.SANITY_PROJECT_ID!,
  dataset: process.env.SANITY_DATASET!,
  apiVersion: '2025-01-01',
  token: process.env.SANITY_API_TOKEN!,
  useCdn: false
});

const ads = new GoogleAdsApi({
  client_id: process.env.GOOGLE_ADS_CLIENT_ID!,
  client_secret: process.env.GOOGLE_ADS_CLIENT_SECRET!,
  developer_token: process.env.GOOGLE_ADS_DEVELOPER_TOKEN!
});

export async function POST(req: Request) {
  const {ids} = await req.json();
  const id = ids?.created?.[0] || ids?.updated?.[0];
  if (!id) return new Response('No document id', {status: 202});

  const campaign = await sanity.fetch(`*[_id == $id][0]{
    title,
    finalUrl,
    adGroupResourceName,
    headlines[]{text},
    descriptions[]{text}
  }`, {id});

  const customer = ads.Customer({
    customer_id: process.env.GOOGLE_ADS_CUSTOMER_ID!,
    login_customer_id: process.env.GOOGLE_ADS_LOGIN_CUSTOMER_ID,
    refresh_token: process.env.GOOGLE_ADS_REFRESH_TOKEN!
  });

  await customer.mutateResources([{ 
    entity: 'ad_group_ad',
    operation: 'create',
    resource: {
      ad_group: campaign.adGroupResourceName,
      status: 'PAUSED',
      ad: {
        final_urls: [campaign.finalUrl],
        responsive_search_ad: {
          headlines: campaign.headlines.slice(0, 15),
          descriptions: campaign.descriptions.slice(0, 4)
        }
      }
    }
  }]);

  return Response.json({synced: true, title: campaign.title});
}

07 β€” Why Sanity

How Sanity + Google Ads works

Build your Google Ads integration on Sanity

Sanity gives you the structured content foundation, real-time event system, and flexible APIs to connect campaign content with Google Ads safely.

Start building free β†’

08 β€” Comparison

CMS approaches to Google Ads

CapabilityTraditional CMSSanity
Ad-ready campaign fieldsCampaign copy often sits inside page fields or rich text, so a developer has to parse content before sending it to Google Ads.Schema-as-code lets you model headlines, descriptions, final URLs, promo dates, regions, approval status, and product references as typed fields.
Real-time sync on publishTeams often rely on manual exports, scheduled jobs, or plugin-specific sync behavior.Webhooks or Functions can run server-side sync logic when content changes, with 500K Function invocations per month included.
Field-level control for Google Ads API payloadsAPIs may return full pages, rendered HTML, or fields the ad sync doesn't need.GROQ can filter, project, and join references in one query, so the Google Ads request gets only approved fields.
Editorial guardrails before spend changesApproval workflows are often page-focused, not built around ad copy variants, policy notes, or campaign status.Sanity Studio can validate Google Ads character limits, require approvalStatus before sync, and use Content Releases for launch timing.
Multi-channel campaign reuseThe web page is usually the primary output, and ad copy is maintained separately.One structured back end can feed landing pages, mobile promos, Google Ads, lifecycle emails, and AI agents from the same campaign document.

09 β€” Next 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 Google Ads and 200+ other tools.