Reminder: v201611 will be sunset on November 30, 2017.

Forecasting Basics

Introduction

This guide explains the ForecastService and outlines how to use the two different types of forecasts: availability and delivery.

Before you start working with the ForecastService, it's important to have a solid understanding of forecasting in DFP.

Availability forecasts

An availability forecast reports the maximum number of available units with which the line item can be booked. This forecast is analogous to the check inventory feature in the UI.

The forecast includes the available, matched, possible, delivered, and reserved units. It can also include all the contending line items and the available units for each targeting breakdown depending on the options set in the AvailabilityForecastOptions. By default, neither is included in the forecast.

Targeting breakdowns include the matched and available units for each targeting criteria. These breakdown entries are automatically generated according to the line item targeting. For example, a line item targeted at ad unit ID 123456 would include a breakdown similar to the following:

<targetingCriteriaBreakdowns>
  <targetingDimension>AD_UNIT</targetingDimension>
  <targetingCriteriaId>123456</targetingCriteriaId>
  <targetingCriteriaName>My Ad Unit Name</targetingCriteriaName>
   <excluded>false</excluded>
   <availableUnits>1000</availableUnits>
   <matchedUnits>2300</matchedUnits>
</targetingCriteriaBreakdowns>

You can run availability forecasts on either an existing or prospective line item.

Existing LineItem

You can run an availability forecast for an existing line item by using its ID.

Java


  // Get the ForecastService.
  ForecastServiceInterface forecastService =
      dfpServices.get(session, ForecastServiceInterface.class);

  // Get forecast for line item.
  AvailabilityForecastOptions options = new AvailabilityForecastOptions();
  options.setIncludeContendingLineItems(true);
  options.setIncludeTargetingCriteriaBreakdown(true);
  AvailabilityForecast forecast =
      forecastService.getAvailabilityForecastById(lineItemId, options);

  long matched = forecast.getMatchedUnits();
  double availablePercent = (forecast.getAvailableUnits() / (matched * 1.0)) * 100;
  String unitType = forecast.getUnitType().toString().toLowerCase();

  System.out.printf("%d %s matched.%n", matched, unitType);
  System.out.printf("%.2f%% %s available.%n", availablePercent, unitType);

  if (forecast.getPossibleUnits() != null) {
    double possiblePercent = (forecast.getPossibleUnits() / (matched * 1.0)) * 100;
    System.out.printf("%.2f%% %s possible.%n", possiblePercent, unitType);
  }

  System.out.printf("%d contending line items.%n",
      forecast.getContendingLineItems() == null ? 0 : forecast.getContendingLineItems().length);
    

Python


  # Initialize appropriate service.
  forecast_service = client.GetService('ForecastService', version='v201702')

  # Set forecasting options.
  forecast_options = {
      'includeContendingLineItems': True,
      'includeTargetingCriteriaBreakdown': True,
  }

  # Get forecast for line item.
  forecast = forecast_service.getAvailabilityForecastById(
      line_item_id, forecast_options)
  matched = long(forecast['matchedUnits'])
  available_percent = (((long(forecast['availableUnits'])/
                         (matched * 1.0)) * 100)
                       if matched != 0 else 0)
  contending_line_items = ([] if 'contendingLineItems' not in forecast
                           else forecast['contendingLineItems'])

  # Display results.
  print '%s %s matched.' % (matched, forecast['unitType'].lower())
  print '%s%% %s available.' % (available_percent, forecast['unitType'].lower())
  print '%d contending line items.' % len(contending_line_items)

  if 'possibleUnits' in forecast and matched:
    possible_percent = (long(forecast['possibleUnits'])/(matched * 1.0)) * 100
    print '%s%% %s possible' % (possible_percent, forecast['unitType'].lower())
    

