Bodaanpassing voor advertentieplanning

Automatisch bodaanpassingen doorvoeren op de blokken in de advertentieplanning per campagne. Op basis van CPA.

Start nu!
Bodaanpassingen voor advertentieplanning
Bodaanpassing Get started!

Wanneer je bodaanpassingen op elk uur van de dag teveel van het goede vindt, biedt dit script de oplossing. Net zoals de scripts voor bodaanpassingen op apparaten, locaties en doelgroepen, worden hiermee automatisch bodaanpassingen ingesteld voor alle blokken in de advertentieplanning van een campagne. Deze advertentieplanning kan je naar wens indelen per campagne.

In het script kan je kiezen om search, display en shopping campagnes op te nemen in de bodaanpassingen. Displaycampagnes kunnen alleen meegenomen worden wanneer search campagnes ook ingeschakeld zijn. Filter blokken in de advertentieplaning per campagnes door een minimaal aantal conversies en/of minimale uitgaven te specificeren in het script. Je bepaalt zelf wat de maximale en minimale bodaanpassing is. Daarnaast kijkt het script alleen naar campagnes met een handmatige biedstrategie, omdat bodaanpassingen bij Smart Bidding al automatisch gebeuren.

Instellingen

  • LOG: Geef aan of het script de tussenstappen moet rapporteren, door de waarde aan te passen naar 'true'.
  • DATE_RANGE: Geef aan hoeveel dagen het script terug moet kijken om de CPA te berekenen.
  • INCLUDE_SEARCH: Geef aan of je het script op je searchcampagnes wil draaien. 
  • INCLUDE_DISPLAY: Geef aan of je het script op je displaycampagnes wil draaien. INCLUDE_SEARCH moet op true staan.
  • INCLUDE_SHOPPING: Geef aan of je het script op je shoppingcampagnes wil draaien.
  • MINIMUM_CONVERSIONS: Optioneel, selecteer alleen blokken in de advertentieplanning die minimaal dit aantal conversies hebben behaald.
  • MINIMUM_COST: Optioneel, selecteer alleenblokken in de advertentieplanning die minimaal deze kosten hebben gemaakt.
  • MINIMUM_CLICKS: Optioneel, alleenblokken in de advertentieplanning selecteren met dit aantal klikken.
  • 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%.
  • LABEL: Wil je dit script niet toepassen op alle campagnes? Label dan de campagnes.
The script
// Copyright 2020. Increase BV. All Rights Reserved.
//
// Created By: Tibbe van Asten
// for Increase B.V.
// 
// Created: 19-03-2020
// Last update: 19-03-2020
//
// ABOUT THE SCRIPT
// With this script we adjust the biddings for blocks in your adschedule 
// for all active campaigns in the account. Change will be based
// on the device statistics vs campaign statistics.
//
////////////////////////////////////////////////////////////////////

var config = {
  
    LOG : true,
    DATE_RANGE : last_n_days(60),

    // Set these to true if you want to include them.
    INCLUDE_SEARCH : true,		
    INCLUDE_DISPLAY : false,
    INCLUDE_SHOPPING : true,	
  
    // 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.1,
    MIN_BID : 0.8,
	
    // Optional: Use a label to make a selection of campaigns.
    // Leave empty to skip.
    LABEL : ""

}

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

function main() {  

  // Starting with selecting Search campaigns, if included in the config.
  if(config.INCLUDE_SEARCH === true) {
    if(config.LABEL != ""){
      if(config.INCLUDE_DISPLAY === true) {      
        var campaignIterator = AdsApp
        .campaigns()
        .withCondition("Status = ENABLED")
        .withCondition("LabelNames CONTAINS_ANY ['" + config.LABEL + "']")
        .get();
      } else {
        var campaignIterator = AdsApp
        .campaigns()
        .withCondition("Status = ENABLED")
        .withCondition("LabelNames CONTAINS_ANY ['" + config.LABEL + "']")
        .withCondition("AdvertisingChannelType != DISPLAY") 
        .get();        
      }
    } else{
      if(config.INCLUDE_DISPLAY === true) {  
        var campaignIterator = AdsApp
        .campaigns()
        .withCondition("Status = ENABLED")
        .get();
      } else {
        var campaignIterator = AdsApp
        .campaigns()
        .withCondition("Status = ENABLED")
        .withCondition("AdvertisingChannelType != DISPLAY") 
        .get();
      }
    }

    // With campaigns selected, the bidadjustments will be set.
    bidAdjustments(campaignIterator);
  }

  // Select Shopping campaigns, if included in the config.
  if(config.INCLUDE_SHOPPING === true) {
    if(config.LABEL != ""){
      var campaignIterator = AdsApp
      .shoppingCampaigns()
      .withCondition("Status = ENABLED")
      .withCondition("LabelNames CONTAINS_ANY ['" + config.LABEL + "']")
      .get();
    } else{
      var campaignIterator = AdsApp
      .shoppingCampaigns()
      .withCondition("Status = ENABLED")
      .get();
    }

    // With campaigns selected, the bidadjustments will be set.
    bidAdjustments(campaignIterator);
  }    
  
  Logger.log("Thanks for using this custom script by Tibbe van Asten. Winning!")
  
} // function main()

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

