유연한 예산 - 단일 계정

도구 아이콘을 클릭합니다.

Google Ads에서는 캠페인별로 일일 예산 금액을 설정할 수 있습니다. 그러나 마케팅 이니셔티브에는 고정 비용이 듭니다. 예를 들어 "가을 할인까지 $5,000를 쓰고 싶습니다." 입찰 전략은 일일예산 지출 방식은 제어할 수 있지만 지출 방식을 관리할 수는 없습니다. 캠페인 중에 예산이 소진될 때

예를 들어 가을 할인에 $5, 000만 지출하고 싶은데 10일 동안 광고를 게재하려는 경우 일일 예산을 500, 000원으로 설정하면 전체 예산 하지만 이 예에서는 전체 예산을 비용을 균등하게 지출하고자 합니다. Google Ads에 지난 며칠간 예산의 대부분을 지출하려는 경우

이 스크립트는 커스텀 예산 분배 체계

작동 방식

예산 전략 테스트

스크립트에는 다음을 실행하는 효과를 시뮬레이션하는 테스트 코드가 포함되어 있습니다. 며칠입니다. 이렇게 하면 스크립트가 실행될 때 어떤 일이 일어날지 일정 기간에 걸쳐 매일 실행되도록 예약되어 있습니다

기본적으로 이 스크립트는 $500의 예산을 균등하게 배분하여 시뮬레이션합니다. 10일 이상

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

스크립트는 매일 새 예산을 계산하여 예산 지출이 고르게 분산됩니다. 할당된 예산 한도에 도달하면 예산이 설정됩니다. 지출을 줄일 수 있습니다

사용되는 함수를 변경하여 사용되는 예산 전략을 변경할 수 있습니다. 함수 자체를 수정할 수 있습니다. 이 스크립트에는 다음과 같은 두 가지 사전 작성된 전략이 제공됩니다. calculateBudgetEvenlycalculateBudgetWeighted 가중치 적용 테스트 설정하기 다음과 같이 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}`);
}