Ofertas las 24 horas del día, los 7 días de la semana: ¡Pasar a los dispositivos móviles con un 100% más de compras!

El ex Googler Daniel Gilbert tiene una secuencia de comandos mejorada que le permite ajustar sus ofertas de AdWords (computadoras de escritorio y dispositivos móviles) cada hora de todos los días.

Capture2

El comportamiento del cliente cambia en diferentes momentos del día. La programación de anuncios de AdWords, con solo seis ventanas de oferta únicas por día, no se acerca a la granularidad que necesitamos para que nuestras cuentas de AdWords brillen. La mayoría de las herramientas de ofertas de terceros solo permiten dos o tres cambios de oferta al día.

En respuesta a esto, compartí un script de AdWords creado por el equipo de Brainlabs (mi empleador) hace unos meses, lo que le permite optimizar las ofertas para cada hora del día.

Basado en comentarios de El Blog informatico lectores, hemos reforzado nuestro script de AdWords, que ahora puede utilizar para Google Shopping o campañas habituales. También le permite cambiar los ajustes de la oferta para dispositivos móviles cada hora; actualmente, no hay otra forma de hacerlo. Puede encontrar el script a continuación: todo lo que necesita hacer es cópielo y péguelo en su cuenta de AdWords y lea las instrucciones para configurarlo según sus necesidades.

La secuencia de comandos funciona buscando el modificador de ofertas para cada hora en una hoja de Google. Haz un duplicado de nuestra hoja de cálculo de ejemplo y establezca todos los multiplicadores de ofertas en los valores que necesite. La primera hoja de la hoja de cálculo corresponderá a su programación de anuncios (aplicada a todo el tráfico) y su segunda hoja corresponderá a sus ajustes de la oferta para dispositivos móviles.

Tenga en cuenta que, a diferencia de la versión anterior de la secuencia de comandos, el ajuste de la oferta que ingresa en la hoja de cálculo es el mismo que ingresaría en AdWords: 0% significa que las ofertas no cambiarán, por lo que una oferta de $ 1 permanecería $ 1; -10% significa que las ofertas se reducirán en un 10%, por lo que una oferta de $ 1,00 sería efectivamente $ 0,90. Ahora también puede utilizar la secuencia de comandos para desactivar la publicidad en determinados momentos: simplemente reduzca el ajuste de la oferta como -100%. (En realidad, no puede tener un modificador de -100% en una programación de anuncios, por lo que si hay un -100% en la hoja de programación de anuncios, el script simplemente no creará una programación para ese intervalo de tiempo).

Recuerde también que las ofertas para dispositivos móviles se verán afectadas tanto por la hoja de programación de anuncios y la hoja para dispositivos móviles: si tiene una oferta de $ 1, el ajuste de la programación de anuncios es -10% y el ajuste de la oferta para dispositivos móviles es -10%, entonces la oferta efectiva para dispositivos móviles sería $ 0.81 (ya que los ajustes se multiplican para dar un -19% ). Para ayudarlo a realizar un seguimiento de esto, hay una tabla adicional en la hoja móvil para el cambio compuesto. No tiene que hacer nada en esta tabla: se completará con fórmulas.

Una vez que haya copiado el script en su cuenta, tendrá que configurar las siguientes opciones:

  • Introduzca la URL de la hoja de Google que utilizó anteriormente para spreadsheetUrl, reemplazando el valor que existe actualmente.
  • Selecciona el ShoppingCampaigns variable a cierto si desea que su secuencia de comandos afecte solo a las campañas de Shopping. Conjunto ShoppingCampaigns a falso si desea que su secuencia de comandos afecte solo a las campañas regulares.
  • Selecciona el runMobileBids variable a cierto si desea que su secuencia de comandos afecte los ajustes de la oferta para dispositivos móviles de sus campañas. Conjunto runMobileBids a falso si desea que su secuencia de comandos deje en paz los ajustes de la oferta para dispositivos móviles.
  • Entrar en la matriz excludeCampaignNameContains una lista de frases contenidas en los nombres de las campañas que le gustaría excluir. Estos deben estar entre comillas y separados por comas: por ejemplo [“Brand”,”Competitor Names”] para excluir todas las campañas con nombres que contengan «marcas» o «nombres de competidores». Dejar en blanco [], para no excluir ninguna campaña.
  • Entrar en la matriz includeCampaignNameContains una lista de frases contenidas en los nombres de las campañas que le gustaría incluir. Me gusta excludeCampaignNameContains estos deben estar entre comillas y separados por comas: por ejemplo [“Brand”,”Competitor Names”] para incluir solo campañas con nombres que contengan «marcas» o «nombres de competidores». Dejar en blanco [], para incluir todas las campañas.

