Цей скріпт дозволить вам робити більш гнучкі ставки – буквально в будь-яку хвилину будь-якого дня на будь-якому пристрої.
Як використовувати скріпт (сценарій)
Коефіцієнти ставок працюють з електронної таблиці Google, і URL-адресу потрібно вставити в код як електронну таблицю. Скопіюйте шаблон-коду та встановіть в ньому свої ставки. Документ повинен виглядати приблизно так:
- У клітинках B2-H25 введіть множники ставок: 0% множник ставок не змінює жодних ставок, а X%/-X% – корегує ставки
- Якщо ви також хочете використовувати мобільні корекції, їх варто розмістити на другому аркуші цієї ж електронної таблиці.
- Потрібно встановити для змінної shoppingCampaigns значення true, якщо ви хочете використовувати її в торгових кампаніях, або значення false для використання в пошукових або медійних кампаніях.
- Встановіть для runMobileBids значення true, якщо ви хочете змінювати коригування ставок для мобільних пристроїв щогодини, або встановіть значення false, якщо ви хочете змінити лише розклад показу оголошень.
- Якщо ви хочете використовувати ці множники лише в деяких кампаніях, використовуйте excludeCampaignNameContains і includeCampaignNameContains, щоб сказати, що повинно, а що не повинно бути у назвах кампаній.
- Потім вам потрібно встановити розклад, щоб сценарій працював щогодини. Сценарій не встановлює всі розклади заздалегідь, тому що Google Ads не допускає достатньої кількості ставок – натомість він постійно оновлюватиме графіки показу оголошень, тому наступні кілька годин завжди заповнюються.
Код скріпта для корекції ставок в Google Ads
function main() { // The Google sheet to use var spreadsheetUrl = 'https://docs.google.com/spreadsheets/d/1Om0jiszc8Uuuv_DhFkH1KV23glqssGB6Xqziofxcc-0/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 = false; // 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. 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(); if (timeZone === 'Etc/GMT') { timeZone = 'GMT'; } 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 = []; var otherDays = weekDays.slice(0); for (var h = 0; h < 5; h++) { var newHour = (hour + h) % 24; if (hour + h > 23) { var newDay = (dayOfWeek + 1) % 7; } else { var newDay = dayOfWeek; } otherDays[newDay] = '-'; if (h < 4) { // Use the specified bids for the next 4 hours 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, newHour + 1, weekDays[newDay], 0]); } else if (bidModifier != -1 && bidModifier.length != 0) { timesAndModifiers.push([newHour, newHour + 1, weekDays[newDay], bidModifier]); } } else { // Fill in the rest of the day with no adjustment (as a back-up incase the script breaks) timesAndModifiers.push([newHour, 24, weekDays[newDay], 0]); } } if (hour > 0) { timesAndModifiers.push([0, hour, weekDays[dayOfWeek], 0]); } for (var d = 0; d < otherDays.length; d++) { if (otherDays[d] != '-') { timesAndModifiers.push([0, 24, otherDays[d], 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] + '"'); } campaignSelector = campaignSelector.withCondition('Status IN [ENABLED,PAUSED]'); 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 for the last run. if (lastRun) { checkAndRemoveAdSchedules(campaignIds, [], shoppingCampaigns); 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; } 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, shoppingCampaigns); // Add in the new ad schedules AddHourlyAdSchedules(campaignIds, timesAndModifiers, existingSchedules, shoppingCampaigns); } 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][1]) + '|' + timesAndModifiers[i][2] + '|' + Utilities.formatString('%.2f', (timesAndModifiers[i][3] + 1)) + '|' + campaign.getId() ) > -1) { continue; } campaign.addAdSchedule({ dayOfWeek: timesAndModifiers[i][2], startHour: timesAndModifiers[i][0], startMinute: 0, endHour: timesAndModifiers[i][1], endMinute: 0, bidModifier: Math.round(100 * (1 + timesAndModifiers[i][3])) / 100 }); } } } function checkAndRemoveAdSchedules(campaignIds, timesAndModifiers, shoppingCampaigns) { 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; if (adScheduleId == '--') { continue; } 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][1]) + '|' + timesAndModifiers[j][2] + '|' + Utilities.formatString('%.2f', timesAndModifiers[j][3] + 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) { if (shoppingCampaigns) { var campaign = adSchedule.getShoppingCampaign(); } else { var campaign = adSchedule.getCampaign(); } existingWantedSchedules.push(key + "|" + campaign.getId()); } else { unwantedSchedules.push(adSchedule); } } for (var j = 0; j < unwantedSchedules.length; j++) { unwantedSchedules[j].remove(); } } return existingWantedSchedules; } function ConstructIterator(shoppingCampaigns) { if (shoppingCampaigns === true) { return AdWordsApp.shoppingCampaigns(); } return AdWordsApp.campaigns(); } function ModifyMobileBidAdjustment(campaignIds, bidModifier) { var platformIds = []; var newBidModifier = Math.round(100 * (1 + bidModifier)) / 100; 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(newBidModifier); } }