In order to have as much control over the keywords per product in our shopping campaigns, we always place all products in an ad group. That way, you can exclude words per product on which other products can still be displayed.

But as soon as you have more than 10 products in the product feed, you do not want to do this manually. You have to create an ad group per product, add a product, add a bid and exclude 'Other products'. That is why we have created a script that automatically updates this based on the XML product feed. The script goes through all products in feed and checks whether these are already in the shopping campaigns. If the products are new, they will be added to the campaigns.

Set up campaigns manually

From Google Ads Scripts we can not create new Shopping campaigns. That is why you have to create and set it yourself as you wish. When you next run this script for the first time, you will have to do this several times to ensure that all products are in it. On average, the script gets 500 products in half an hour, so turn the script the first time often enough to add all products.

Settings

To run this script properly, you need to set the following things correctly:

  • LOG: Specify whether the script should report the intermediate steps by adjusting the value to 'true'.
  • PRODUCT_FEED_URL: Enter the URL of the XML product feed as it appears in Google Merchant Center
  • SPREADSHEET_URL: Create a new spreadsheet to track the progress of the script.
  • SHEET_NAME: The name of the tab in the spreadsheet. In addition, make sure you enter a '0' in cell A1.
  • DEFAULT_BID: The Max. CPC that is filled in for each product.

Scheduling: If you have more than 500 products, you set them the first time for each hour. When all products are in the campaigns, change this to daily. Make sure you choose a time after updating your product feed in Merchant Center.

Script
// Copyright 2019. Increase BV. All Rights Reserved.
//
// Created By: Tibbe van Asten
// for Increase B.V.
// 
// Last update: 01-03-2019
//
// ABOUT THE SCRIPT
// This scripts adds new adgroups to the branded shopping campaigns,
// based on the productfeed. 
//
////////////////////////////////////////////////////////////////////

var config = {
  
  // You will need a xml-productfeed according to the Google Shopping specifications
  // And create a spreadsheet to keep track of the scripts progress.
  
  LOG : false,  
  PRODUCT_FEED_URL : "XYZ.xml",
  
  // Create a new Google Spreadsheet and set cell A1 to '0'
  SPREADSHEET_URL : "https://docs.google.com/spreadsheets/d/XYZ/edit",
  SHEET_NAME : "Blad 1",
  
  // This bid will be just to set for all new products
  DEFAULT_BID : 1.5
  
}

////////////////////////////////////////////////////////////////////

function main() {
  
  // Connect to the feed and sheet
  var entries = connectFeed();
  var cell = connectSheet();
  var atom = XmlService.getNamespace('http://base.google.com/ns/1.0');  
	
  // Determine where to start 
  var start = cell.getValue();

  for (var i = start; i < entries.length; i++) {   

    // If the script has run all instances of the productfeed, it will start again.
    if(i == (entries.length -1)) {
      i = 0;
      cell.setValue(0);
      
      	Logger.log("Reset to 0");
      
      break;
    }
    
    // When a product from the feed has no id, we will skip it. Otherwise it will result in error.
    if(entries[i].getChild('id', atom) !== null) {
      
      if(config.LOG === true) {
        Logger.log("Id: " + entries[i].getChild('id', atom).getText());
      }
      
      campaignSelector(entries, i, atom);
    
    } // if id exist
    
    cell.setValue(i);
    
  } // for statement

} // function main()

////////////////////////////////////////////////////////////////////

function connectFeed(){
  
  var xml = UrlFetchApp.fetch(config.PRODUCT_FEED_URL).getContentText();
  var document = XmlService.parse(xml);
  var entries = document.getRootElement().getChild('channel').getChildren('item');
  
  return entries;
  
} // function connectFeed()

////////////////////////////////////////////////////////////////////

function connectSheet(){
  
  var ss = SpreadsheetApp.openByUrl(config.SPREADSHEET_URL);
  var sheet = ss.getSheetByName(config.SHEET_NAME);
  var cell = sheet.getRange('A1');
  
  return cell;
  
} // connectSheet()

////////////////////////////////////////////////////////////////////

function campaignSelector(entries, i, atom){
  
  // First we select the campaign
  var campaignIterator = AdsApp
    .shoppingCampaigns()
    .withCondition("Name DOES_NOT_CONTAIN 'Intent'")
    .withCondition("CampaignStatus = ENABLED")
    .get();

  while(campaignIterator.hasNext()) {
    var campaign = campaignIterator.next();
    
    adGroupBuilder(campaign, entries, i, atom);
  }

} // function campaignSelector()

////////////////////////////////////////////////////////////////////

function adGroupBuilder(campaign, entries, i, atom){
  
    // Then we check if a adgroup with the same name already exists
    var adGroupIterator = campaign
      .adGroups()
      .withCondition("Status != REMOVED")
      .withCondition("Name = '" + entries[i].getChild('id', atom).getText() + "'")
      .get();

    // When there is no adgroup with the same name, one is created
    if(!adGroupIterator.hasNext()) {
      
      var shoppingAdGroup = campaign
        .newAdGroupBuilder()
        .withName(entries[i].getChild('id', atom).getText())
        .withCpc(config.DEFAULT_BID)
        .withStatus("ENABLED")
        .build()
        .getResult();

      Logger.log("Adgroup " + entries[i].getChild('id', atom).getText() + " added to " + campaign.getName());

      // Adding a ad to the new adgroup
      var ad = shoppingAdGroup
        .newAdBuilder()
        .build()
        .getResult();

      // Creating the root productgroup 'All Products'
      shoppingAdGroup.createRootProductGroup();
      var root = shoppingAdGroup.rootProductGroup();
      
      itemBuilder(entries, i, atom, root);
      excludeOtherCase(root);

    } // if adgroup doesn't exist
  
} // function adGroupBuilder()

////////////////////////////////////////////////////////////////////

function itemBuilder(entries, i, atom, root){
  
  // Creating a productgroup for this product
  root.newChild().itemIdBuilder()
    .withBid(config.DEFAULT_BID)
    .withValue(entries[i].getChild('id', atom).getText())
    .build();
  
} // itemBuilder()

////////////////////////////////////////////////////////////////////

function excludeOtherCase(root){
  
  // Making sure all other products in this adgroup are excluded
  var children = root.children().get();
  while (children.hasNext()) {
    var child = children.next();
    if (child.isOtherCase()) {
      child.exclude();
    }
  }
  
} // function excludeOtherCase()

Sharing knowledge

Adsscripts.com is all about sharing knowledge. In the current market, PPC specialists like to keep their knowledge and experience to themselves. We're convinced that sharing knowledge can ensure that everyone gets better at their work. We want to change this by sharing our knowledge about scripts with everyone.

Do you also want to contribute? We are open to new ideas and feedback on everything you find on Adsscripts.com.

Contact us

Nils Rooijmans
Google Ads Scripter
Water Cooler Topics
Nils Rooijmans, Google Ads Scripter
Bas Baudoin
Teamleader PPC
Happy Leads
Bas Baudoin, Teamleider SEA
Tibbe van Asten
PPC Specialist
Founder Adsscripts
Tibbe van Asten, Senior PPC Automation Specialist