Forecast Reach

  • This content showcases Java and C# code examples that demonstrate how to use the Google Ads ReachPlanService to forecast the reach of video ad campaigns.

  • The code examples cover how to discover plannable locations and available products, define targeting options such as age, gender, and devices, and set campaign duration.

  • Key operations include retrieving locations (showPlannableLocations), listing available products (showPlannableProducts), defining product mixes, and generating a reach forecast (getReachCurve/ requestReachCurve).

  • The process involves creating a GenerateReachForecastRequest with parameters like customer ID, location, product mix, budget, currency, targeting, and campaign duration.

  • The workflow is described with specific function like forecastManualMix and buildReachRequest, covering initialization, discovery, forecasting, and error handling, and it includes how to manually define budget allocation between different products.

Java

// Copyright 2020 Google LLC
//
// 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
//
//     https://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.

package com.google.ads.googleads.examples.planning;

import com.beust.jcommander.Parameter;
import com.google.ads.googleads.examples.utils.ArgumentNames;
import com.google.ads.googleads.examples.utils.CodeSampleParams;
import com.google.ads.googleads.lib.GoogleAdsClient;
import com.google.ads.googleads.v21.common.DeviceInfo;
import com.google.ads.googleads.v21.common.GenderInfo;
import com.google.ads.googleads.v21.enums.DeviceEnum.Device;
import com.google.ads.googleads.v21.enums.GenderTypeEnum.GenderType;
import com.google.ads.googleads.v21.enums.ReachPlanAgeRangeEnum.ReachPlanAgeRange;
import com.google.ads.googleads.v21.errors.GoogleAdsError;
import com.google.ads.googleads.v21.errors.GoogleAdsException;
import com.google.ads.googleads.v21.services.CampaignDuration;
import com.google.ads.googleads.v21.services.GenerateReachForecastRequest;
import com.google.ads.googleads.v21.services.GenerateReachForecastResponse;
import com.google.ads.googleads.v21.services.ListPlannableLocationsRequest;
import com.google.ads.googleads.v21.services.ListPlannableLocationsResponse;
import com.google.ads.googleads.v21.services.ListPlannableProductsRequest;
import com.google.ads.googleads.v21.services.ListPlannableProductsResponse;
import com.google.ads.googleads.v21.services.PlannableLocation;
import com.google.ads.googleads.v21.services.PlannedProduct;
import com.google.ads.googleads.v21.services.PlannedProductReachForecast;
import com.google.ads.googleads.v21.services.ProductMetadata;
import com.google.ads.googleads.v21.services.ReachForecast;
import com.google.ads.googleads.v21.services.ReachPlanServiceClient;
import com.google.ads.googleads.v21.services.Targeting;
import com.google.common.base.Joiner;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Demonstrates how to interact with the ReachPlanService to find plannable locations and product
 * codes, build a media plan, and generate a video ads reach forecast.
 */
public class ForecastReach {

  private static class ForecastReachParams extends CodeSampleParams {
    @Parameter(names = ArgumentNames.CUSTOMER_ID, required = true)
    private Long customerId;
  }

  public static void main(String[] args) {
    ForecastReachParams params = new ForecastReachParams();

    if (!params.parseArguments(args)) {

      // Either pass the required parameters for this example on the command line, or insert them
      // into the code here. See the parameter class definition above for descriptions.
      params.customerId = Long.parseLong("INSERT_CUSTOMER_ID_HERE");
    }

    GoogleAdsClient googleAdsClient;
    try {
      googleAdsClient = GoogleAdsClient.newBuilder().fromPropertiesFile().build();
    } catch (FileNotFoundException fnfe) {
      System.err.printf(
          "Failed to load GoogleAdsClient configuration from file. Exception: %s%n", fnfe);
      return;
    } catch (IOException ioe) {
      System.err.printf("Failed to create GoogleAdsClient. Exception: %s%n", ioe);
      return;
    }

    try {
      new ForecastReach().runExample(googleAdsClient, params.customerId);
    } catch (GoogleAdsException gae) {
      // GoogleAdsException is the base class for most exceptions thrown by an API request.
      // Instances of this exception have a message and a GoogleAdsFailure that contains a
      // collection of GoogleAdsErrors that indicate the underlying causes of the
      // GoogleAdsException.
      System.err.printf(
          "Request ID %s failed due to GoogleAdsException. Underlying errors:%n",
          gae.getRequestId());
      int i = 0;
      for (GoogleAdsError googleAdsError : gae.getGoogleAdsFailure().getErrorsList()) {
        System.err.printf("  Error %d: %s%n", i++, googleAdsError);
      }
    }
  }

  /**
   * Runs the example.
   *
   * @param googleAdsClient the Google Ads API client.
   * @param customerId the customer ID for the reach forecast.
   */
  private void runExample(GoogleAdsClient googleAdsClient, long customerId) {
    String locationId = "2840"; // US
    String currencyCode = "USD";
    long budgetMicros = 5_000_000L; // $5 USD

    try (ReachPlanServiceClient reachPlanServiceClient =
        googleAdsClient.getLatestVersion().createReachPlanServiceClient()) {
      showPlannableLocations(reachPlanServiceClient);
      showPlannableProducts(reachPlanServiceClient, locationId);
      forecastManualMix(reachPlanServiceClient, customerId, locationId, currencyCode, budgetMicros);
    }
  }

  /**
   * Maps friendly names of plannable locations to location IDs usable with ReachPlanServiceClient.
   *
   * @param reachPlanServiceClient instance of Reach Plan Service client.
   */
  private void showPlannableLocations(ReachPlanServiceClient reachPlanServiceClient) {
    ListPlannableLocationsRequest request = ListPlannableLocationsRequest.newBuilder().build();
    ListPlannableLocationsResponse response =
        reachPlanServiceClient.listPlannableLocations(request);

    System.out.println("Plannable Locations:");
    for (PlannableLocation location : response.getPlannableLocationsList()) {
      System.out.printf(
          "Name: %s, ID: %s, ParentCountryId: %s%n",
          location.getName(), location.getId(), location.getParentCountryId());
    }
  }

  /**
   * Lists plannable products for a given location.
   *
   * @param reachPlanServiceClient instance of Reach Plan Service client.
   * @param locationId location ID to plan for. To find a valid location ID, either see
   *     https://developers.google.com/google-ads/api/reference/data/geotargets or call
   *     ReachPlanServiceClient.listPlannableLocations().
   */
  private void showPlannableProducts(
      ReachPlanServiceClient reachPlanServiceClient, String locationId) {
    ListPlannableProductsRequest request =
        ListPlannableProductsRequest.newBuilder().setPlannableLocationId(locationId).build();

    ListPlannableProductsResponse response = reachPlanServiceClient.listPlannableProducts(request);

    System.out.printf("Plannable Products for location %s:%n", locationId);
    for (ProductMetadata product : response.getProductMetadataList()) {
      System.out.printf("%s:%n", product.getPlannableProductCode());
      System.out.println("Age Ranges:");
      for (ReachPlanAgeRange ageRange : product.getPlannableTargeting().getAgeRangesList()) {
        System.out.printf("\t- %s%n", ageRange);
      }
      System.out.println("Genders:");
      for (GenderInfo gender : product.getPlannableTargeting().getGendersList()) {
        System.out.printf("\t- %s%n", gender.getType());
      }
      System.out.println("Devices:");
      for (DeviceInfo device : product.getPlannableTargeting().getDevicesList()) {
        System.out.printf("\t- %s%n", device.getType());
      }
    }
  }

