Zernio
Zernio
PlatformsGoogle Ads

Build

Create AdsPerformance MaxDemand Gen

Target

KeywordsCustomer Match

Measure

Insights & GAQLConversionsURL Tracking Tags

Operate

RecommendationsAccounts & LabelsLimits and errors
Dashboard
llms.txtOpenAPI
OverviewPlatformsAPI ReferenceResources
Google Ads

Demand Gen

Create Google Demand Gen campaigns with image, video or carousel ads across YouTube, Discover and Gmail, grow them with new ad groups and ads, and edit creative, channels, audiences and targeting.


When you finish this page a Google Demand Gen campaign exists, paused, with one ad group and one ad, from one POST /v1/ads/create call, and you know how to add ad groups and ads to it and edit them later. You need a googleads account and the customer id from List ad accounts.

Demand Gen serves on YouTube (in-stream, in-feed and Shorts), Discover, Gmail and Google's display partners. Set campaignType: "demand_gen" and put the creative, channel and audience settings in demandGen. The request creates a daily budget, the campaign, one ad group and one ad in a single atomic Google request.

Create a campaign

curl -X POST "https://zernio.com/api/v1/ads/create" \
  -H "Authorization: Bearer $ZERNIO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "accountId": "66b2e19d8c3f5a7e9d0b1c2d",
    "adAccountId": "1234567890",
    "name": "Demand Gen launch",
    "campaignType": "demand_gen",
    "budgetAmount": 10,
    "budgetType": "daily",
    "countries": ["ES"],
    "languages": ["es"],
    "demandGen": {
      "finalUrl": "https://example.com",
      "businessName": "Acme",
      "headlines": ["Schedule posts", "One social API"],
      "descriptions": ["Publish and manage social content through one API."],
      "callToAction": "Learn more",
      "images": {
        "landscape": ["https://cdn.example.com/landscape-1200x628.png"],
        "square": ["https://cdn.example.com/square-1080x1080.png"],
        "logo": ["https://cdn.example.com/logo-512.png"]
      },
      "channels": ["youtube_in_feed", "youtube_shorts", "discover", "gmail"],
      "audience": {
        "userInterests": ["92948"],
        "ageRanges": [{ "min": 25, "max": 54 }]
      }
    }
  }'

The created ad carries Google's native platformCampaignId, platformAdSetId (the ad group) and platformAdId. The campaign is always created paused; enable it with PUT /v1/ads/campaigns/{campaignId}/status once you have reviewed it. Send validateOnly: true to have Google validate the whole request without creating anything.

  • budgetType is daily, in whole units of the account currency like every other Google create.
  • Geo (countries, regions, cities, zips, metros) and languages are written on the ad group, because Demand Gen keeps them there rather than on the campaign.
  • Bidding: omit bidStrategy (or send LOWEST_COST_WITHOUT_CAP) for Maximize Conversions, COST_CAP plus bidAmount for target CPA, LOWEST_COST_WITH_MIN_ROAS plus roasAverageFloor for target ROAS, or LOWEST_COST_WITH_BID_CAP plus bidAmount for target CPC.
  • locationTargetingType (presence or presence_or_interest) is set on the new campaign.

Choose the ad format

The fields you send in demandGen pick one of three ad formats:

FormatSelected byCreative fields
Multi-asset image adDefaultheadlines (1 to 5, 40 characters), descriptions (1 to 5, 90 characters), businessName, optional callToAction, and images.landscape or images.square (optionally portrait) plus images.logo
Video responsive adyoutubeVideoIds (1 to 5 existing YouTube video ids)headlines, longHeadlines (1 to 5, 90 characters, required here), descriptions, businessName, and exactly one images.logo
Carousel adcarouselCards (2 to 10 cards)Exactly one headline, one description, one logo, businessName and optional callToAction; each card has its own headline, images and optional finalUrl and callToAction

finalUrl, businessName (25 characters), headlines, descriptions and images.logo are always required. Image sizes: landscape 1.91:1 (at least 600 x 314), square 1:1 (at least 300 x 300), portrait 4:5 (at least 480 x 600) and logo 1:1 (at least 128 x 128).

A carousel ad looks like this:

{
  "campaignType": "demand_gen",
  "demandGen": {
    "finalUrl": "https://example.com",
    "businessName": "Acme",
    "headlines": ["One social API"],
    "descriptions": ["Publish everywhere from one API."],
    "images": { "logo": ["https://cdn.example.com/logo-512.png"] },
    "carouselCards": [
      { "headline": "Schedule posts", "images": { "square": "https://cdn.example.com/card-1.png" } },
      { "headline": "Read analytics", "finalUrl": "https://example.com/pricing", "images": { "square": "https://cdn.example.com/card-2.png" } }
    ]
  }
}

Each card needs its own image (no two cards may share one), and every card should use the same image shape. Card images are uploaded to the account's asset library before the campaign is created, validateOnly included, because Google checks cards against existing images; an identical image is reused, not duplicated.

Channels and audiences

demandGen.channels sets the ad group's channel controls: only the listed channels serve, out of youtube_in_stream, youtube_in_feed, youtube_shorts, discover, gmail and display. Omit it to serve on all of them.