PHP


  $forecastService = $dfpServices->get($session, ForecastService::class);

  // Get forecast for line item.
  $options = new AvailabilityForecastOptions();
  $options->setIncludeContendingLineItems(true);
  $options->setIncludeTargetingCriteriaBreakdown(true);
  $forecast = $forecastService->getAvailabilityForecastById(
      $lineItemId, $options);

  // Print out forecast results.
  $matchedUnits = $forecast->getMatchedUnits();
  $unitType = strtolower($forecast->getUnitType());
  printf("%d %s matched.\n", $matchedUnits, $unitType);

  if ($matchedUnits > 0) {
    $percentAvailableUnits =
        $forecast->getAvailableUnits() / $matchedUnits * 100;
    $percentPossibleUnits =
        $forecast->getPossibleUnits() / $matchedUnits * 100;
    printf("%.2d%% %s available.\n", $percentAvailableUnits, $unitType);
    printf("%.2d%% %s possible.\n", $percentPossibleUnits, $unitType);
  }

  printf("%d contending line items.\n",
      count($forecast->getContendingLineItems()));
    

C#


  // Get the ForecastService.
  ForecastService forecastService =
      (ForecastService) user.GetService(DfpService.v201702.ForecastService);
  // Get forecast for line item.
  AvailabilityForecastOptions options = new AvailabilityForecastOptions();
  options.includeContendingLineItems = true;
  options.includeTargetingCriteriaBreakdown = true;
  AvailabilityForecast forecast =
      forecastService.getAvailabilityForecastById(lineItemId, options);

  // Display results.
  long matched = forecast.matchedUnits;
  double availablePercent = (double) (forecast.availableUnits / (matched * 1.0)) * 100;
  String unitType = forecast.unitType.ToString().ToLower();

  Console.WriteLine("{0} {1} matched.\n{2} % {3} available.", matched, unitType,
      availablePercent, unitType);
  if (forecast.possibleUnitsSpecified) {
    double possiblePercent = (double) (forecast.possibleUnits / (matched * 1.0)) * 100;
    Console.WriteLine(possiblePercent + "% " + unitType + " possible.\n");
  }
  Console.WriteLine("{0} contending line items.", (forecast.contendingLineItems != null)?
      forecast.contendingLineItems.Length : 0);
    

Ruby


  # Get the ForecastService.
  forecast_service = dfp.service(:ForecastService, API_VERSION)
  # Set forecasting options.
  forecast_options = {
    :include_contending_line_items => True,
    :include_targeting_criteria_breakdown => True,
  }

  # Get forecast for the line item.
  forecast = forecast_service.get_availability_forecast_by_id(
      line_item_id, forecast_options)

  if forecast
    # Display results.
    matched = forecast[:matched_units]
    available_percent = forecast[:available_units] * 100.0 / matched
    unit_type = forecast[:unit_type].to_s.downcase
    puts "%.2f %s matched." % [matched, unit_type]
    puts "%.2f%% %s available." % [available_percent, unit_type]
    puts "%d contending line items." % forecast[:contending_line_items].size
    if forecast[:possible_units]
      possible_percent = forecast[:possible_units] * 100.0 / matched
      puts "%.2f%% %s possible." % [possible_percent, unit_type]
    end
  end
    

This example will have an output similar to the following:

100 clicks matched.
2 contending line items.

Prospective LineItem

Alternatively, you can create a prospective line item and forecast without persisting it. To do so, create a local line item and set it on the ProspectiveLineItem. If you set an advertiser ID, the forecast also takes unified blocking rules into account.

Java


  // Get forecast for prospective line item.
  ProspectiveLineItem prospectiveLineItem = new ProspectiveLineItem();
  prospectiveLineItem.setAdvertiserId(advertiserId);
  prospectiveLineItem.setLineItem(lineItem);
  AvailabilityForecastOptions options  = new AvailabilityForecastOptions();
  options.setIncludeContendingLineItems(true);
  options.setIncludeTargetingCriteriaBreakdown(true);

  AvailabilityForecast forecast = 
      forecastService.getAvailabilityForecast(prospectiveLineItem, options);
    