  /**
   * Creates a base request to generate a reach forecast.
   *
   * @param customerId the customer ID for the reach forecast.
   * @param productMix the product mix for the reach forecast.
   * @param locationId location ID to plan for. To find a valid location ID, either see
   *     https://developers.google.com/google-ads/api/reference/data/geotargets or call
   *     ReachPlanServiceClient.ListPlannableLocations.
   * @param currencyCode three-character ISO 4217 currency code.
   * @return populated GenerateReachForecastRequest object.
   */
  private GenerateReachForecastRequest buildReachRequest(
      Long customerId, List<PlannedProduct> productMix, String locationId, String currencyCode) {
    CampaignDuration duration = CampaignDuration.newBuilder().setDurationInDays(28).build();

    List<GenderInfo> genders =
        Arrays.asList(
            GenderInfo.newBuilder().setType(GenderType.FEMALE).build(),
            GenderInfo.newBuilder().setType(GenderType.MALE).build());

    List<DeviceInfo> devices =
        Arrays.asList(
            DeviceInfo.newBuilder().setType(Device.DESKTOP).build(),
            DeviceInfo.newBuilder().setType(Device.MOBILE).build(),
            DeviceInfo.newBuilder().setType(Device.TABLET).build());

    Targeting targeting =
        Targeting.newBuilder()
            .setPlannableLocationId(locationId)
            .setAgeRange(ReachPlanAgeRange.AGE_RANGE_18_65_UP)
            .addAllGenders(genders)
            .addAllDevices(devices)
            .build();

    // See the docs for defaults and valid ranges:
    // https://developers.google.com/google-ads/api/reference/rpc/latest/GenerateReachForecastRequest
    return GenerateReachForecastRequest.newBuilder()
        .setCustomerId(Long.toString(customerId))
        .setCurrencyCode(currencyCode)
        .setCampaignDuration(duration)
        .setTargeting(targeting)
        .setMinEffectiveFrequency(1)
        .addAllPlannedProducts(productMix)
        .build();
  }

  /**
   * Pulls and prints the reach curve for the given request.
   *
   * @param reachPlanServiceClient instance of Reach Plan Service client.
   * @param request an already-populated reach curve request.
   */
  private void getReachCurve(
      ReachPlanServiceClient reachPlanServiceClient, GenerateReachForecastRequest request) {
    GenerateReachForecastResponse response = reachPlanServiceClient.generateReachForecast(request);
    System.out.println("Reach curve output:");
    System.out.println(
        "Currency, Cost Micros, On-Target Reach, On-Target Imprs, Total Reach, Total Imprs,"
            + " Products");
    for (ReachForecast point : response.getReachCurve().getReachForecastsList()) {
      System.out.printf(
          "%s, \"",
          Joiner.on(", ")
              .join(
                  request.getCurrencyCode(),
                  String.valueOf(point.getCostMicros()),
                  String.valueOf(point.getForecast().getOnTargetReach()),
                  String.valueOf(point.getForecast().getOnTargetImpressions()),
                  String.valueOf(point.getForecast().getTotalReach()),
                  String.valueOf(point.getForecast().getTotalImpressions())));
      for (PlannedProductReachForecast product : point.getPlannedProductReachForecastsList()) {
        System.out.printf("[Product: %s, ", product.getPlannableProductCode());
        System.out.printf("Budget Micros: %s]", product.getCostMicros());
      }
      System.out.printf("\"%n");
    }
  }

  /**
   * Pulls a forecast for a budget split 15% and 85% between two products.
   *
   * @param reachPlanServiceClient instance of Reach Plan Service client.
   * @param customerId the customer ID for the reach forecast.
   * @param locationId location ID to plan for. To find a valid location ID, either see
   *     https://developers.google.com/google-ads/api/reference/data/geotargets or call
   *     ReachPlanServiceClient.listPlannableLocations().
   * @param currencyCode three-character ISO 4217 currency code.
   * @param budgetMicros budget in currency to plan for.
   */
  private void forecastManualMix(
      ReachPlanServiceClient reachPlanServiceClient,
      long customerId,
      String locationId,
      String currencyCode,
      long budgetMicros) {
    List<PlannedProduct> productMix = new ArrayList<>();

    // Set up a ratio to split the budget between two products.
    double trueviewAllocation = 0.15;
    double bumperAllocation = 1 - trueviewAllocation;

    // See listPlannableProducts on ReachPlanService to retrieve a list
    // of valid PlannableProductCode's for a given location:
    // https://developers.google.com/google-ads/api/reference/rpc/latest/ReachPlanService
    productMix.add(
        PlannedProduct.newBuilder()
            .setPlannableProductCode("TRUEVIEW_IN_STREAM")
            .setBudgetMicros((long) (budgetMicros * bumperAllocation))
            .build());
    productMix.add(
        PlannedProduct.newBuilder()
            .setPlannableProductCode("BUMPER")
            .setBudgetMicros((long) (budgetMicros * bumperAllocation))
            .build());

    GenerateReachForecastRequest request =
        buildReachRequest(customerId, productMix, locationId, currencyCode);

    getReachCurve(reachPlanServiceClient, request);
  }

}

      

C#

// Copyright 2019 Google LLC
//
// 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.

using CommandLine;
using Google.Ads.Gax.Examples;
using Google.Ads.GoogleAds.Lib;
using Google.Ads.GoogleAds.V21.Common;
using Google.Ads.GoogleAds.V21.Errors;
using Google.Ads.GoogleAds.V21.Services;
using System;
using System.Collections.Generic;
using static Google.Ads.GoogleAds.V21.Enums.DeviceEnum.Types;
using static Google.Ads.GoogleAds.V21.Enums.GenderTypeEnum.Types;
using static Google.Ads.GoogleAds.V21.Enums.ReachPlanAgeRangeEnum.Types;

namespace Google.Ads.GoogleAds.Examples.V21
{
    /// <summary>
    /// This example demonstrates how to interact with the ReachPlanService to find plannable
    /// locations and product codes, build a media plan, and generate a video ads reach forecast.
    /// </summary>
    public class ForecastReach : ExampleBase
    {
        /// <summary>
        /// Command line options for running the <see cref="ForecastReach"/> example.
        /// </summary>
        public class Options : OptionsBase
        {
            /// <summary>
            /// The Google Ads customer ID for which the call is made.
            /// </summary>
            [Option("customerId", Required = true, HelpText =
                "The Google Ads customer ID for which the call is made.")]
            public long CustomerId { get; set; }
        }

        /// <summary>
        /// Main method, to run this code example as a standalone application.
        /// </summary>
        /// <param name="args">The command line arguments.</param>
        public static void Main(string[] args)
        {
            Options options = ExampleUtilities.ParseCommandLine<Options>(args);

            ForecastReach codeExample = new ForecastReach();
            Console.WriteLine(codeExample.Description);
            codeExample.Run(new GoogleAdsClient(), options.CustomerId);
        }

        /// <summary>
        /// Returns a description about the code example.
        /// </summary>
        public override string Description =>
            "This example demonstrates how to interact with the ReachPlanService to find " +
            "plannable locations and product codes, build a media plan, and generate a video ads " +
            "reach forecast.";