demandGen.audience builds a Google Audience and attaches it to the ad group. Send at least one dimension:

FieldValues
userListsNumeric Google user list ids, such as a Customer Match list (up to 20)
userInterestsNumeric Google interest category ids (up to 20)
customAudiencesNumeric Google custom audience ids (up to 20)
ageRangesObjects with min (18, 25, 35, 45, 55 or 65) and optional max (24, 34, 44, 54 or 64; omit for no upper bound)
gendersmale, female, undetermined

All ids must belong to the same Google customer. To reuse an Audience you already have, send its numeric id as demandGen.audienceId instead of audience.

Add ad groups and ads

Grow an existing Demand Gen campaign with the same endpoint and campaignType: "demand_gen":

  • A new ad group: send existingCampaignId with the campaign's Google id. The new ad group gets its own geo, languages, channels and audience from the request, plus its ad, in one atomic request, and is created paused. demandGen.adGroupName names it (it defaults to the ad name).
  • A new ad in an ad group: send adSetId with the ad group's Google id. demandGen carries only the ad's creative; ad group settings (geo, languages, channels, audience, audienceId, adGroupName) return 400. The new ad is created paused.
{
  "accountId": "66b2e19d8c3f5a7e9d0b1c2d",
  "adAccountId": "1234567890",
  "name": "Demand Gen, second audience",
  "campaignType": "demand_gen",
  "existingCampaignId": "23508518100",
  "countries": ["US"],
  "demandGen": {
    "adGroupName": "Returning visitors",
    "finalUrl": "https://example.com",
    "businessName": "Acme",
    "headlines": ["Schedule posts"],
    "descriptions": ["Publish everywhere from one API."],
    "images": {
      "square": ["https://cdn.example.com/square-1080x1080.png"],
      "logo": ["https://cdn.example.com/logo-512.png"]
    },
    "audience": { "userLists": ["123456"] }
  }
}

Neither shape takes budget, bidding or schedule fields: the campaign owns them, and sending them returns 400. locationTargetingType also belongs to the campaign and returns 400 here. The target must be a Demand Gen campaign or ad group, otherwise the request returns 400. Both shapes support validateOnly. A campaign migrated from Discovery that still targets locations and languages on the campaign refuses them on a new ad group, so geo and language fields return 400 there and the new ad group follows the campaign's targeting.

Edit creative, channels and audience

PUT /v1/ads/{adId} takes a top-level demandGen object and applies it in one atomic Google request. Every field you send replaces that whole field; fields you omit are kept.

curl -X PUT "https://zernio.com/api/v1/ads/66f0a1b2c3d4e5f6a7b8c9d2" \
  -H "Authorization: Bearer $ZERNIO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "demandGen": {
      "headlines": ["Schedule posts", "One social API"],
      "images": { "square": ["https://cdn.example.com/new-square.png"] },
      "audience": { "userInterests": ["92948"], "genders": ["female"] }
    }
  }'
  • Which creative fields apply depends on the ad's format, read from Google: image ads take headlines, descriptions, businessName, callToAction and images; video ads take headlines, longHeadlines, descriptions, businessName, youtubeVideoIds and exactly one images.logo; carousel ads take one headline, one description, one logo, businessName and callToAction. A field the ad does not take returns 422.
  • A carousel's cards cannot be edited: create a new carousel ad instead.
  • New images are uploaded as new Google assets; the previous ones stay in the account's asset library.
  • channels, audience and audienceId change the ad's ad group, so they apply to every ad in it. audience builds a new Google Audience and attaches it in place of the current one (the previous audience is detached, not deleted). Ad groups of campaigns migrated from Discovery use ungrouped audience segments, and Google refuses an Audience on them.
  • The Search and Display creative fields (headlines at the top level, creative, assetGroup) return 422 on a Demand Gen ad, and demandGen returns 422 on any other channel.

Edit targeting

Demand Gen keeps locations and languages on the ad group, so there are two ways to change them:

  • targeting on PUT /v1/ads/{adId} takes locations, languages, locationTargetingType and devices. Locations and languages go to that ad's ad group and apply to every ad in it.
  • PUT /v1/ads/campaigns/{campaignId}/targeting writes locations and languages to the campaign's ad group when it has exactly one, and the response carries that adGroupId; the campaign-level locations and languages read back then stay empty. With several ad groups the call returns 400 naming them, so edit each through an ad in that ad group. devices and locationTargetingType stay campaign-level.

Campaigns migrated from Discovery that still target on the campaign keep being written there. Budget, bidding and name are edited with the regular campaign endpoints.

Related

  • Create ads: Search, Display and Performance Max on the same endpoint.
  • Customer Match: build the user lists audience.userLists takes.
  • Create standalone ad and Update ad: every field of demandGen.
Was this page helpful?

Performance Max

Manage the asset groups of a Google Performance Max campaign: read them with ad strength, add new groups, edit URLs and status, link and unlink assets, and replace the retail listing-group tree.

Keywords

Read the Search keywords your Google campaigns run, add keywords to an ad group, and research new ones with the Keyword Planner.

On this page

Create a campaignChoose the ad formatChannels and audiencesAdd ad groups and adsEdit creative, channels and audienceEdit targetingRelated