Groups keyboard shortcuts have been updated
Dismiss
See shortcuts

Unable to Enable/Pause Demand Gen campaigns from ads script

160 views
Skip to first unread message

Ngoc Tien Tran

unread,
Feb 2, 2025, 11:40:01 PMFeb 2
to Google Ads Scripts Forum
I want to write a script, which enable/pause my campaigns programmatically
function processCampaignsIterator(iterator, campaignType) {
let count = 0;
let campaignsProcessed = [];
while (iterator.hasNext()) {
const campaign = iterator.next();
const campaignName = campaign.getName();
const campaignId = campaign.getId();

// Only process campaigns whose names contain "🔵"
if (!campaignName.includes("🔵")) {
Logger.log(
`${campaignType} Campaign "${campaignName}" (ID: ${campaignId}) does not contain "🔵". Skipping.`
);
continue;
}

Logger.log(
`Processing ${campaignType} Campaign: "${campaignName}" (ID: ${campaignId})`
);

if (action === "ON") {
if (campaign.isPaused()) {
campaign.enable();
Logger.log(
`Enabled ${campaignType} Campaign: "${campaignName}" (ID: ${campaignId})`
);
count++;
campaignsProcessed.push({ name: campaignName, id: campaignId });
} else {
Logger.log(
`${campaignType} Campaign "${campaignName}" (ID: ${campaignId}) is already enabled.`
);
}
} else if (action === "OFF") {
if (campaign.isEnabled()) {
campaign.pause();
Logger.log(
`Paused ${campaignType} Campaign: "${campaignName}" (ID: ${campaignId})`
);
count++;
campaignsProcessed.push({ name: campaignName, id: campaignId });
} else {
Logger.log(
`${campaignType} Campaign "${campaignName}" (ID: ${campaignId}) is already paused.`
);
}
} else {
Logger.log(`Invalid action "${action}" specified.`);
}
}
return { count, campaignsProcessed };
}


this function worked fine with campaigns types such as Video, Shopping, or Performance Max.
Ex: below code will works fine
// Process Video Campaigns
const videoIterator = AdsApp.videoCampaigns().get();
result = processCampaignsIterator(videoIterator, "Video");
totalCount += result.count;
processedCampaigns = processedCampaigns.concat(result.campaignsProcessed);


But now, I want to do same thing for my Demand Gen Campaigns,

I know that now the google ads script does not support for get Demand Gen Campaigns yet.

Is there any method to do this? Or I need to wait for Demand Gen Campaigns being supported by Google Ads Script? If so, when will it happened?

Many thanks. 

Google Ads Scripts Forum

unread,
Feb 2, 2025, 11:55:00 PMFeb 2
to Google Ads Scripts Forum
Hi,

Thank you for reaching out to the Google Ads Scripts Support team.

I would like to inform you that Demand Gen campaigns are not yet supported in Google Ads Scripts as stated by you already. Currently we don't have any other method available used for Demand Gen campaigns. We recommend you to please follow our blog posts for future updates and announcements as we don't have any timeline currently in place.

Thanks,
Google Ads Scripts team

Ngoc Tien Tran

unread,
Feb 3, 2025, 1:47:29 AMFeb 3
to Google Ads Scripts Forum

Thanks for your response.

I understand that currently, we have no methods to deal with Demand gen campaigns. But I read a post, that my Video campaigns are being update to Demand Gen soon in here: https://support.google.com/google-ads/answer/15110871?hl=en&sjid=8308115145357291537-NC

So when after all of my Video campaigns updated to Demand Gen, will my code to auto Enable / Pause campaigns stop to work?

Google Ads Scripts Forum Advisor

unread,
Feb 3, 2025, 4:07:41 AMFeb 3
to adwords...@googlegroups.com
Hi,

We understand your concern on the upgradation from Video Campaigns to Demand Gen. I would recommend keeping an eye on our blog post for future updates and announcements on the steps to be taken as part of this upgrade.

 
This message is in relation to case "ref:!00D1U01174p.!5004Q02vGzjn:ref" (ADR-00286753)

Thanks,
 
Google Logo Google Ads Scripts Team

Feedback
How was our support today?

rating1    rating2    rating3    rating4    rating5



Sigurd Fabrin