        /// <summary>
        /// Runs the code example, showing a typical series of calls to the
        /// <see cref="Services.V21.ReachPlanService"/>.
        /// </summary>
        /// <param name="client">The Google Ads API client.</param>
        /// <param name="customerId">The Google Ads customer ID for which the call is made.</param>
        public void Run(GoogleAdsClient client, long customerId)
        {
            string locationId = "2840"; // US
            string currencyCode = "USD";
            long budgetMicros = 5_000_000L;
            ReachPlanServiceClient reachPlanService =
                client.GetService(Services.V21.ReachPlanService);

            try
            {
                ShowPlannableLocations(reachPlanService);
                ShowPlannableProducts(reachPlanService, locationId);
                ForecastMix(reachPlanService, customerId.ToString(), locationId, currencyCode,
                    budgetMicros);
            }
            catch (GoogleAdsException e)
            {
                Console.WriteLine("Failure:");
                Console.WriteLine($"Message: {e.Message}");
                Console.WriteLine($"Failure: {e.Failure}");
                Console.WriteLine($"Request ID: {e.RequestId}");
                throw;
            }
        }

        /// <summary>
        /// Maps friendly names of plannable locations to location IDs usable with
        /// <see cref="ReachPlanServiceClient"/>.
        /// </summary>
        /// <param name="reachPlanService">Instance of Reach Plan Service client.</param>
        public void ShowPlannableLocations(ReachPlanServiceClient reachPlanService)
        {
            ListPlannableLocationsRequest request = new ListPlannableLocationsRequest();
            ListPlannableLocationsResponse response = reachPlanService.ListPlannableLocations(
                request);

            Console.WriteLine("Plannable Locations:");
            Console.WriteLine("Name,\tId,\t,ParentCountryId");
            foreach (PlannableLocation location in response.PlannableLocations)
            {
                Console.WriteLine(
                    $"\"{location.Name}\",\t{location.Id},{location.ParentCountryId}");
            }
        }

        /// <summary>
        /// Lists plannable products for a given location.
        /// </summary>
        /// <param name="reachPlanService">Instance of Reach Plan Service client.</param>
        /// <param name="locationId">Location ID to plan for. To find a valid location ID, either
        /// see https://developers.google.com/google-ads/api/reference/data/geotargets or call
        /// <see cref="ReachPlanServiceClient.ListPlannableLocations"/>.</param>
        public void ShowPlannableProducts(
            ReachPlanServiceClient reachPlanService, string locationId)
        {
            ListPlannableProductsRequest request = new ListPlannableProductsRequest
            {
                PlannableLocationId = locationId
            };
            ListPlannableProductsResponse response = reachPlanService.ListPlannableProducts(
                request);

            Console.WriteLine($"Plannable Products for location {locationId}:");
            foreach (ProductMetadata product in response.ProductMetadata)
            {
                Console.WriteLine($"{product.PlannableProductCode}:");
                Console.WriteLine("Age Ranges:");
                foreach (ReachPlanAgeRange ageRange in product.PlannableTargeting.AgeRanges)
                {
                    Console.WriteLine($"\t- {ageRange}");
                }

                Console.WriteLine("Genders:");
                foreach (GenderInfo gender in product.PlannableTargeting.Genders)
                {
                    Console.WriteLine($"\t- {gender.Type}");
                }

                Console.WriteLine("Devices:");
                foreach (DeviceInfo device in product.PlannableTargeting.Devices)
                {
                    Console.WriteLine($"\t- {device.Type}");
                }
            }
        }

        /// <summary>
        /// Create a base request to generate a reach forecast.
        /// </summary>
        /// <param name="customerId">The customer ID for the reach forecast.</param>
        /// <param name="productMix">The product mix for the reach forecast.</param>
        /// <param name="locationId">Location ID to plan for. To find a valid location ID, either
        /// see https://developers.google.com/google-ads/api/reference/data/geotargets or call
        /// <see cref="ReachPlanServiceClient.ListPlannableLocations"/>.</param>
        /// <param name="currencyCode">Three-character ISO 4217 currency code.</param>
        public GenerateReachForecastRequest BuildReachRequest(
            string customerId, List<PlannedProduct> productMix, string locationId,
            string currencyCode)
        {
            // Valid durations are between 1 and 90 days.
            CampaignDuration duration = new CampaignDuration
            {
                DurationInDays = 28
            };

            GenderInfo[] genders =
            {
                new GenderInfo {Type = GenderType.Female},
                new GenderInfo {Type = GenderType.Male}
            };

            DeviceInfo[] devices =
            {
                new DeviceInfo {Type = Device.Desktop},
                new DeviceInfo {Type = Device.Mobile},
                new DeviceInfo {Type = Device.Tablet}
            };

            Targeting targeting = new Targeting
            {
                PlannableLocationId = locationId,
                AgeRange = ReachPlanAgeRange.AgeRange1865Up,
            };
            targeting.Genders.AddRange(genders);
            targeting.Devices.AddRange(devices);

            // See the docs for defaults and valid ranges:
            // https://developers.google.com/google-ads/api/reference/rpc/latest/GenerateReachForecastRequest
            GenerateReachForecastRequest request = new GenerateReachForecastRequest
            {
                CustomerId = customerId,
                CurrencyCode = currencyCode,
                CampaignDuration = duration,
                Targeting = targeting,
                MinEffectiveFrequency = 1
            };

            request.PlannedProducts.AddRange(productMix);

            return request;
        }

        /// <summary>
        /// Retrieves and prints the reach curve for the given request.
        /// </summary>
        /// <param name="reachPlanService">Instance of Reach Plan Service client.</param>
        /// <param name="request">An already-populated reach curve request.</param>
        public void GetReachCurve(ReachPlanServiceClient reachPlanService,
            GenerateReachForecastRequest request)
        {
            GenerateReachForecastResponse response = reachPlanService.GenerateReachForecast(
                request);
            Console.WriteLine("Reach curve output:");
            Console.WriteLine(
                "Currency, Cost Micros, On-Target Reach, On-Target Impressions, Total Reach," +
                " Total Impressions, Products");
            foreach (ReachForecast point in response.ReachCurve.ReachForecasts)
            {
                Console.Write($"{request.CurrencyCode}, ");
                Console.Write($"{point.CostMicros}, ");
                Console.Write($"{point.Forecast.OnTargetReach}, ");
                Console.Write($"{point.Forecast.OnTargetImpressions}, ");
                Console.Write($"{point.Forecast.TotalReach}, ");
                Console.Write($"{point.Forecast.TotalImpressions}, ");
                Console.Write("\"[");
                foreach (PlannedProductReachForecast productReachForecast in
                    point.PlannedProductReachForecasts)
                {
                    Console.Write($"(Product: {productReachForecast.PlannableProductCode}, ");
                    Console.Write($"Budget Micros: {productReachForecast.CostMicros}), ");
                }

                Console.WriteLine("]\"");
            }
        }