Python


  prospective_line_item = {
      'lineItem': line_item,
      'advertiserId': advertiser_id
  }

  # Set forecasting options.
  forecast_options = {
      'includeContendingLineItems': True,
      'includeTargetingCriteriaBreakdown': True,
  }

  # Get forecast.
  forecast = forecast_service.getAvailabilityForecast(
      prospective_line_item, forecast_options)
    

PHP


  // Get forecast for prospective line item.
  $prospectiveLineItem = new ProspectiveLineItem();
  $prospectiveLineItem->setAdvertiserId($advertiserId);
  $prospectiveLineItem->setLineItem($lineItem);
  $options = new AvailabilityForecastOptions();
  $options->setIncludeContendingLineItems(true);
  $options->setIncludeTargetingCriteriaBreakdown(true);

  $forecast = $forecastService->getAvailabilityForecast(
      $prospectiveLineItem, $options);
    

C#


  // Get availability forecast.
  AvailabilityForecastOptions options = new AvailabilityForecastOptions();
  options.includeContendingLineItems = true;
  options.includeTargetingCriteriaBreakdown = true;
  ProspectiveLineItem prospectiveLineItem = new ProspectiveLineItem();
  prospectiveLineItem.advertiserId = advertiserId;
  prospectiveLineItem.lineItem = lineItem;
  AvailabilityForecast forecast =
      forecastService.getAvailabilityForecast(prospectiveLineItem, options);
    

Ruby


  prospective_line_item = {
    :advertiser_id => advertiser_id,
    :line_item => line_item
  }

  # Set forecasting options.
  forecast_options = {
    :include_contending_line_items => True,
    :include_targeting_criteria_breakdown => True,
  }

  # Get forecast for the line item.
  forecast = forecast_service.get_availability_forecast(
      prospective_line_item, forecast_options)
    

Delivery forecasts

If you want to simulate the delivery of multiple competing line items, you can do so with a DeliveryForecast. This is similar to sales management forecasting in the UI.

Existing LineItems

You can run a delivery forecast for existing line items by using their IDs.

Java


  // Get the ForecastService.
  ForecastServiceInterface forecastService =
      dfpServices.get(session, ForecastServiceInterface.class);

  DeliveryForecastOptions options = new DeliveryForecastOptions();
      
  DeliveryForecast forecast = forecastService.getDeliveryForecastByIds(
      new long[] {lineItemId1, lineItemId2}, options);

  for (LineItemDeliveryForecast lineItemForecast : forecast.getLineItemDeliveryForecasts()) {
    String unitType = lineItemForecast.getUnitType().toString().toLowerCase();
    System.out.printf("Forecast for line item %d:%n", lineItemForecast.getLineItemId());
    System.out.printf("\t%d %s matched%n", lineItemForecast.getMatchedUnits(), unitType);
    System.out.printf("\t%d %s delivered%n", lineItemForecast.getDeliveredUnits(), unitType);
    System.out.printf("\t%d %s predicted%n",
        lineItemForecast.getPredictedDeliveryUnits(), unitType);
  }
    

Python


  # Initialize appropriate service.
  forecast_service = client.GetService('ForecastService', version='v201702')

  # Get forecast for line item.
  forecast = forecast_service.getDeliveryForecastByIds(
      [line_item_id1, line_item_id2], None)

  for single_forecast in forecast['lineItemDeliveryForecasts']:
    unit_type = single_forecast['unitType']
    print ('Forecast for line item %d:\n\t%d %s matched\n\t%d %s delivered\n\t'
           '%d %s predicted\n' % (
               single_forecast['lineItemId'], single_forecast['matchedUnits'],
               unit_type, single_forecast['deliveredUnits'], unit_type,
               single_forecast['predictedDeliveryUnits'], unit_type))


if __name__ == '__main__':
  # Initialize client object.
  dfp_client = dfp.DfpClient.LoadFromStorage()
  main(dfp_client, LINE_ITEM_ID_1, LINE_ITEM_ID_2)

    