Hemos establecido el valor predeterminado de ShoppingCampaigns a falso, por lo tanto, si desea ejecutar esta secuencia de comandos en campañas de Shopping en lugar de campañas normales, asegúrese de cambiar esta variable. Si desea que la secuencia de comandos funcione en ambos tipos de campañas, simplemente duplique la secuencia de comandos y ejecute dos instancias en su cuenta.

Una vez que se hayan configurado los ajustes, estará listo para configurar un programa para el script: configúrelo para que se ejecute cada hora.

Cuando ya no desee utilizar este script, simplemente configure el última carrera variable a cierto y ejecute el script una vez. Esto eliminará todas las programaciones de anuncios y establecerá todos los ajustes de la oferta para dispositivos móviles de la campaña en 0%. También recuerde detener el programa del script, para que no continúe ejecutándose cada hora.

Hay algunas cosas a tener en cuenta:

  • Importante: Para todas las campañas afectadas, este script eliminará todas las programaciones de anuncios existentes.
  • Si utiliza la secuencia de comandos con ajustes de la oferta para dispositivos móviles, sobrescribirá los ajustes de la oferta a nivel de campaña existentes en las campañas afectadas. Sin embargo, no afectará los ajustes de la oferta para dispositivos móviles a nivel del grupo de anuncios; deberá eliminarlos usted mismo. (De lo contrario, anularán los ajustes a nivel de campaña).
  • La secuencia de comandos utiliza la zona horaria de su cuenta de AdWords para decidir qué hora es.
  • Recuerde, existen límites para los ajustes de la oferta: la programación de anuncios no puede superar el + 900% y los ajustes de la oferta para dispositivos móviles no pueden superar el 300%. Si bien puede usar -100% para representar que sus campañas están desactivadas (o excluidas de los dispositivos móviles), no puede usar ajustes entre -100% y -90%.
  • Si hay un ajuste de oferta ilegal (p. Ej., Fuera de los límites o sin un número), el script establecerá un ajuste predeterminado del 0% en su lugar. Esto se mostrará en el registro del script.
  • Si hay una celda en blanco, la secuencia de comandos asumirá que eso significa que el ajuste debe ser -100%.
  • El tiempo de este guión es más preciso que el de la versión anterior. Un script programado podría ejecutarse en cualquier momento de la hora; en la secuencia de comandos anterior, la oferta que desea para las 2:00 p. m. se puede aplicar en cualquier momento entre las 2:00 p. m. y las 3:00 p. m. La programación de anuncios de Google le permite cambiar los ajustes exactamente a la hora, pero tiene un número limitado de ventanas, por lo que el nuevo script mantiene un conjunto continuo de ventanas de ajuste (el ajuste de esta hora y los ajustes de las próximas horas). Cada hora, la secuencia de comandos eliminará el ajuste de la oferta de la última hora y, con la ventana que se libera, creará un ajuste para el futuro.
  • Esto significa que si deja de ejecutar el script, los horarios evitarán que sus anuncios se muestren la mayor parte del tiempo. usted necesitar para ejecutar el script una última vez con última carrera establecido en verdadero o cambiar manualmente las programaciones de anuncios.
  • Sin embargo, lo anterior solo se aplica a las programaciones de anuncios, no a los ajustes de la oferta para dispositivos móviles; solo se pueden cambiar cuando se ejecuta la secuencia de comandos. Por lo tanto, tenga en cuenta que es posible que los ajustes de la oferta para dispositivos móviles no cambien exactamente en el momento adecuado. Si algún desarrollador inteligente de AdWords tiene ideas para solucionar este problema, se ha ganado un trabajo en Brainlabs. Por el momento, solo ejecutamos el script varias veces hasta que se le asigne un tiempo de ejecución cercano a la marca de la hora; una vez que lo hace, tiende a mantener el mismo intervalo de tiempo.