        /// <summary>
        /// Gets a forecast for a budget split 15% and 85% between two products.
        /// </summary>
        /// <param name="reachPlanService">Instance of Reach Plan Service client.</param>
        /// <param name="customerId">The customer ID for the reach forecast.</param>
        /// <param name="locationId">Location ID to plan for. To find a valid location ID, either
        /// see https://developers.google.com/google-ads/api/reference/data/geotargets or call
        /// <see cref="ReachPlanServiceClient.ListPlannableLocations"/>.</param>
        /// <param name="currencyCode">Three-character ISO 4217 currency code.</param>
        /// <param name="budgetMicros">Budget in currency to plan for.</param>
        public void ForecastMix(ReachPlanServiceClient reachPlanService, string customerId,
            string locationId, string currencyCode, long budgetMicros)
        {
            List<PlannedProduct> productMix = new List<PlannedProduct>();

            // Set up a ratio to split the budget between two products.
            double trueviewAllocation = 0.15;
            double bumperAllocation = 1 - trueviewAllocation;

            // See listPlannableProducts on ReachPlanService to retrieve a list
            // of valid PlannableProductCode's for a given location:
            // https://developers.google.com/google-ads/api/reference/rpc/latest/ReachPlanService
            productMix.Add(new PlannedProduct
            {
                PlannableProductCode = "TRUEVIEW_IN_STREAM",
                BudgetMicros = Convert.ToInt64(budgetMicros * trueviewAllocation)
            });
            productMix.Add(new PlannedProduct
            {
                PlannableProductCode = "BUMPER",
                BudgetMicros = Convert.ToInt64(budgetMicros * bumperAllocation)
            });

            GenerateReachForecastRequest request =
                BuildReachRequest(customerId, productMix, locationId, currencyCode);

            GetReachCurve(reachPlanService, request);
        }
    }
}

      

PHP

<?php

/**
 * Copyright 2020 Google LLC
 *
 * 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
 *
 *     https://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.
 */

namespace Google\Ads\GoogleAds\Examples\Planning;

require __DIR__ . '/../../vendor/autoload.php';

use GetOpt\GetOpt;
use Google\Ads\GoogleAds\Examples\Utils\ArgumentNames;
use Google\Ads\GoogleAds\Examples\Utils\ArgumentParser;
use Google\Ads\GoogleAds\Lib\OAuth2TokenBuilder;
use Google\Ads\GoogleAds\Lib\V21\GoogleAdsClient;
use Google\Ads\GoogleAds\Lib\V21\GoogleAdsClientBuilder;
use Google\Ads\GoogleAds\Lib\V21\GoogleAdsException;
use Google\Ads\GoogleAds\V21\Common\DeviceInfo;
use Google\Ads\GoogleAds\V21\Common\GenderInfo;
use Google\Ads\GoogleAds\V21\Enums\DeviceEnum\Device;
use Google\Ads\GoogleAds\V21\Enums\GenderTypeEnum\GenderType;
use Google\Ads\GoogleAds\V21\Enums\ReachPlanAgeRangeEnum\ReachPlanAgeRange;
use Google\Ads\GoogleAds\V21\Errors\GoogleAdsError;
use Google\Ads\GoogleAds\V21\Services\CampaignDuration;
use Google\Ads\GoogleAds\V21\Services\GenerateReachForecastRequest;
use Google\Ads\GoogleAds\V21\Services\ListPlannableLocationsRequest;
use Google\Ads\GoogleAds\V21\Services\ListPlannableProductsRequest;
use Google\Ads\GoogleAds\V21\Services\PlannableLocation;
use Google\Ads\GoogleAds\V21\Services\PlannedProduct;
use Google\Ads\GoogleAds\V21\Services\PlannedProductReachForecast;
use Google\Ads\GoogleAds\V21\Services\ProductMetadata;
use Google\Ads\GoogleAds\V21\Services\ReachForecast;
use Google\Ads\GoogleAds\V21\Services\Targeting;
use Google\ApiCore\ApiException;

/**
 * This example demonstrates how to interact with the ReachPlanService to find plannable
 * locations and product codes, build a media plan, and generate a video ads reach forecast.
 */
class ForecastReach
{
    private const CUSTOMER_ID = 'INSERT_CUSTOMER_ID_HERE';
    private const CURRENCY_CODE = 'USD';
    // You can get a valid location ID from
    // https://developers.google.com/adwords/api/docs/appendix/geotargeting or by calling
    // ListPlannableLocations on the ReachPlanService.
    private const LOCATION_ID = '2840'; // US
    private const BUDGET_MICROS = 5000000; // 5

    public static function main()
    {
        // Either pass the required parameters for this example on the command line, or insert
        // them into the constants above.
        $options = (new ArgumentParser())->parseCommandArguments([
            ArgumentNames::CUSTOMER_ID => GetOpt::REQUIRED_ARGUMENT
        ]);

        // Generate a refreshable OAuth2 credential for authentication.
        $oAuth2Credential = (new OAuth2TokenBuilder())->fromFile()->build();

        // Construct a Google Ads client configured from a properties file and the
        // OAuth2 credentials above.
        $googleAdsClient = (new GoogleAdsClientBuilder())
            ->fromFile()
            ->withOAuth2Credential($oAuth2Credential)
            ->build();

        try {
            self::runExample(
                $googleAdsClient,
                $options[ArgumentNames::CUSTOMER_ID] ?: self::CUSTOMER_ID
            );
        } catch (GoogleAdsException $googleAdsException) {
            printf(
                "Request with ID '%s' has failed.%sGoogle Ads failure details:%s",
                $googleAdsException->getRequestId(),
                PHP_EOL,
                PHP_EOL
            );
            foreach ($googleAdsException->getGoogleAdsFailure()->getErrors() as $error) {
                /** @var GoogleAdsError $error */
                printf(
                    "\t%s: %s%s",
                    $error->getErrorCode()->getErrorCode(),
                    $error->getMessage(),
                    PHP_EOL
                );
            }
            exit(1);
        } catch (ApiException $apiException) {
            printf(
                "ApiException was thrown with message '%s'.%s",
                $apiException->getMessage(),
                PHP_EOL
            );
            exit(1);
        }
    }

    /**
     * Runs the example.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     */
    public static function runExample(GoogleAdsClient $googleAdsClient, int $customerId)
    {
        self::showPlannableLocations($googleAdsClient);
        self::showPlannableProducts($googleAdsClient);
        self::forecastManualMix($googleAdsClient, $customerId);
    }

    /**
     * Shows map of plannable locations to their IDs.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     */
    private static function showPlannableLocations(GoogleAdsClient $googleAdsClient)
    {
        $response = $googleAdsClient->getReachPlanServiceClient()->listPlannableLocations(
            new ListPlannableLocationsRequest()
        );

        printf("Plannable Locations:%sName, Id, ParentCountryId%s", PHP_EOL, PHP_EOL);
        foreach ($response->getPlannableLocations() as $location) {
            /** @var PlannableLocation $location */
            printf(
                "'%s', %s, %s%s",
                $location->getName(),
                $location->getId(),
                $location->getParentCountryId(),
                PHP_EOL
            );
        }
    }