unread,
Feb 3, 2025, 5:40:12 AMFeb 3
to Google Ads Scripts Forum
"Unable to Enable/Pause Demand Gen campaigns from ads script"

 @Google Ads Scripts Forum Advisor replied:
"I would like to inform you that Demand Gen campaigns are not yet supported in Google Ads Scripts [...]"

Luckily, this is not true!

You can enable/pause/remove any campaign regardless of campaign type using a Google Ads script. You'll just need to use AdsApp.bulkUploads() - which is readily available in Google Ads scripts. 


The example code below will pause a campaign of any campaign type
function main() {
  const bulkUpload = AdsApp.bulkUploads()
  .newCsvUpload(['Action','Campaign','Campaign status']);
  bulkUpload.append({
        'Campaign': 'Name of your campaign',
        'Campaign status': 'Paused',
        'Action': 'Edit'
  });
  bulkUpload.setFileName('Change campaign status');
  bulkUpload.apply();
}



Sigurd

Ngoc Tien Tran

unread,
Feb 7, 2025, 1:59:40 AMFeb 7
to Google Ads Scripts Forum
@Sigurd
Thanks for your response, now I can Enable/Pause my campaigns in bulk with this code:

```
function performAction(action) {
  try {
    // Create a bulk upload object with the required CSV headers.
    var bulkUpload = AdsApp.bulkUploads().newCsvUpload(['Action', 'Campaign', 'Campaign status']);
   
    // Initialize counters and a list to store campaign details.
    var totalCount = 0;
    var processedCampaigns = [];
   
    // Example 1: Process campaigns returned by the standard selector (for standard campaigns)
    // Note: Demand Gen campaigns might not be returned by AdsApp.campaigns(), so if you have a known list,
    //       you can merge that list below.
    var campaignIterator = AdsApp.campaigns()
      .withCondition("Name CONTAINS '🔵'")
      .get();
    while (campaignIterator.hasNext()) {
      var campaign = campaignIterator.next();
      var campaignName = campaign.getName();
     
      // Append a row to the CSV upload.

      if (action === "ON") {
        bulkUpload.append({
          'Action': 'Edit',
          'Campaign': campaignName,
          'Campaign status': 'Enabled'

        });
      } else if (action === "OFF") {
        bulkUpload.append({
          'Action': 'Edit',
          'Campaign': campaignName,
          'Campaign status': 'Paused'
        });
      }
     
      // Optionally capture the campaign details (using getId() if available).
      processedCampaigns.push({ name: campaignName, id: campaign.getId() });
      totalCount++;
    }
   
    // Set a file name (for logging purposes in the Google Ads UI)

    bulkUpload.setFileName('Change campaign status');
    // Apply the bulk upload to update the campaigns.
    bulkUpload.apply();
   
    Logger.log('Bulk upload applied for ' + totalCount + ' campaign(s).');
    return { totalCount: totalCount, processedCampaigns: processedCampaigns };
  } catch (error) {
    Logger.log('Error in performAction: ' + error.message);
    throw new Error('Failed to perform action "' + action + '": ' + error.message);
  }
}
```

But I still got one problem that the AdsApp.campaigns() only return for the campaigns which has Video or Search type, not Demand Gen campaigns.

Do you know the way to get all of my active campaigns regardless to their type?

Many thanks

Sigurd Fabrin

unread,
Feb 7, 2025, 6:01:42 AMFeb 7
to Google Ads Scripts Forum
"But I still got one problem that the AdsApp.campaigns() only return for the campaigns which has Video or Search type, not Demand Gen campaigns."

You just need to use API reports to fetch the campaigns you wish to pause/enable/remove. Use this tool to get your GAQL  queries to work https://developers.google.com/google-ads/api/fields/v18/campaign_query_builder

Here's an example of a script that pauses campaigns with a too low road

* Cautionary note about using bulk uploads via script: It will upload the changes even in script preview. 
For that reason I have set the code below to upload as  preview only, meaning you'll need to manually click a button in the bulk uploads section for the changes to take effect in the account.
Change .preview() to .apply() when you are done testing

