Google offers a variety of products and audiences you can use to build
campaigns, though you might not know how to formulate a plan. To help with
this, ReachPlanService
provides discovery
methods you can use to generate a
curve.
Audience targeting
The first component of a media plan is audience targeting, which can include the following target criteria:
- Audiences
- Reference
AudienceTargeting
. - Age Ranges
- Reference the
ReachPlanAgeRange
enum. - Genders
- Reference the
GenderInfo
criterion. - Devices
- Reference the
DeviceInfo
criterion. - Locations
- Use the
ListPlannableLocations
method to find supported location IDs. - Networks
- Use the
ListPlannableLocations
method to find applicable networks, which may vary by product and region.
Product mix
In addition to the targeting information, you must specify a product mix in order to generate a curve.
The ListPlannableProducts
method on ReachPlanService
shows the
latest available formats for a given location ID, represented by the
plannable_product_code
and
plannable_product_name
fields of ProductMetadata
. Keep in mind
that these values change periodically, so it is best to provide your users with
live results rather than persisting responses offline.
Here is a code example of how to get the product mix for some target criteria:
Java
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()); } } }
C#
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}"); } } }
PHP
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); } } }
Python
def show_plannable_products(client, location_id): """Lists plannable products for a given location. Args: client: an initialized GoogleAdsClient instance. location_id: The location ID to plan for. """ reach_plan_service = client.get_service("ReachPlanService") response = reach_plan_service.list_plannable_products( plannable_location_id=location_id ) print(f"Plannable Products for Location ID {location_id}") for product_metadata in response.product_metadata: print( f"{product_metadata.plannable_product_code} : " f"{product_metadata.plannable_product_name}" ) print("Age Ranges:") for age_range in product_metadata.plannable_targeting.age_ranges: print(f"\t- {age_range.name}") print("Genders:") for gender in product_metadata.plannable_targeting.genders: print(f"\t- {gender.type_.name}") print("Devices:") for device in product_metadata.plannable_targeting.devices: print(f"\t- {device.type_.name}")
Ruby
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
Perl
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}; } } }
To generate a curve you would then assign a budget to each product:
Java
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#
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
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 ); }
Python
def forecast_manual_mix( client, customer_id, location_id, currency_code, budget ): """Pulls a forecast for product mix created manually. 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. budget: Budget to allocate to the plan. """ product_mix = [] trueview_allocation = 0.15 bumper_allocation = 1 - trueview_allocation product_splits = [ ("TRUEVIEW_IN_STREAM", trueview_allocation), ("BUMPER", bumper_allocation), ] for product, split in product_splits: planned_product = 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 )
Ruby
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
Perl
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::V17::Services::ReachPlanService::PlannedProduct-> new({ plannableProductCode => "TRUEVIEW_IN_STREAM", budgetMicros => int($budget_micros * $trueview_allocation)}); push @$product_mix, Google::Ads::GoogleAds::V17::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); }
This is also when you can set
advanced_product_targeting
for YouTube Select Lineups.
Reach forecast request fields
You must set the customer_id
, campaign_duration
, and planned_products
fields for each
GenerateReachForecastRequest
.
You can also set the following optional fields:
Field | Description |
---|---|
cookie_frequency_cap_setting |
The maximum number of times an ad can be shown to the same user during a specified time interval. This cap can be defined as a limit per one day, one week, or one month. |
currency_code |
Three-character ISO 4217 currency code. |
customer_reach_group |
The name of the customer being planned for. This is a user-defined value. Required if targeting.audience_targeting is set. |
min_effective_frequency |
Minimum number of times a person was exposed to the ad for the reported reach metrics. |
targeting |
The targeting to be applied to all products selected in the product mix, including location, age range, genders, devices, and network. |