    /**
     * Lists plannable products for a given location.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     */
    private static function showPlannableProducts(GoogleAdsClient $googleAdsClient)
    {
        $response = $googleAdsClient->getReachPlanServiceClient()->listPlannableProducts(
            ListPlannableProductsRequest::build(self::LOCATION_ID)
        );

        print 'Plannable Products for Location ID ' . self::LOCATION_ID . ':' . PHP_EOL;
        foreach ($response->getProductMetadata() as $product) {
            /** @var ProductMetadata $product */
            print $product->getPlannableProductCode() . ':' . PHP_EOL;
            print 'Age Ranges:' . PHP_EOL;
            foreach ($product->getPlannableTargeting()->getAgeRanges() as $ageRange) {
                /** @var ReachPlanAgeRange $ageRange */
                printf("\t- %s%s", ReachPlanAgeRange::name($ageRange), PHP_EOL);
            }
            print 'Genders:' . PHP_EOL;
            foreach ($product->getPlannableTargeting()->getGenders() as $gender) {
                /** @var GenderInfo $gender */
                printf("\t- %s%s", GenderType::name($gender->getType()), PHP_EOL);
            }
            print 'Devices:' . PHP_EOL;
            foreach ($product->getPlannableTargeting()->getDevices() as $device) {
                /** @var DeviceInfo $device */
                printf("\t- %s%s", Device::name($device->getType()), PHP_EOL);
            }
        }
    }

    /**
     * Retrieves and prints the reach curve for a given product mix.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @param array $productMix the product mix for the reach forecast
     * @param string $locationId the location ID to plan for. You can get a valid location ID from
     *     https://developers.google.com/adwords/api/docs/appendix/geotargeting or
     *     by calling ListPlannableLocations on the ReachPlanService.
     * @param string $currencyCode three-character ISO 4217 currency code
     */
    private static function getReachCurve(
        GoogleAdsClient $googleAdsClient,
        int $customerId,
        array $productMix,
        string $locationId,
        string $currencyCode
    ) {
        // Valid durations are between 1 and 90 days.
        $duration = new CampaignDuration(['duration_in_days' => 28]);
        $targeting = new Targeting([
            'plannable_location_id' => $locationId,
            'age_range' => ReachPlanAgeRange::AGE_RANGE_18_65_UP,
            'genders' => [
                new GenderInfo(['type' => GenderType::FEMALE]),
                new GenderInfo(['type' => GenderType::MALE])
            ],
            'devices' => [
                new DeviceInfo(['type' => Device::DESKTOP]),
                new DeviceInfo(['type' => Device::MOBILE]),
                new DeviceInfo(['type' => Device::TABLET])
            ]
        ]);

        // See the docs for defaults and valid ranges:
        // https://developers.google.com/google-ads/api/reference/rpc/latest/GenerateReachForecastRequest
        $response = $googleAdsClient->getReachPlanServiceClient()->generateReachForecast(
            GenerateReachForecastRequest::build($customerId, $duration, $productMix)
                ->setCurrencyCode($currencyCode)
                ->setTargeting($targeting)
        );

        printf(
            "Reach curve output:%sCurrency, Cost Micros, On-Target Reach, On-Target Imprs," .
                " Total Reach, Total Imprs, Products%s",
            PHP_EOL,
            PHP_EOL
        );
        foreach ($response->getReachCurve()->getReachForecasts() as $point) {
            $products = '';
            /** @var ReachForecast $point */
            foreach ($point->getPlannedProductReachForecasts() as $plannedProductReachForecast) {
                /** @var PlannedProductReachForecast $plannedProductReachForecast */
                $products .= sprintf(
                    '(Product: %s, Budget Micros: %s)',
                    $plannedProductReachForecast->getPlannableProductCode(),
                    $plannedProductReachForecast->getCostMicros()
                );
            }
            printf(
                "%s, %d, %d, %d, %d, %d, %s%s",
                $currencyCode,
                $point->getCostMicros(),
                $point->getForecast()->getOnTargetReach(),
                $point->getForecast()->getOnTargetImpressions(),
                $point->getForecast()->getTotalReach(),
                $point->getForecast()->getTotalImpressions(),
                $products,
                PHP_EOL
            );
        }
    }

    /**
     * Gets a forecast for product mix created manually.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     */
    private static function forecastManualMix(GoogleAdsClient $googleAdsClient, int $customerId)
    {
        // Set up a ratio to split the budget between two products.
        $trueviewAllocation = floatval(0.15);
        $bumperAllocation = floatval(1 - $trueviewAllocation);

        // See listPlannableProducts on ReachPlanService to retrieve a list
        // of valid PlannableProductCode's for a given location:
        // https://developers.google.com/google-ads/api/reference/rpc/latest/ReachPlanService
        $productMix = [
            new PlannedProduct([
                'plannable_product_code' => 'TRUEVIEW_IN_STREAM',
                'budget_micros' => self::BUDGET_MICROS * $trueviewAllocation
            ]),
            new PlannedProduct([
                'plannable_product_code' => 'BUMPER',
                'budget_micros' => self::BUDGET_MICROS * $bumperAllocation
            ])
        ];

        self::getReachCurve(
            $googleAdsClient,
            $customerId,
            $productMix,
            self::LOCATION_ID,
            self::CURRENCY_CODE
        );
    }
}

ForecastReach::main();

      

Python

#!/usr/bin/env python
# Copyright 2019 Google LLC
#
# 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
#
#     https://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.
"""This code example generates a video ads reach forecast."""

import argparse
import math
import sys

from google.ads.googleads.client import GoogleAdsClient
from google.ads.googleads.errors import GoogleAdsException
from google.ads.googleads.v21.enums.types.reach_plan_age_range import (
    ReachPlanAgeRangeEnum,
)
from google.ads.googleads.v21.enums.types.gender_type import GenderTypeEnum
from google.ads.googleads.v21.enums.types.device import DeviceEnum
from google.ads.googleads.v21.common.types.criteria import (
    GenderInfo,
    DeviceInfo,
)
from google.ads.googleads.v21.services.services.reach_plan_service.client import (
    ReachPlanServiceClient,
)
from google.ads.googleads.v21.services.types.reach_plan_service import (
    ListPlannableLocationsResponse,
    PlannableLocation,
    ListPlannableProductsResponse,
    ProductMetadata,
    GenerateReachForecastRequest,
    GenerateReachForecastResponse,
    ReachForecast,
    PlannedProductReachForecast,
    PlannedProduct,
)

ONE_MILLION = 1.0e6


def main(client: GoogleAdsClient, customer_id: str):
    """The main method that creates all necessary entities for the example.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID.
    """
    # You can review a list of valid location IDs by visiting:
    # https://developers.google.com/google-ads/api/reference/data/geotargets
    # or by calling the ListPlannableLocations method on ReachPlanService.
    location_id = "2840"  # US
    currency_code = "USD"
    budget = 500000

    show_plannable_locations(client)
    show_plannable_products(client, location_id)
    forecast_manual_mix(client, customer_id, location_id, currency_code, budget)


def show_plannable_locations(client: GoogleAdsClient):
    """Shows map of plannable locations to their IDs.

    Args:
        client: an initialized GoogleAdsClient instance.
    """
    reach_plan_service: ReachPlanServiceClient = client.get_service(
        "ReachPlanService"
    )
    response: ListPlannableLocationsResponse = (
        reach_plan_service.list_plannable_locations()
    )

    print("Plannable Locations")
    print("Name,\tId,\tParentCountryId")
    location: PlannableLocation
    for location in response.plannable_locations:
        print(
            f"'{location.name}',\t{location.id},\t{location.parent_country_id}"
        )