PHP


  $forecastService = $dfpServices->get($session, ForecastService::class);

  // Get forecast for the line items with no options set.
  $forecast = $forecastService->getDeliveryForecastByIds(
      [$lineItemId1, $lineItemId2], new DeliveryForecastOptions());

  // Print out forecast results.
  foreach ($forecast->getLineItemDeliveryForecasts() as $lineItemForecast) {
    $unitType = strtolower($lineItemForecast->getUnitType());
    printf("Forecast for line item ID %d:\n",
        $lineItemForecast->getLineItemId());
    printf("    %d %s matched\n",
        $lineItemForecast->getMatchedUnits(), $unitType);
    printf("    %d %s delivered\n",
        $lineItemForecast->getDeliveredUnits(), $unitType);
    printf("    %d %s predicted\n",
        $lineItemForecast->getPredictedDeliveryUnits(), $unitType);
  }
    

C#


  // Get the ForecastService.
  ForecastService forecastService =
      (ForecastService) user.GetService(DfpService.v201702.ForecastService);
  // Get a delivery forecast for the line items.
  DeliveryForecastOptions options = new DeliveryForecastOptions();
  options.ignoredLineItemIds = new long[]{};
  DeliveryForecast forecast = forecastService.getDeliveryForecastByIds(
      new long[] {lineItemId1, lineItemId2}, options);

  // Display results.
  foreach (LineItemDeliveryForecast lineItemForecast in forecast.lineItemDeliveryForecasts) {
    String unitType = lineItemForecast.unitType.GetType().Name.ToLower();
    Console.WriteLine("Forecast for line item {0}:", lineItemForecast.lineItemId);
    Console.WriteLine("\t{0} {1} matched", lineItemForecast.matchedUnits, unitType);
    Console.WriteLine("\t{0} {1} delivered", lineItemForecast.deliveredUnits, unitType);
    Console.WriteLine("\t{0} {1} predicted", lineItemForecast.predictedDeliveryUnits,
        unitType);
  }
    

Ruby


  # Get the ForecastService.
  forecast_service = dfp.service(:ForecastService, API_VERSION)
  # Get forecast for the line item.
  forecast = forecast_service.get_delivery_forecast_by_ids(
      [line_item_id1, line_item_id2], nil)

  if forecast
    forecast[:line_item_delivery_forecasts].each do |single_forecast|
      # Display results.
      unit_type = single_forecast[:unit_type]
      puts ('Forecast for line item %d:\n\t%d %s matched\n\t%d %s ' +
            'delivered\n\t%d %s predicted\n') % [
                single_forecast[:line_item_id], single_forecast[:matched_units],
                unit_type, single_forecast[:delivered_units], unit_type,
                single_forecast[:predicted_delivery_units], unit_type]
    end
  end
    

This example will have an output similar to the following:

Forecast for line item 14678:
    100 clicks matched
    0 clicks delivered
    98 clicks predicted

If you want to exclude any line items from the delivery simulation, you can do so by setting their IDs in the DeliveryForecastOptions.

Prospective LineItems

Similar to the availability forecasts, you can run delivery forecasts on line items that are not persisted. To do so, use ProspectiveLineItem objects in the ForecastService.getDeliveryForecast method.

FAQ

I have a lot of line items for which I want to forecast availability. Can I run multiple forecasts in one request?

No. You must make a separate availability forecast request for each line item or prospective line item.

I ran a number of forecasts and now I'm getting EXCEEDED_QUOTA errors. What gives?

Forecasts are computationally expensive, and the quota system ensures the service is reliable. You can safely wait and retry any forecasts that resulted in a quota error.

What causes NO_FORECAST_YET or NOT_ENOUGH_INVENTORY errors?

Forecasts are run based on your network's traffic history. Sometimes, there's not enough historical data to run a forecast. For more details on these errors, see the ForecastError documentation.

What's an AlternativeUnitTypeForecast?

Sometimes it's useful to know what other inventory is available. For example, when forecasting for a CPC line item, the alternative unit type forecasts will include information about the number of impressions.

I have more questions about DFP forecasting in general.

See if they're covered in the product FAQ, or ask in our developer forum.

Send feedback about...

DoubleClick for Publishers
DoubleClick for Publishers
Need help? Visit our support page.