/*
*
* Advanced ad scheduling
*
* This script will apply ad schedules to campaigns or shopping campaigns and set the
* ad schedule bid modifier and mobile bid modifier at each hour according to
* multiplier timetables in a Google sheet.
*
* Version: 2.0
* brainlabsdigital.com
*
*/

function main() {
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
 //Options
 
 //The Google sheet to use
 //The default value is the example sheet linked to in the article
 var spreadsheetUrl = "https://docs.google.com/a/brainlabsdigital.com/spreadsheets/d/1JDGBPs2qyGdHd94BRZw9lE9JFtoTaB2AmlL7xcmLx2g/edit#gid=0";
 
 //Shopping or regular campaigns
 //Use true if you want to run script on shopping campaigns (not regular campaigns).
 //Use false for regular campaigns.
 var shoppingCampaigns = false;
 
 //Use true if you want to set mobile bid adjustments as well as ad schedules.
 //Use false to just set ad schedules.
 var runMobileBids = true;
 
 //Optional parameters for filtering campaign names. The matching is case insensitive.
 //Select which campaigns to exclude e.g ["foo", "bar"] will ignore all campaigns
 //whose name contains 'foo' or 'bar'. Leave blank [] to not exclude any campaigns.
 var excludeCampaignNameContains = [];
 
 //Select which campaigns to include e.g ["foo", "bar"] will include only campaigns
 //whose name contains 'foo' or 'bar'. Leave blank [] to include all campaigns.
 var includeCampaignNameContains = [];
 
 //When you want to stop running the ad scheduling for good, set the lastRun
 //variable to true to remove all ad schedules and mobile bid modifiers.
 var lastRun = false;
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
 
 //Initialise for use later.
 var weekDays = ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", "SUNDAY"];
 var adScheduleCodes = [];
 var campaignIds = [];
 
 //Retrieving up hourly data
 var scheduleRange = "B2:H25";
 var accountName = AdWordsApp.currentAccount().getName();
 var spreadsheet = SpreadsheetApp.openByUrl(spreadsheetUrl);
 var sheets = spreadsheet.getSheets();
 
 var timeZone = AdWordsApp.currentAccount().getTimeZone();
 var date = new Date();
 var dayOfWeek = parseInt(Utilities.formatDate(date, timeZone, "uu"), 10) - 1;
 var hour = parseInt(Utilities.formatDate(date, timeZone, "HH"), 10);
 
 var sheet = sheets[0];
 var data = sheet.getRange(scheduleRange).getValues();
 
 //This hour's bid multiplier.
 var thisHourMultiplier = data[hour][dayOfWeek];
 var lastHourCell = "I2";
 sheet.getRange(lastHourCell).setValue(thisHourMultiplier);
 
 //The next few hours' multipliers
 var timesAndModifiers = [];
 for (var h=0; h<4; h++) {
 var newHour = (hour + h)%24;
 if (hour + h > 23) {
 var newDay = (dayOfWeek + 1)%7;
 } else {
 var newDay = dayOfWeek;
 }
 var bidModifier = data[newHour][newDay];
 if (isNaN(bidModifier) || (bidModifier < -0.9 && bidModifier > -1) || bidModifier > 9) {
 Logger.log("Bid modifier '" + bidModifier + "' for " + weekDays[newDay] + " " + newHour + " is not valid.");
 timesAndModifiers.push([newHour, weekDays[newDay], 0]);
 } else if (bidModifier != -1 && bidModifier.length != 0) {
 timesAndModifiers.push([newHour, weekDays[newDay], bidModifier]);
 }
 }
 
 if (timesAndModifiers.length === 0){
 // If there are no modifiers then the campaigns should not be running for the next few hours.
 // If we just removed all schedules, then ads would start running (with no modifier)
 // so an arbitrary ad schedule is created (scheduled for yesterday so it does not affect anything).
 timesAndModifiers.push([0,weekDays[(dayOfWeek+6)%7],0.0]);
 }
 
 
 //Pull a list of all relevant campaign IDs in the account.
 var campaignSelector = ConstructIterator(shoppingCampaigns)
 for(var i = 0; i < excludeCampaignNameContains.length; i++){
 campaignSelector = campaignSelector.withCondition('Name DOES_NOT_CONTAIN_IGNORE_CASE "' + excludeCampaignNameContains[i] + '"');
 }
 var campaignIterator = campaignSelector.get();
 while(campaignIterator.hasNext()){
 var campaign = campaignIterator.next();
 var campaignName = campaign.getName();
 var includeCampaign = false;
 if(includeCampaignNameContains.length === 0){
 includeCampaign = true;
 }
 for(var i = 0; i < includeCampaignNameContains.length; i++){
 var index = campaignName.toLowerCase().indexOf(includeCampaignNameContains[i].toLowerCase());
 if(index !== -1){
 includeCampaign = true;
 break;
 }
 }
 if(includeCampaign){
 var campaignId = campaign.getId();
 campaignIds.push(campaignId);
 }
 }
 
 //Return if there are no campaigns.
 if(campaignIds.length === 0){
 Logger.log("There are no campaigns matching your criteria.");
 return;
 }
 
 //Remove all ad scheduling and mobile bid adjustments for the last run.
 if(lastRun){
 checkAndRemoveAdSchedules(campaignIds, []);
 ModifyMobileBidAdjustment(campaignIds, 0);
 return;
 }
 
 // Change the mobile bid adjustment 
 if(runMobileBids){
 if (sheets.length < 2) {
 Logger.log("Mobile ad schedule sheet was not found in the Google spreadsheet.");
 } else {
 var sheet = sheets[1];
 var data = sheet.getRange(scheduleRange).getValues();
 var thisHourMultiplier_Mobile = data[hour][dayOfWeek];
 
 if (thisHourMultiplier_Mobile.length === 0) {
 thisHourMultiplier_Mobile = -1;
 }
 
 if (isNaN(thisHourMultiplier_Mobile) || (thisHourMultiplier_Mobile < -0.9 && thisHourMultiplier_Mobile > -1) || thisHourMultiplier_Mobile > 3) {
 Logger.log("Mobile bid modifier '" + thisHourMultiplier_Mobile + "' for " + weekDays[dayOfWeek] + " " + hour + " is not valid.");
 thisHourMultiplier_Mobile = 0;
 }
 
 if(thisHourMultiplier === ""){
 var totalMultiplier = "";
 }
 else if(thisHourMultiplier == -1 || thisHourMultiplier_Mobile == -1){
 var totalMultiplier = -1;
 }
 else{
 var totalMultiplier = (1+thisHourMultiplier_Mobile)*(1+thisHourMultiplier) -1;
 }
 sheet.getRange("I2").setValue(thisHourMultiplier_Mobile);
 sheet.getRange("T2").setValue(totalMultiplier);
 ModifyMobileBidAdjustment(campaignIds, thisHourMultiplier_Mobile);
 }
 }
 
 // Check the existing ad schedules, removing those no longer necessary
 var existingSchedules = checkAndRemoveAdSchedules(campaignIds, timesAndModifiers);
 
 // Add in the new ad schedules
 AddHourlyAdSchedules(campaignIds, timesAndModifiers, existingSchedules, shoppingCampaigns);
 
}