def show_plannable_products(client: GoogleAdsClient, location_id: str):
    """Lists plannable products for a given location.

    Args:
        client: an initialized GoogleAdsClient instance.
        location_id: The location ID to plan for.
    """
    reach_plan_service: ReachPlanServiceClient = client.get_service(
        "ReachPlanService"
    )
    response: ListPlannableProductsResponse = (
        reach_plan_service.list_plannable_products(
            plannable_location_id=location_id
        )
    )
    print(f"Plannable Products for Location ID {location_id}")

    product_metadata: ProductMetadata
    for product_metadata in response.product_metadata:
        print(
            f"{product_metadata.plannable_product_code} : "
            f"{product_metadata.plannable_product_name}"
        )

        print("Age Ranges:")
        age_range: ReachPlanAgeRangeEnum
        for age_range in product_metadata.plannable_targeting.age_ranges:
            print(f"\t- {age_range.name}")

        print("Genders:")
        gender: GenderInfo
        for gender in product_metadata.plannable_targeting.genders:
            print(f"\t- {gender.type_.name}")

        print("Devices:")
        device: DeviceInfo
        for device in product_metadata.plannable_targeting.devices:
            print(f"\t- {device.type_.name}")


def request_reach_curve(
    client: GoogleAdsClient,
    customer_id: str,
    product_mix: list[PlannedProduct],
    location_id: str,
    currency_code: str,
):
    """Creates a sample request for a given product mix.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: The customer ID for the reach forecast.
        product_mix: The product mix for the reach forecast.
        location_id: The location ID to plan for.
        currency_code: Three-character ISO 4217 currency code.
    """
    # See the docs for defaults and valid ranges:
    # https://developers.google.com/google-ads/api/reference/rpc/latest/GenerateReachForecastRequest
    request: GenerateReachForecastRequest = client.get_type(
        "GenerateReachForecastRequest"
    )
    request.customer_id = customer_id
    # Valid durations are between 1 and 90 days.
    request.campaign_duration.duration_in_days = 28
    request.currency_code = currency_code
    request.cookie_frequency_cap = 0
    request.min_effective_frequency = 1
    request.planned_products = product_mix

    request.targeting.plannable_location_id = location_id
    request.targeting.age_range = (
        client.enums.ReachPlanAgeRangeEnum.AGE_RANGE_18_65_UP
    )

    # Add gender targeting to the request.
    gender_type: GenderTypeEnum
    for gender_type in [
        client.enums.GenderTypeEnum.FEMALE,
        client.enums.GenderTypeEnum.MALE,
    ]:
        gender: GenderInfo = client.get_type("GenderInfo")
        gender.type_ = gender_type
        request.targeting.genders.append(gender)

    # Add device targeting to the request.
    device_type: DeviceEnum
    for device_type in [
        client.enums.DeviceEnum.DESKTOP,
        client.enums.DeviceEnum.MOBILE,
        client.enums.DeviceEnum.TABLET,
    ]:
        device: DeviceInfo = client.get_type("DeviceInfo")
        device.type_ = device_type
        request.targeting.devices.append(device)

    reach_plan_service: ReachPlanServiceClient = client.get_service(
        "ReachPlanService"
    )
    response: GenerateReachForecastResponse = (
        reach_plan_service.generate_reach_forecast(request=request)
    )

    print(
        "Currency, Cost, On-Target Reach, On-Target Imprs, Total Reach,"
        " Total Imprs, Products"
    )
    point: ReachForecast
    for point in response.reach_curve.reach_forecasts:
        product_splits = []
        p: PlannedProductReachForecast
        for p in point.planned_product_reach_forecasts:
            product_splits.append(
                {p.plannable_product_code: p.cost_micros / ONE_MILLION}
            )
        print(
            [
                currency_code,
                point.cost_micros / ONE_MILLION,
                point.forecast.on_target_reach,
                point.forecast.on_target_impressions,
                point.forecast.total_reach,
                point.forecast.total_impressions,
                product_splits,
            ]
        )


def forecast_manual_mix(
    client: GoogleAdsClient,
    customer_id: str,
    location_id: str,
    currency_code: str,
    budget: int,
):
    """Pulls a forecast for product mix created manually.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: The customer ID for the reach forecast.
        location_id: The location ID to plan for.
        currency_code: Three-character ISO 4217 currency code.
        budget: Budget to allocate to the plan.
    """
    product_mix: list[PlannedProduct] = []
    trueview_allocation = 0.15
    bumper_allocation = 1 - trueview_allocation
    product_splits = [
        ("TRUEVIEW_IN_STREAM", trueview_allocation),
        ("BUMPER", bumper_allocation),
    ]
    product: str
    split: float
    for product, split in product_splits:
        planned_product: PlannedProduct = client.get_type("PlannedProduct")
        planned_product.plannable_product_code = product
        planned_product.budget_micros = math.trunc(budget * ONE_MILLION * split)
        product_mix.append(planned_product)

    request_reach_curve(
        client, customer_id, product_mix, location_id, currency_code
    )


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="Generates video ads reach forecast."
    )
    # The following argument(s) should be provided to run the example.
    parser.add_argument(
        "-c",
        "--customer_id",
        type=str,
        required=True,
        help="The Google Ads customer ID.",
    )
    args = parser.parse_args()

    # GoogleAdsClient will read the google-ads.yaml configuration file in the
    # home directory if none is specified.
    googleads_client = GoogleAdsClient.load_from_storage(version="v21")

    try:
        main(googleads_client, args.customer_id)
    except GoogleAdsException as ex:
        print(
            'Request with ID "{}" failed with status "%s" and includes the '
            "following errors:".format(ex.request_id, ex.error.code().name)
        )
        for error in ex.failure.errors:
            print('\tError with message "{}".'.format(error.message))
            if error.location:
                for field_path_element in error.location.field_path_elements:
                    print(
                        "\t\tOn field: {}".format(field_path_element.field_name)
                    )
        sys.exit(1)

      

Ruby

#!/usr/bin/env ruby
# Encoding: utf-8
#
# Copyright 2020 Google LLC
#
# 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
#
#     https://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.
#
# This example demonstrates how to interact with the ReachPlanService to find
# plannable locations and product codes, build a media plan, and generate a
# video ads reach forecast.

require 'optparse'
require 'google/ads/google_ads'

def forecast_reach(customer_id)
  # GoogleAdsClient will read a config file from
  # ENV['HOME']/google_ads_config.rb when called without parameters
  client = Google::Ads::GoogleAds::GoogleAdsClient.new

  reach_plan_service = client.service.reach_plan

  show_plannable_locations(reach_plan_service)

  show_plannable_products(reach_plan_service)

  forecast_manual_mix(client, reach_plan_service, customer_id)
end

# Shows map of plannable locations to their IDs.
def show_plannable_locations(reach_plan_service)
  response = reach_plan_service.list_plannable_locations()

  puts "Plannable Locations:"
  puts "Name, Id, ParentCountryId"

  response.plannable_locations.each do |location|
    puts "'#{location.name}', #{location.id}, #{location.parent_country_id}"
  end
end

# Lists plannable products for a given location.
def show_plannable_products(reach_plan_service)
  response = reach_plan_service.list_plannable_products(
    plannable_location_id: LOCATION_ID,
  )

  puts "Plannable Products for Location ID #{LOCATION_ID}:"

  response.product_metadata.each do |product|
    puts "#{product.plannable_product_code}:"
    puts "Age Ranges:"
    product.plannable_targeting.age_ranges.each do |age_range|
      puts "\t- #{age_range}"
    end
    puts "Genders:"
    product.plannable_targeting.genders.each do |gender|
      puts "\t- #{gender.type}"
    end
    puts "Devices:"
    product.plannable_targeting.devices.each do |device|
      puts "\t- #{device.type}"
    end
  end
