Google Ads를 사용하면 각 캠페인의 일일 예산 금액을 설정할 수 있습니다. 하지만 일부 마케팅 이니셔티브에는 고정 비용이 연결됩니다. 예를 들어 '가을 할인 전까지 5,000달러를 지출하고 싶어'와 같은 경우입니다. 입찰 전략을 사용하면 일일 예산의 지출 방식을 어느 정도 관리할 수 있지만 캠페인 기간 동안 예산이 소진되는 방식은 관리할 수 없습니다.
예를 들어 가을 할인 광고에 5,000달러만 지출하고 10일 동안 광고를 게재하려는 경우 일일 예산을 500달러로 설정하여 전체 예산을 사용할 수 있습니다. 하지만 이 경우 매일 전체 금액을 지출하고 균등하게 지출해야 합니다. 마지막 며칠 동안 예산의 대부분을 지출하고 싶다고 Google Ads에 알릴 수는 없습니다.
이 스크립트는 맞춤 예산 배분 계획을 사용하여 캠페인 예산을 매일 동적으로 조정합니다.
작동 방식
예산 전략 테스트
스크립트에는 여러 날 동안 실행되는 효과를 시뮬레이션하는 테스트 코드가 포함되어 있습니다. 이렇게 하면 스크립트가 일정 기간 동안 매일 실행되도록 예약되었을 때 어떤 일이 일어날지 더 잘 파악할 수 있습니다.
기본적으로 이 스크립트는 10일 동안 지출된 500달러의 균등한 예산 배분을 시뮬레이션합니다.
function main() {
testBudgetStrategy(calculateBudgetEvenly, 10, 500);
// setNewBudget(calculateBudgetEvenly, CAMPAIGN_NAME, TOTAL_BUDGET, START_DATE, END_DATE);
}
setNewBudget
함수 호출은 주석 처리되어 테스트 코드만 실행됨을 나타냅니다. 예제 실행 결과 출력되는 내용은 다음과 같습니다.
Day 1.0 of 10.0, new budget 50.0, cost so far 0.0
Day 2.0 of 10.0, new budget 50.0, cost so far 50.0
Day 3.0 of 10.0, new budget 50.0, cost so far 100.0
Day 4.0 of 10.0, new budget 50.0, cost so far 150.0
Day 5.0 of 10.0, new budget 50.0, cost so far 200.0
Day 6.0 of 10.0, new budget 50.0, cost so far 250.0
Day 7.0 of 10.0, new budget 50.0, cost so far 300.0
Day 8.0 of 10.0, new budget 50.0, cost so far 350.0
Day 9.0 of 10.0, new budget 50.0, cost so far 400.0
Day 10.0 of 10.0, new budget 50.0, cost so far 450.0
Day 11.0 of 10.0, new budget 0.0, cost so far 500.0
스크립트는 매일 새로운 예산을 계산하여 예산 지출이 균등하게 분산되도록 합니다. 할당된 예산 한도에 도달하면 예산이 0으로 설정되어 지출이 중지됩니다.
사용되는 함수를 변경하거나 함수 자체를 수정하여 사용되는 예산 전략을 변경할 수 있습니다. 스크립트에는 calculateBudgetEvenly
및 calculateBudgetWeighted
의 두 가지 사전 빌드 전략이 제공됩니다. 가중 테스트 예산 전략을 설정하려면 다음과 같이 testBudgetStrategy
를 변경합니다.
testBudgetStrategy(calculateBudgetWeighted, 10, 500);
미리보기를 클릭하고 로거 출력을 확인합니다. 이 예산 전략은 기간 초반에 더 적은 예산을 할당하고 마지막 며칠 동안 더 많은 예산을 할당합니다.
이 테스트 방법을 사용하여 예산 계산 함수의 변경사항을 시뮬레이션하고 예산을 분배하는 자체 접근 방식을 시도할 수 있습니다.
예산 할당
calculateBudgetWeighted
예산 전략은 다음 함수를 통해 구현됩니다.
function calculateBudgetWeighted(costSoFar, totalBudget, daysSoFar, totalDays) {
const daysRemaining = totalDays - daysSoFar;
const budgetRemaining = totalBudget - costSoFar;
if (daysRemaining <= 0) {
return budgetRemaining;
} else {
return budgetRemaining / (2 * daysRemaining - 1) ;
}
}
이 함수는 다음 인수를 사용합니다.
costSoFar
START_DATE
부터 오늘까지 캠페인에서 발생한 누적 비용입니다.totalBudget
START_DATE
~END_DATE
에 할당된 지출입니다.daysSoFar
START_DATE
부터 오늘까지 경과된 일수입니다.totalDays
START_DATE
과END_DATE
사이의 총 일수입니다.
이러한 인수를 사용하는 한 자체 함수를 작성할 수 있습니다. 이 값을 사용하면 지금까지 지출한 금액과 전체 지출액을 비교하고 전체 예산의 타임라인에서 현재 위치를 확인할 수 있습니다.
특히 이 예산 전략은 남은 예산(totalBudget - costSoFar
)을 파악하고 이를 남은 일수의 두 배로 나눕니다. 이렇게 하면 캠페인 종료 시점에 예산이 집중됩니다. START_DATE
이후의 비용을 사용하면 설정된 예산이 완전히 소진되지 않는 '느린 날'도 고려됩니다.
실제를 위한 예산
예산 전략이 마음에 들면 이 스크립트를 매일 실행하도록 예약하기 전에 몇 가지 변경사항을 적용해야 합니다.
먼저 파일 맨 위의 상수를 업데이트합니다.
START_DATE
: 예산 전략의 시작으로 설정합니다. 현재 날짜 또는 과거의 날짜여야 합니다.END_DATE
: 이 예산으로 광고할 마지막 날을 설정합니다.TOTAL_BUDGET
: 지출하려는 총 금액입니다. 이 값은 계정의 통화로 사용하고 스크립트를 실행하도록 예약한 시기에 따라 초과될 수 있습니다.CAMPAIGN_NAME
: 예산 전략을 적용할 캠페인의 이름입니다.
그런 다음 테스트를 사용 중지하고 실제로 예산을 변경하는 로직을 사용 설정합니다.
function main() {
// testBudgetStrategy(calculateBudgetEvenly, 10, 500);
setNewBudget(calculateBudgetWeighted, CAMPAIGN_NAME, TOTAL_BUDGET, START_DATE, END_DATE);
}
예약
다음 날의 예산을 가능한 한 많이 보내도록 이 스크립트를 매일 현지 시간대의 자정 또는 그 직후에 실행하도록 예약하세요. 하지만 비용과 같은 가져온 보고서 데이터는 약 3시간 지연될 수 있으므로 costSoFar
매개변수는 자정 이후에 실행되도록 예약된 스크립트의 경우 어제의 총계를 참조할 수 있습니다.
설정
아래 버튼을 클릭하여 Google Ads 계정에서 스크립트를 만드세요.
스크립트를 저장하고 미리보기 버튼을 클릭합니다. 이 스크립트는 기본적으로 10일 동안 500달러의 예산 전략을 시뮬레이션합니다. 로거 출력에는 시뮬레이션되는 날짜, 해당 날짜에 할당된 예산, 지금까지 지출된 총금액이 반영됩니다.
소스 코드
// Copyright 2015, Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @name Flexible Budgets
*
* @overview The Flexible budgets script dynamically adjusts campaign budget for
* an advertiser account with a custom budget distribution scheme on a daily
* basis. See
* https://developers.google.com/google-ads/scripts/docs/solutions/flexible-budgets
* for more details.
*
* @author Google Ads Scripts Team [adwords-scripts@googlegroups.com]
*
* @version 2.1
*
* @changelog
* - version 2.1
* - Split into info, config, and code.
* - version 2.0
* - Updated to use new Google Ads scripts features.
* - version 1.0.3
* - Add support for video and shopping campaigns.
* - version 1.0.2
* - Use setAmount on the budget instead of campaign.setBudget.
* - version 1.0.1
* - Improvements to time zone handling.
* - version 1.0
* - Released initial version.
*/
/**
* Configuration to be used for the Flexible Budgets script.
*/
CONFIG = {
'total_budget': 500,
'campaign_name': 'Special Promotion',
'start_date': 'November 1, 2021 0:00:00 -0500',
'end_date': 'December 1, 2021 0:00:00 -0500'
};
const TOTAL_BUDGET = CONFIG.total_budget;
const CAMPAIGN_NAME = CONFIG.campaign_name;
const START_DATE = new Date(CONFIG.start_date);
const END_DATE = new Date(CONFIG.end_date);
function main() {
testBudgetStrategy(calculateBudgetEvenly, 10, 500);
// setNewBudget(calculateBudgetEvenly, CAMPAIGN_NAME, TOTAL_BUDGET,
// START_DATE, END_DATE);
}
function setNewBudget(budgetFunction, campaignName, totalBudget, start, end) {
const today = new Date();
if (today < start) {
console.log('Not ready to set budget yet');
return;
}
const campaign = getCampaign(campaignName);
const costSoFar = campaign.getStatsFor(
getDateStringInTimeZone('yyyyMMdd', start),
getDateStringInTimeZone('yyyyMMdd', end)).getCost();
const daysSoFar = datediff(start, today);
const totalDays = datediff(start, end);
const newBudget = budgetFunction(costSoFar, totalBudget, daysSoFar,
totalDays);
campaign.getBudget().setAmount(newBudget);
}
function calculateBudgetEvenly(costSoFar, totalBudget, daysSoFar, totalDays) {
const daysRemaining = totalDays - daysSoFar;
const budgetRemaining = totalBudget - costSoFar;
if (daysRemaining <= 0) {
return budgetRemaining;
} else {
return budgetRemaining / daysRemaining;
}
}
function calculateBudgetWeighted(costSoFar, totalBudget, daysSoFar,
totalDays) {
const daysRemaining = totalDays - daysSoFar;
const budgetRemaining = totalBudget - costSoFar;
if (daysRemaining <= 0) {
return budgetRemaining;
} else {
return budgetRemaining / (2 * daysRemaining - 1);
}
}
function testBudgetStrategy(budgetFunc, totalDays, totalBudget) {
let daysSoFar = 0;
let costSoFar = 0;
while (daysSoFar <= totalDays + 2) {
const newBudget = budgetFunc(costSoFar, totalBudget, daysSoFar, totalDays);
console.log(`Day ${daysSoFar + 1} of ${totalDays}, new budget ` +
`${newBudget}, cost so far ${costSoFar}`);
costSoFar += newBudget;
daysSoFar += 1;
}
}
/**
* Returns number of days between two dates, rounded up to nearest whole day.
*/
function datediff(from, to) {
const millisPerDay = 1000 * 60 * 60 * 24;
return Math.ceil((to - from) / millisPerDay);
}
function getDateStringInTimeZone(format, date, timeZone) {
date = date || new Date();
timeZone = timeZone || AdsApp.currentAccount().getTimeZone();
return Utilities.formatDate(date, timeZone, format);
}
/**
* Finds a campaign by name, whether it is a regular, video, or shopping
* campaign, by trying all in sequence until it finds one.
*
* @param {string} campaignName The campaign name to find.
* @return {Object} The campaign found, or null if none was found.
*/
function getCampaign(campaignName) {
const selectors = [AdsApp.campaigns(), AdsApp.videoCampaigns(),
AdsApp.shoppingCampaigns()];
for (const selector of selectors) {
const campaignIter = selector
.withCondition(`CampaignName = "${campaignName}"`)
.get();
if (campaignIter.hasNext()) {
return campaignIter.next();
}
}
throw new Error(`Could not find specified campaign: ${campaignName}`);
}