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
每天,指令碼都會計算新的預算,確保預算支出平均分配。達到預算上限後,系統會將預算設為零,停止支出。
如要變更預算策略,請變更使用的函式,或修改函式本身。指令碼內建兩種策略: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
從 totalDays
- :
START_DATE
和END_DATE
之間的天數總和。
START_DATE
到今天經過的天數。
You can write your own function as long as it takes these arguments. 您可以加入這些引數,自行撰寫函式。您可以根據這些值,比較目前支出與整體支出,並判斷目前在整個預算時間軸中的位置。
具體來說,這項預算策略會計算剩餘預算 (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}`);
}