end

# Retrieves and prints the reach curve for a given product mix.
def get_reach_curve(
  client,
  reach_plan_service,
  customer_id,
  product_mix,
  location_id,
  currency_code)
  duration = client.resource.campaign_duration do |d|
    # Valid durations are between 1 and 90 days.
    d.duration_in_days = 28
  end

  targeting = client.resource.targeting do |t|
    t.plannable_location_id = location_id
    t.age_range = :AGE_RANGE_18_65_UP
    t.genders << client.resource.gender_info do |gender|
      gender.type = :FEMALE
    end
    t.genders << client.resource.gender_info do |gender|
      gender.type = :MALE
    end
    t.devices << client.resource.device_info do |device|
      device.type = :DESKTOP
    end
    t.devices << client.resource.device_info do |device|
      device.type = :MOBILE
    end
    t.devices << client.resource.device_info do |device|
      device.type = :TABLET
    end
  end

  # See the docs for defaults and valid ranges:
  # https://developers.google.com/google-ads/api/reference/rpc/latest/GenerateReachForecastRequest
  response = reach_plan_service.generate_reach_forecast(
    customer_id: customer_id,
    campaign_duration: duration,
    planned_products: product_mix,
    currency_code: currency_code,
    targeting: targeting,
  )

  puts "Reach curve output:"
  puts "Currency, Cost Micros, On-Target Reach, On-Target Imprs, " \
    "Total Reach, Total Imprs, Products"

  response.reach_curve.reach_forecasts.each do |point|
    products = ""
    point.planned_product_reach_forecasts.each do |product|
      products += "(Product: #{product.plannable_product_code}, "\
        "Cost Micros: #{product.cost_micros})"
    end
    puts "#{currency_code}, #{point.cost_micros}, " \
      "#{point.forecast.on_target_reach}, " \
      "#{point.forecast.on_target_impressions}, " \
      "#{point.forecast.total_reach}, " \
      "#{point.forecast.total_impressions}, " \
      "#{products}"
  end
end

# Gets a forecast for product mix created manually.
def forecast_manual_mix(client, reach_plan_service, customer_id)
  # Set up a ratio to split the budget between two products.
  trueview_allocation = 0.15
  bumper_allocation = 1 - trueview_allocation

  # See listPlannableProducts on ReachPlanService to retrieve a list
  # of valid PlannableProductCode's for a given location:
  # https://developers.google.com/google-ads/api/reference/rpc/latest/ReachPlanService
  product_mix = []

  product_mix << client.resource.planned_product do |p|
    p.plannable_product_code = 'TRUEVIEW_IN_STREAM'
    p.budget_micros = BUDGET_MICROS * trueview_allocation
  end

  product_mix << client.resource.planned_product do |p|
    p.plannable_product_code = 'BUMPER'
    p.budget_micros = BUDGET_MICROS * bumper_allocation
  end

  get_reach_curve(
    client,
    reach_plan_service,
    customer_id,
    product_mix,
    LOCATION_ID,
    CURRENCY_CODE,
  )
end

if __FILE__ == $0
  CUSTOMER_ID = 'INSERT_CUSTOMER_ID_HERE';
  CURRENCY_CODE = 'USD';
  # You can get a valid location ID from
  # https://developers.google.com/adwords/api/docs/appendix/geotargeting
  # or by calling list_plannable_locations on the reach_plan service.
  LOCATION_ID = '2840'; # US
  BUDGET_MICROS = 5_000_000; # 5

  options = {}
  # The following parameter(s) should be provided to run the example. You can
  # either specify these by changing the INSERT_XXX_ID_HERE values below, or on
  # the command line.
  #
  # Parameters passed on the command line will override any parameters set in
  # code.
  #
  # Running the example with -h will print the command line usage.
  options[:customer_id] = 'INSERT_CUSTOMER_ID_HERE'

  OptionParser.new do |opts|
    opts.banner = sprintf('Usage: %s [options]', File.basename(__FILE__))

    opts.separator ''
    opts.separator 'Options:'

    opts.on('-C', '--customer-id CUSTOMER-ID', String, 'Customer ID') do |v|
      options[:customer_id] = v
    end

    opts.separator ''
    opts.separator 'Help:'

    opts.on_tail('-h', '--help', 'Show this message') do
      puts opts
      exit
    end
  end.parse!

  begin
    forecast_reach(options.fetch(:customer_id).tr("-", ""))
  rescue Google::Ads::GoogleAds::Errors::GoogleAdsError => e
    e.failure.errors.each do |error|
      STDERR.printf("Error with message: %s\n", error.message)
      if error.location
        error.location.field_path_elements.each do |field_path_element|
          STDERR.printf("\tOn field: %s\n", field_path_element.field_name)
        end
      end
      error.error_code.to_h.each do |k, v|
        next if v == :UNSPECIFIED
        STDERR.printf("\tType: %s\n\tCode: %s\n", k, v)
      end
    end
    raise
  end
end

      

Perl

#!/usr/bin/perl -w
#
# Copyright 2019, Google LLC
#
# 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.
#
# This example demonstrates how to interact with the ReachPlanService to find
# plannable locations and product codes, build a media plan, and generate a video
# ads reach forecast.

use strict;
use warnings;
use utf8;

use FindBin qw($Bin);
use lib "$Bin/../../lib";
use Google::Ads::GoogleAds::Client;
use Google::Ads::GoogleAds::Utils::GoogleAdsHelper;
use Google::Ads::GoogleAds::V21::Common::GenderInfo;
use Google::Ads::GoogleAds::V21::Common::DeviceInfo;
use Google::Ads::GoogleAds::V21::Enums::ReachPlanAdLengthEnum
  qw(FIFTEEN_OR_TWENTY_SECONDS);
use Google::Ads::GoogleAds::V21::Enums::GenderTypeEnum qw(MALE FEMALE);
use Google::Ads::GoogleAds::V21::Enums::DeviceEnum qw(DESKTOP MOBILE TABLET);
use Google::Ads::GoogleAds::V21::Enums::ReachPlanAgeRangeEnum
  qw(AGE_RANGE_18_65_UP);
use Google::Ads::GoogleAds::V21::Services::ReachPlanService::PlannedProduct;
use Google::Ads::GoogleAds::V21::Services::ReachPlanService::CampaignDuration;
use Google::Ads::GoogleAds::V21::Services::ReachPlanService::Targeting;
use
  Google::Ads::GoogleAds::V21::Services::ReachPlanService::GenerateReachForecastRequest;

use Getopt::Long qw(:config auto_help);
use Pod::Usage;
use Cwd qw(abs_path);

# The following parameter(s) should be provided to run the example. You can
# either specify these by changing the INSERT_XXX_ID_HERE values below, or on
# the command line.
#
# Parameters passed on the command line will override any parameters set in
# code.
#
# Running the example with -h will print the command line usage.
my $customer_id = "INSERT_CUSTOMER_ID_HERE";