/**
* Function to add ad schedules for the campaigns with the given IDs, unless the schedules are 
* referenced in the existingSchedules array. The scheduling will be added as a hour long periods
* as specified in the passed parameter array and will be given the specified bid modifier.
*
* @param array campaignIds array of campaign IDs to add ad schedules to
* @param array timesAndModifiers the array of [hour, day, bid modifier] for which to add ad scheduling
* @param array existingSchedules array of strings identifying already existing schedules.
* @param bool shoppingCampaigns using shopping campaigns?
* @return void
*/
function AddHourlyAdSchedules(campaignIds, timesAndModifiers, existingSchedules, shoppingCampaigns){
 // times = [[hour,day],[hour,day]]
 var campaignIterator = ConstructIterator(shoppingCampaigns)
 .withIds(campaignIds)
 .get();
 while(campaignIterator.hasNext()){
 var campaign = campaignIterator.next();
 for(var i = 0; i < timesAndModifiers.length; i++){
 if (existingSchedules.indexOf(
 timesAndModifiers[i][0] + "|" + (timesAndModifiers[i][0]+1) + "|" + timesAndModifiers[i][1]
 + "|" + Utilities.formatString("%.2f",(timesAndModifiers[i][2]+1)) + "|" + campaign.getId())
 > -1) {
 
 continue;
 }
 
 campaign.addAdSchedule({
 dayOfWeek: timesAndModifiers[i][1],
 startHour: timesAndModifiers[i][0],
 startMinute: 0,
 endHour: timesAndModifiers[i][0]+1,
 endMinute: 0,
 bidModifier: 1+timesAndModifiers[i][2]
 });
 }
 }
}