const settings = {
  costThreshold : 100, // in account currency. Ignore campaign that has spent less
  minRoas : 5, // pause campaigns if cost is above its threshold and roas is below this-  or if revenue is 0
  campaignPattern : 'some campaign name pattern', // name contains this. Or leave empty to include all
  LookbackDays: 90 // number of days, since yesterday, to assess performance
}
function main() {
  const bulkUpload = AdsApp.bulkUploads().newCsvUpload(['Action','Campaign','Campaign Status']);
  const dates = getDates(settings.LookbackDays);
  const query = `
    SELECT
      campaign.name,
      metrics.cost_micros,
      metrics.conversions_value
    FROM
      campaign
    WHERE
      campaign.status = ENABLED
      AND campaign.name LIKE "%${settings.campaignPattern}%"
      AND metrics.cost_micros > ${settings.costThreshold*1000000}
      AND segments.date BETWEEN "${dates.startDate}" AND "${dates.endDate}"`;
  console.log(`Looking at the last ${settings.LookbackDays} i.e. ${dates.startDate} - ${dates.endDate}`);
  const response = AdsApp.search(query);
  if (response.totalNumEntities() === 0) {return console.log(`No campaigns match the criteria`)}
  let counter = 0;
  while (response.hasNext()) {
    const row = response.next();
    const cost = row.metrics.costMicros/1000000; // convert to account currency
    if (!row.metrics.conversionsValue) {
      bulkUpload.append({'Action':'Edit','Campaign':row.campaign.name,'Campaign Status':'Paused'})
      counter++;
      console.log(`*** PAUSED: "${row.campaign.name}". No revenue, but cost of ${cost.toFixed(2)} ***`);
    }
    else {
    const roas = row.metrics.conversionsValue/cost;
      if (roas < settings.minRoas) {
        bulkUpload.append({'Action':'Edit','Campaign':row.campaign.name,'Campaign Status':'Paused'})
        counter++;
        console.log(`*** PAUSED: "${row.campaign.name}". Roas is ${roas.toFixed(2)} and cost is ${cost.toFixed(2)} ***`);
      }
      else {
        console.log(`All good: "${row.campaign.name}". Roas is ${roas.toFixed(2)} and cost is ${cost.toFixed(2)}`);
      }
    }
  }
  if (counter > 0) {
    bulkUpload.setFileName(`Pause ${counter} campaigns because of bad performance`);
    bulkUpload.preview(); // replace .preview() with .apply()
  }
}
function getDates(days) {
  const format = 'yyyy-MM-dd';
  const timeZone = AdsApp.currentAccount().getTimeZone();
  const today = new Date();
  const oneDay = 1000*60*60*24;
  return {
    startDate : Utilities.formatDate(new Date(today - (days * oneDay)), timeZone, format),
    endDate : Utilities.formatDate(new Date(today), timeZone, format)
  }
}



Sigurd

Google Ads Scripts Forum Advisor

unread,
Feb 7, 2025, 11:54:37 AMFeb 7
to adwords...@googlegroups.com

Hi,

@Sigurd - Thanks for the brief solution.

I would suggest that you follow the code provided by Sigurd and get back to us if you still face any issues. 

Ngoc Tien Tran

unread,
Feb 20, 2025, 11:27:46 PMFeb 20
to Google Ads Scripts Forum

Hello @Sigurd, Thanks for your reply. I'm using your bulkUpload and it's worked.
Now I can bulk ON/OFF all of my campaigns without any consider about their type is Demand Gen, Search, Video, or anything else.
But I have another problem, that now I want to create a Video Ad under an Ad Group under my Demand Gen Campaign. (I have created campaign and ad group already)
Do you know the way to do that? Is that bulk upload worked in this case?

Google Ads Scripts Forum Advisor

unread,
Feb 21, 2025, 3:59:59 AMFeb 21
to adwords...@googlegroups.com
Hi,

Currently Google Ads Scripts does not support creating a video ad under an ad group under demand gen campaign. I would recommend that you continuously follow our blog for updates and new releases on this feature. 


Thanks,
 
Google Logo Google Ads Scripts Team

Feedback
How was our support today?

rating1    rating2    rating3    rating4    rating5

[2025-02-21 08:59:36Z GMT] This message is in relation to case "ref:!00D1U01174p.!5004Q02vGzjn:ref" (ADR-00286753)



Reply all
Reply to author
Forward
0 new messages