sub forecast_reach {
  my ($api_client, $customer_id) = @_;

  # Location ID to plan for. You can get a valid location ID from
  # https://developers.google.com/google-ads/api/reference/data/geotargets or by
  # calling list_plannable_locations on the ReachPlanService.
  # Location ID 2840 is for USA.
  my $location_id   = "2840";
  my $currency_code = "USD";
  my $budget_micros = 500_000_000_000;

  my $reach_plan_service = $api_client->ReachPlanService();

  show_plannable_locations($reach_plan_service);
  show_plannable_products($reach_plan_service, $location_id);
  forecast_mix(
    $reach_plan_service, $customer_id, $location_id,
    $currency_code,      $budget_micros
  );

  return 1;
}

# Maps friendly names of plannable locations to location IDs usable with
# ReachPlanService.
sub show_plannable_locations {
  my ($reach_plan_service) = @_;

  my $response = $reach_plan_service->list_plannable_locations();

  print "Plannable Locations:\n";
  print "Name,\tId,\tParentCountryId\n";
  foreach my $location (@{$response->{plannableLocations}}) {
    printf "'%s',\t%s,\t%d\n", $location->{name}, $location->{id},
      $location->{parentCountryId} ? $location->{parentCountryId} : 0;
  }
}

# Lists plannable products for a given location.
sub show_plannable_products {
  my ($reach_plan_service, $location_id) = @_;

  my $response = $reach_plan_service->list_plannable_products({
    plannableLocationId => $location_id
  });

  printf "Plannable Products for location %d:\n", $location_id;
  foreach my $product (@{$response->{productMetadata}}) {
    printf "%s : '%s'\n", $product->{plannableProductCode},
      $product->{plannableProductName};
    print "Age Ranges:\n";
    foreach my $age_range (@{$product->{plannableTargeting}{ageRanges}}) {
      printf "\t- %s\n", $age_range;
    }
    print "Genders:\n";
    foreach my $gender (@{$product->{plannableTargeting}{genders}}) {
      printf "\t- %s\n", $gender->{type};
    }
    print "Devices:\n";
    foreach my $device (@{$product->{plannableTargeting}{devices}}) {
      printf "\t- %s\n", $device->{type};
    }
  }
}

# Pulls a forecast for a budget split 15% and 85% between two products.
sub forecast_mix {
  my (
    $reach_plan_service, $customer_id, $location_id,
    $currency_code,      $budget_micros
  ) = @_;

  my $product_mix = [];

  # Set up a ratio to split the budget between two products.
  my $trueview_allocation = 0.15;
  my $bumper_allocation   = 1 - $trueview_allocation;

  # See list_plannable_products on ReachPlanService to retrieve a list of valid
  # plannable product codes for a given location:
  # https://developers.google.com/google-ads/api/reference/rpc/latest/ReachPlanService
  push @$product_mix,
    Google::Ads::GoogleAds::V21::Services::ReachPlanService::PlannedProduct->
    new({
      plannableProductCode => "TRUEVIEW_IN_STREAM",
      budgetMicros         => int($budget_micros * $trueview_allocation)});
  push @$product_mix,
    Google::Ads::GoogleAds::V21::Services::ReachPlanService::PlannedProduct->
    new({
      plannableProductCode => "BUMPER",
      budgetMicros         => int($budget_micros * $bumper_allocation)});

  my $reach_request =
    build_reach_request($customer_id, $product_mix, $location_id,
    $currency_code);

  pull_reach_curve($reach_plan_service, $reach_request);
}

# Create a base request to generate a reach forecast.
sub build_reach_request {
  my ($customer_id, $product_mix, $location_id, $currency_code) = @_;

  # Valid durations are between 1 and 90 days.
  my $duration =
    Google::Ads::GoogleAds::V21::Services::ReachPlanService::CampaignDuration->
    new({
      durationInDays => 28
    });

  my $genders = [
    Google::Ads::GoogleAds::V21::Common::GenderInfo->new({
        type => FEMALE
      }
    ),
    Google::Ads::GoogleAds::V21::Common::GenderInfo->new({
        type => MALE
      })];

  my $devices = [
    Google::Ads::GoogleAds::V21::Common::DeviceInfo->new({
        type => DESKTOP
      }
    ),
    Google::Ads::GoogleAds::V21::Common::DeviceInfo->new({
        type => MOBILE
      }
    ),
    Google::Ads::GoogleAds::V21::Common::DeviceInfo->new({
        type => TABLET
      })];

  my $targeting =
    Google::Ads::GoogleAds::V21::Services::ReachPlanService::Targeting->new({
      plannableLocationId => $location_id,
      ageRange            => AGE_RANGE_18_65_UP,
      genders             => $genders,
      devices             => $devices
    });

  # See the docs for defaults and valid ranges:
  # https://developers.google.com/google-ads/api/reference/rpc/latest/GenerateReachForecastRequest
  return
    Google::Ads::GoogleAds::V21::Services::ReachPlanService::GenerateReachForecastRequest
    ->new({
      customerId            => $customer_id,
      currencyCode          => $currency_code,
      campaignDuration      => $duration,
      cookieFrequencyCap    => 0,
      minEffectiveFrequency => 1,
      targeting             => $targeting,
      plannedProducts       => $product_mix
    });
}

# Pulls and prints the reach curve for the given request.
sub pull_reach_curve {
  my ($reach_plan_service, $reach_request) = @_;

  my $response = $reach_plan_service->generate_reach_forecast($reach_request);
  print "Reach curve output:\n";
  print "Currency,\tCost Micros,\tOn-Target Reach,\tOn-Target Imprs,\t" .
    "Total Reach,\tTotal Imprs,\tProducts\n";
  foreach my $point (@{$response->{reachCurve}{reachForecasts}}) {
    printf "%s,\t%d,\t%d,\t%d,\t%d,\t%d,\t'[", $reach_request->{currencyCode},
      $point->{costMicros}, $point->{forecast}{onTargetReach},
      $point->{forecast}{onTargetImpressions}, $point->{forecast}{totalReach},
      $point->{forecast}{totalImpressions};
    foreach my $productReachForecast (@{$point->{plannedProductReachForecasts}})
    {
      printf "(Product: %s, Budget Micros: %d), ",
        $productReachForecast->{plannableProductCode},
        $productReachForecast->{costMicros};
    }
    print "]'\n";
  }
}

# Don't run the example if the file is being included.
if (abs_path($0) ne abs_path(__FILE__)) {
  return 1;
}

# Get Google Ads Client, credentials will be read from ~/googleads.properties.
my $api_client = Google::Ads::GoogleAds::Client->new();

# By default examples are set to die on any server returned fault.
$api_client->set_die_on_faults(1);

# Parameters passed on the command line will override any parameters set in code.
GetOptions("customer_id=s" => \$customer_id);

# Print the help message if the parameters are not initialized in the code nor
# in the command line.
pod2usage(2) if not check_params($customer_id);

# Call the example.
forecast_reach($api_client, $customer_id =~ s/-//gr);

=pod

=head1 NAME

forecast_reach

=head1 DESCRIPTION

This example demonstrates how to interact with the ReachPlanService to find plannable
locations and product codes, build a media plan, and generate a video ads reach forecast.

=head1 SYNOPSIS

forecast_reach.pl [options]

    -help                       Show the help message.
    -customer_id                The Google Ads customer ID.

=cut