/**
* Function to remove ad schedules from all campaigns referenced in the passed array
* which do not correspond to schedules specified in the passed timesAndModifiers array.
*
* @param array campaignIds array of campaign IDs to remove ad scheduling from
* @param array timesAndModifiers array of [hour, day, bid modifier] of the wanted schedules
* @return array existingWantedSchedules array of strings identifying the existing undeleted schedules
*/
function checkAndRemoveAdSchedules(campaignIds, timesAndModifiers) {
 
 var adScheduleIds = [];
 
 var report = AdWordsApp.report(
 'SELECT CampaignId, Id ' + 
 'FROM CAMPAIGN_AD_SCHEDULE_TARGET_REPORT ' +
 'WHERE CampaignId IN ["' + campaignIds.join('","') + '"]'
 );
 
 var rows = report.rows();
 while(rows.hasNext()){
 var row = rows.next();
 var adScheduleId = row['Id'];
 var campaignId = row['CampaignId'];
 adScheduleIds.push([campaignId,adScheduleId]);
 }
 
 var chunkedArray = [];
 var chunkSize = 10000;
 
 for(var i = 0; i < adScheduleIds.length; i += chunkSize){
 chunkedArray.push(adScheduleIds.slice(i, i + chunkSize));
 }
 
 var wantedSchedules = [];
 var existingWantedSchedules = [];
 
 for (var j=0; j<timesAndModifiers.length; j++) {
 wantedSchedules.push(timesAndModifiers[j][0] + "|" + (timesAndModifiers[j][0]+1) + "|" + timesAndModifiers[j][1] + "|" + Utilities.formatString("%.2f",timesAndModifiers[j][2]+1));
 }
 
 for(var i = 0; i < chunkedArray.length; i++){
 var unwantedSchedules = [];
 
 var adScheduleIterator = AdWordsApp.targeting()
 .adSchedules()
 .withIds(chunkedArray[i])
 .get();
 while (adScheduleIterator.hasNext()) {
 var adSchedule = adScheduleIterator.next();
 var key = adSchedule.getStartHour() + "|" + adSchedule.getEndHour() + "|" + adSchedule.getDayOfWeek() + "|" + Utilities.formatString("%.2f",adSchedule.getBidModifier());
 
 if (wantedSchedules.indexOf(key) > -1) {
 existingWantedSchedules.push(key + "|" + adSchedule.getCampaign().getId());
 } else {
 unwantedSchedules.push(adSchedule);
 }
 }
 
 for(var j = 0; j < unwantedSchedules.length; j++){
 unwantedSchedules[j].remove();
 }
 }
 
 return existingWantedSchedules;
}


/**
* Function to construct an iterator for shopping campaigns or regular campaigns.
*
* @param bool shoppingCampaigns Using shopping campaigns?
* @return AdWords iterator Returns the corresponding AdWords iterator
*/
function ConstructIterator(shoppingCampaigns){
 if(shoppingCampaigns === true){
 return AdWordsApp.shoppingCampaigns();
 }
 else{
 return AdWordsApp.campaigns();
 }
}


/**
* Function to set a mobile bid modifier for a set of campaigns
*
* @param array campaignIds An array of the campaign IDs to be affected
* @param Float bidModifier The multiplicative mobile bid modifier
* @return void
*/
function ModifyMobileBidAdjustment(campaignIds, bidModifier){
 
 var platformIds = [];
 
 for(var i = 0; i < campaignIds.length; i++){
 platformIds.push([campaignIds[i],30001]);
 }
 
 var platformIterator = AdWordsApp.targeting()
 .platforms()
 .withIds(platformIds)
 .get();
 while (platformIterator.hasNext()) {
 var platform = platformIterator.next();
 platform.setBidModifier(1+bidModifier);
 }
}

Las opiniones expresadas en este artículo pertenecen al autor invitado y no necesariamente a El Blog informatico. Los autores del personal se enumeran aquí.


Deja un comentario