Bodaanpassingen voor locaties

Pas bodaanpassingen toe op de toegevoegde locaties in alle campagnes op basis van de CPA of ROAS.

Start nu!
Bodaanpassingen Get started!

Door het toevoegen van zoveel mogelijk locaties in je campagne, krijg je meer inzicht in de prestaties in het targetgebied. Op die manier kan je bodaanpassingen doen om de kosten per conversie te drukken op locaties die te duur zijn.

We hebben ook scripts voor bodaanpassingen op doelgroepen, apparaten en voor elk uur van de dag. Start gelijk met het automatiseren van alle bodaanpassingen in jouw accounts!

Bodaanpassingen op CPA of ROAS

Met de laatste aanpassingen in dit script is het mogelijk om de bodaanpassingen te berekenen op basis van CPA of ROAS. De CPA of ROAS van een locatie wordt vergeleken met de CPA of ROAS van de bijbehorende campagne. 

Instellingen

In het script kan je slechts de volgende zaken aanpassen:

  • LOG: Geef aan of het script de tussenstappen moet rapporteren, door de waarde aan te passen naar 'true'.
  • DATE_RANGE: Het script kijkt naar de statistieken over deze periode.
  • MINIMUM_CONVERSIONS: Minimaal aantal conversies. Wanneer een locatie minder conversies heeft, wordt er geen bodaanpassing gedaan.
  • MINIMUM_CONVERSIONVALUE: Minimale conversiewaarde. Wanneer een locatie minder conversiewaarde heeft, wordt er geen bodaanpassing gedaan.
  • MINIMUM_COST: Minimale kosten voor een locatie. Wanneer een locatie minder uitgaven heeft, wordt er geen bodaanpassing gedaan.
  • MINIMUM_CLICKS: Minimaal aantal klikken. Wanneer een locatie minder klikken heeft, wordt er geen bodaanpassing gedaan.
  • KPI: Kies om de bodaanpassing te berekenen op basis van 'CPA' of 'ROAS'
  • CAMPAIGN_LABEL: Gebruik een label om campagnes te selecteren
  • MAX_BID: De bodaanpassing zal niet hoger zijn dan dit ingestelde bod. 1.3 = +30% of 2 = +100%
  • MIN_BID: De bodaanpassing zal niet lager zijn dan dit ingestelde bod. 0.75 = -25% of 0.5 = -50%.

Frequentie: Om voldoende data te genereren adviseren we om het script eenmaal per dag of eenmaal per week te draaien.

The script
// Copyright 2021. Increase BV. All Rights Reserved.
//
// Created By: Tibbe van Asten
// for Increase B.V.
// 
// Created: 20-07-2018
// Last update: 23-08-2021 - Arjan Schoorl fixed the campaignIterator
//
// ABOUT THE SCRIPT
// With this script we adjust the biddings for locations in 
// active campaigns.
//
////////////////////////////////////////////////////////////////////

var config = {

  LOG : true,
  DATE_RANGE : "LAST_30_DAYS",

  // Optional: Use minimum conversions and/or cost to select targetlocations
  // Leave empty to skip
  MINIMUM_CONVERSIONS : "",
  MINIMUM_CONVERSIONVALUE : "",
  MINIMUM_COST : "",
  MINIMUM_CLICKS : "",
  
  // Set bidadjustments based on CPA or ROAS
  KPI : "ROAS",
  
  // Optional: Use a campaignlabel to make a selection.
  // Leave empty to skip
  CAMPAIGN_LABEL : "",
  
  // 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.2,
  MIN_BID : 0.8
  
}


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

