By adding as many locations as possible in your campaign, you gain more insight into the performance in the target area. That way you can make bid adjustments to reduce the cost per conversion in locations that are too expensive.

We also have scripts for bidadjustments for audiences, devices or adschedule. Start automating all of your bidadjustments today.

Settings

In the script you can only adjust the following things:

  • LOG: Specify whether the script should report the intermediate steps by adjusting the value to true.
  • DATE_RANGE: The script looks at the conversions and costs over this period.
  • EXCLUDE_LOCATIONS: Exclude locations from this scripts with location ID's. Add multiple location ID's with comma's separated. Find the ID's here: https://developers.google.com/adwords/api/docs/appendix/geotargeting
  • MINIMUM_CONVERSIONS: Optional, select only location with this number of conversions or more
  • MINIMUM_COST: Optional, select only location with this amount of spend or more.
  • MINIMUM_CLICKS: Optional, only select location with this number of clicks.
  • MAX_BID: The bidadjustment will not be higher than this. 1.3 = +30% or 2 = +100%
  • MIN_BID: The bidadjustment will not be lower than this. 0.75 = -25% or 0.5 = -50%.

Scheduling: To generate sufficient data we advise to run the script once a day or week.

Script
// Copyright 2019. Increase BV. All Rights Reserved.
//
// Created By: Tibbe van Asten
// for Increase B.V.
// 
// Created: 20-07-2018
// Last update: 19-09-2019
//
// ABOUT THE SCRIPT
// With this script we adjust the biddings for locations in 
// active campaigns.
//
////////////////////////////////////////////////////////////////////

var config = {

  LOG : true,
  DATE_RANGE : "LAST_30_DAYS",
  
  // Add location ID's to skip from bidadjustments, comma seperated
  // Find location ID's: https://developers.google.com/adwords/api/docs/appendix/geotargeting
  EXCLUDE_LOCATIONS : "",
  
  // Optional: Use minimum conversions and/or cost to select devices.
  // Cost is in account currency. Leave empty to skip.
  MINIMUM_CONVERIONS : "2",
  MINIMUM_CLICKS : "100",
  MINIMUM_COST : "10",
  
  // Bidadjustments won't be higher then MAX_BID and not lower then MIN_BID.
  // Examples: 1.2 = +20%, 0.8 = -20%, 2 = +100%.
  MAX_BID : 1,
  MIN_BID : 0.8,
  
}

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

function main() {
    
  var locationIterator = AdsApp
    .targeting()
    .targetedLocations()
    .withCondition("CampaignStatus = ENABLED")
    .get();

  while(locationIterator.hasNext()) {
    var location = locationIterator.next();
    
    // Skip location if set to exclude in the config
    if(config.EXCLUDE_LOCATIONS !== "" && config.EXCLUDE_LOCATIONS.indexOf(location.getId()) >= 0){
      continue;
    } 

    var locationConversions = location.getStatsFor(config.DATE_RANGE).getConversions();
    var locationCost = location.getStatsFor(config.DATE_RANGE).getCost();
    var locationClicks = location.getStatsFor(config.DATE_RANGE).getClicks();
    var locationCpa = locationCost / locationConversions;
    var campaignCpa = location.getCampaign().getStatsFor(config.DATE_RANGE).getCost() / location.getCampaign().getStatsFor(config.DATE_RANGE).getConversions();
    var newLocationBid = campaignCpa / locationCpa;
    
    // Only change locations that have the required conversions, cost or clicks
    if(config.MINIMUM_CONVERIONS != "" || config.MINIMUM_COST != "" || config.MINIMUM_CLICKS != ""){

      if(locationConversions < config.MINIMUM_CONVERIONS && locationCost < config.MINIMUM_COST && locationClicks < config.MINIMUM_CLICKS) continue;

    } // check minimums     

    // If there is an location CPA, we will place a bidadjustment
    if(isNaN(newLocationBid) === false && isFinite(locationCpa) === true && location.getBidModifier() !== newLocationBid) {
      if(newLocationBid < config.MIN_BID) { newLocationBid = config.MIN_BID; }
      if(newLocationBid > config.MAX_BID) { newLocationBid = config.MAX_BID; }
      
      	if(config.LOG === true) {
          Logger.log("Campaign: " + location.getCampaign().getName());
          Logger.log("Location: " + location.getName()); 
          Logger.log("Location CPA: " + locationCpa);
          Logger.log("New location bid: " + newLocationBid);
          Logger.log(" ");
        }  
      
      location.setBidModifier(newLocationBid);    
         
    }    

  } // location iterator      
  
} // function main()

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, Teamleader PPC
Martijn Kraan
Freelance PPC Specialist
Brightstep
Martijn Kraan, Freelance PPC Specialist
Tibbe van Asten
PPC Specialist
Founder Adsscripts
Tibbe van Asten, Senior PPC Automation Specialist