function bidAdjustments(iterator) {
  
  var from = config.DATE_RANGE[0];
  var to = config.DATE_RANGE[1];
  
  while(iterator.hasNext()){
    var campaign = iterator.next();
    
    // We only want to alter the campaigns and adgroups with manual bidding strategies.
    if(campaign.bidding().getStrategyType() == "MANUAL_CPC" || campaign.bidding().getStrategyType() == "MANUAL_CPM" || campaign.bidding().getStrategyType() == "MANUAL_CPV"){
      
      var campaignCpa = campaign.getStatsFor(from, to).getCost() / campaign.getStatsFor(from, to).getConversions();

      	if(config.LOG === true){
          Logger.log("Checking " + campaign.getName());
          Logger.log("-----");
        }
      
      // Within the campaign, we will check for devices.
      var scheduleIterator = campaign
        .targeting()
        .adSchedules()
        .get();
      
      while(scheduleIterator.hasNext()){
        var schedule = scheduleIterator.next();
        
        var scheduleConversions = schedule.getStatsFor(from, to).getConversions();
        var scheduleCost = schedule.getStatsFor(from, to).getCost();
        var scheduleClicks = schedule.getStatsFor(from, to).getClicks();
        
          if(config.LOG === true){
            Logger.log("Schedule: " + schedule.getDayOfWeek() + " " + schedule.getStartHour() + "-" + schedule.getEndHour());
            Logger.log("Conversions: " + scheduleConversions);
            Logger.log("Cost: " + scheduleCost);
            Logger.log("Clicks: " + scheduleClicks);
          }
        
        // Only change devices that have the required conversions, cost or clicks
        if(config.MINIMUM_CONVERIONS != "" || config.MINIMUM_COST != "" || config.MINIMUM_CLICKS != ""){
          
          if(scheduleConversions < config.MINIMUM_CONVERIONS && scheduleCost < config.MINIMUM_COST && scheduleClicks < config.MINIMUM_CLICKS) continue;
          
        } // check minimums        
        
        var scheduleCpa = scheduleCost / scheduleConversions;
        var newScheduleBid = campaignCpa / scheduleCpa;

        // If there is an audience CPA, we will place a bidadjustment.
        if(isNaN(newScheduleBid) === false && isFinite(scheduleCpa) === true && schedule.getBidModifier() !== newScheduleBid) {
          if(newScheduleBid < config.MIN_BID) { newScheduleBid = config.MIN_BID; }
          if(newScheduleBid > config.MAX_BID) { newScheduleBid = config.MAX_BID; }

          schedule.setBidModifier(newScheduleBid);  

          if(config.LOG === true){
            Logger.log("Bidadjustment " + schedule.getDayOfWeek() + " " + schedule.getStartHour() + "-" + schedule.getEndHour() + " changed to " + schedule.getBidModifier());
          }
        }        

        // Negative bidadjustment when conversions = 0.
        if(scheduleConversions == 0 && scheduleCost > config.MINIMUM_COST && isNaN(newScheduleBid) == false){
          schedule.setBidModifier(config.MIN_BID);

          if(config.LOG === true){
            Logger.log("Bidadjustment " + schedule.getDayOfWeek() + " " + schedule.getStartHour() + "-" + schedule.getEndHour() + " changed to " + schedule.getBidModifier());
          }
        }
        
        if(config.LOG === true){
          Logger.log(" ");
        }

      } // scheduleIterator   
      
      if(config.LOG === true){
        Logger.log(" ");
      }
            
    } // manual bidding
    
  } // campaignIterator
  
} // function bidAdjustments()

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

function last_n_days(n) {
  
	var	from = new Date(), to = new Date();
	to.setUTCDate(from.getUTCDate() - n);
  
	return googleDateRange(from, to);
  
} // function last_n_days()

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

function googleDateRange(from, to) {
  
	function googleFormat(date) {
    
		var date_array = [date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate()];
    
		if (date_array[1] < 10) date_array[1] = '0' + date_array[1];
		if (date_array[2] < 10) date_array[2] = '0' + date_array[2];
    
		return date_array.join('');
	}
  
	var inverse = (from > to);
	from = googleFormat(from);
	to = googleFormat(to);
  
	var result = [from, to];
	
  if (inverse) {
		result = [to, from];
	}
  
	return result;
  
} // function googleDateRange()
Show whole script!
The Experts
Tibbe van Asten Head of PPC @ Increase
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