function main() {
  
  if(config.KPI != "CPA" && config.KPI != "ROAS"){
    throw Error("Set KPI to 'CPA' or 'ROAS' only!");
  }
  
  var map = {};
  
  // Collecting all targetlocation data
  var report = AdsApp.report(
    "SELECT Id, CampaignName, CampaignId, BidModifier, Conversions, ConversionValue, Cost, Clicks " +
    "FROM CAMPAIGN_LOCATION_TARGET_REPORT " +
    "WHERE IsNegative = FALSE " +
    "AND CampaignStatus = ENABLED " +
    " DURING " + config.DATE_RANGE
  );

  var rows = report.rows();
  while(rows.hasNext()){
    var row = rows.next();
    
    // Check thresholds
    if(config.MINIMUM_CONVERSIONS != "" || config.MINIMUM_CONVERSIONVALUE != "" ||config.MINIMUM_COST != "" || config.MINIMUM_CLICKS != ""){
      
      if(row["Conversions"] < config.MINIMUM_CONVERSIONS || row["ConversionValue"] < config.MINIMUM_CONVERSIONVALUE || row["Cost"] < config.MINIMUM_COST || row["Clicks"] < config.MINIMUM_CLICKS) continue;
      
    }
    
    // Skip campaign when not set to manual bidding. And check label.
    var campaignIterator = AdsApp.campaigns().withIds([row["CampaignId"]]).get();
    while(campaignIterator.hasNext()) { 
      var campaign = campaignIterator.next();       
      
      if(campaign.bidding().getStrategyType() != "MANUAL_CPC" && campaign.bidding().getStrategyType() != "MANUAL_CPM" && campaign.bidding().getStrategyType() != "MANUAL_CPV") continue;
      if(config.CAMPAIGN_LABEL != ""){ while(!campaign.labels().withCondition("Name = '" + config.CAMPAIGN_LABEL + "'").get().hasNext()) continue; }
      
      var campaignKpi = parseFloat(getCampaignKpi(campaign.getId())).toFixed(2);
      var oldBid = parseFloat(1 + (row["BidModifier"].split("%")[0] / 100)).toFixed(2);
    }
    
    // Calculate KPI's and new bid
    if(config.KPI == "CPA"){ var locationKpi = parseFloat(row["Cost"] / row["Conversions"]).toFixed(2); var newBid = parseFloat(campaignKpi / locationKpi).toFixed(2); }
    if(config.KPI == "ROAS"){ var locationKpi = parseFloat(row["ConversionValue"] / row["Cost"]).toFixed(2); var newBid = parseFloat(locationKpi / campaignKpi).toFixed(2); }
    
    // If there is a CPA or ROAS, we will set a bidadjustment
    if(isNaN(newBid) === false && isFinite(locationKpi) === true) {
      if(newBid < config.MIN_BID) { newBid = parseFloat(config.MIN_BID).toFixed(2); }
      if(newBid > config.MAX_BID) { newBid = parseFloat(config.MAX_BID).toFixed(2); }  
      
      // Add to map
      if(newBid != oldBid) {
        if(map[row["Id"] + "," + row["CampaignId"]] == null) {
          map[row["Id"] + "," + row["CampaignId"]] = [];
        }
        map[row["Id"] + "," + row["CampaignId"]].push([row["Id"], row["CampaignName"], newBid]);
      
          if(config.LOG === true){
            Logger.log("Location " + row["Id"] + " in " + row["CampaignName"]);
            Logger.log("Current bidadjustment: " + row["BidModifier"] + " = " + oldBid);
            Logger.log("Location " + config.KPI + ": " + locationKpi + ", Campain " + config.KPI + ": " + campaignKpi + ", New bid: " + newBid);
            Logger.log("------------");
          }   
      }

    } // Check bid
    
  } // rowIterator
  
  if(config.LOG === true){
    Logger.log(" ");
    Logger.log("...Loop through locations");
    Logger.log(" ");
  }
  
  for (var key in map) {
    
    var campaignIterator = AdsApp
      .campaigns()
      .withIds([key.split(",")[1]])
      .get();
    
    while(campaignIterator.hasNext()){
      var campaign = campaignIterator.next();
      
        var ids = [];
        ids.push(key.split(",")[1]);
        ids.push(key.split(",")[0]);
      
      var locationIterator = campaign
        .targeting()
        .targetedLocations()
        .withIds([ids])
        .get();

      while(locationIterator.hasNext()){
        var location = locationIterator.next();
        
        location.setBidModifier(parseFloat(map[key][0][2])); 
        Logger.log("Bidadjustment of " + map[key][0][2] + " set for " + map[key][0][0] + " in " + map[key][0][1]);
        
      } // locationIterator
      
    } // campaignIterator
    
  } // keyIterator
  
} // function main()

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

function getCampaignKpi(campaignId){
  
  var report = AdsApp.report(
    "SELECT Cost, Conversions, ConversionValue " +
    "FROM CAMPAIGN_PERFORMANCE_REPORT " +
    "WHERE CampaignId = '" + campaignId + "' " +
    "DURING " + config.DATE_RANGE
  );
  
  var rows = report.rows();
  while(rows.hasNext()){
    var campaign = rows.next();
    
    if(config.KPI == "CPA"){ var campaignKpi = campaign["Cost"] / campaign["Conversions"]; }
    if(config.KPI == "ROAS"){ var campaignKpi = campaign["ConversionValue"] / campaign["Cost"]; }
    
  } // campaignIterator 
  
  return campaignKpi;
  
} // function getCampaignKpi()
Show whole script!
Loading Comments
The Experts
Tibbe van Asten Team Lead Search
Nils Rooijmans Water Cooler Topics
Martijn Kraan Freelance PPC Specialist
Bas Baudoin Teamlead SEA @ Happy Leads
How about you? JOIN US!
Sharing Knowledge
Caring

Kennis delen

Adsscripts.com staat voor het delen van kennis. In de huidige markt houden SEA-specialisten de kennis en ervaring graag voor zich. Wij zijn er van overtuigd dat het delen van kennis ervoor kan zorgen dat iedereen beter wordt in haar of zijn werk. Daarom lopen wij hier graag in voorop, door onze kennis over scripts te delen met iedereen.

Wil jij ook graag een bijdrage leveren? Wij staan open voor nieuwe ideeën en feedback op alles wat je op Adsscripts.com vindt.

Neem contact op

Training &
Workshop
Neem contact op!
Adsscripts Training & Workshop