Tag Archives: dfp_api

Filtering report data by custom targeting key ID in the DFP API

A lot of our DFP API developers have been asking recently about how to filter report data by custom targeting key ID. Currently the DFP API allows you to filter report data by custom targeting value ID only. Until we have official support for filtering by custom targeting key ID in reports, you can use the CustomTargetingService and the ReportService together to achieve this goal.

Step 1: Use CustomTargetingService to get your keys and values

You will first need to use getCustomTargetingValuesByStatement and filter by the custom targeting keys you’re interested in to obtain all the corresponding values. For example:

    WHERE customTargetingKeyId IN (17, 18, 19)

If you have a lot of keys and values in your network, a better approach is to store these in a local database and do nightly syncs. Use getCustomTargetingKeysByStatement to obtain all the keys in your network, and then iterate through them, calling getCustomTargetingValuesByStatement for each key to obtain their values. Our client libraries all have examples of this. For instance, the Java example can be found in our ads Java client library GitHub repository. This way, you can look up the values associated with a custom targeting key more quickly and not do an additional API call.

Step 2: Use the values in a report query

Once you have the values for the custom targeting key you’re interested in, you can then use the ReportQuery.statement with the PQL IN clause to filter on the CUSTOM_TARGETING_VALUE_ID dimension. For example, say you were interested in filtering on custom targeting key ID of 7777. You look up the values of 7777 in Step 1, which gives you three value IDs: 3211, 88990, 123456. You can then use the IDs to effectively filter your report data by custom targeting key ID 7777.

    WHERE CUSTOM_TARGETING_VALUE_ID IN (3211, 88990, 123456)

However, please be aware that if you have a lot of custom targeting value IDs to filter on, you should batch them by querying for no more than 500 IDs at a time in the PQL IN clause. For example, you will run your report filtering on the first 500 IDs you’ve collected and save that report. Then you will run the same report on the next page of 500 IDs you’ve collected and so on until you have no more IDs. You can then combine the reports locally so that you have all the data for those custom targeting IDs.

If you have any questions about this, feel free to drop us a line on the DFP API forums or Ads Developer Google+ page.

Announcing the release of DFP API v201411

Today we are releasing v201411 of the DFP API. This release supports creating and updating VideoRedirectCreatives, enhances cross-sell via the new SharedAdUnitService, and adds an experimental Targeting field to the Line_Item PQL table. There are also new Sales Manager enhancements, including derived custom criteria on proposal line items and PQL filtering for Product.lastModifiedDateTime. A detailed list of these and other changes can be found on our release notes page.

Creating VideoRedirectCreatives

You can now use the DFP API to create and update externally hosted and YouTube hosted VideoRedirectCreatives. Simply set the VideoRedirectAsset.redirectUrl to the YouTube or third party URL hosting your ad:

    videoRedirectAsset.setRedirectUrl("http://0.thirdpartyadserver.com/ad.mp4")

You will also need to set the VideoMetadata information for both externally hosted and YouTube hosted ads. For streaming videos, set the minimumBitRate and maximumBitRate; for progressive videos, use the static bitRate.

Custom targeting filter changes

In DFP API v201411 CustomTargetingService.getCustomTargetingKeysByStatement and CustomTargetingService.getCustomTargetingValuesByStatement will return INACTIVE keys and INACTIVE values, respectively. You can filter them by supplying a where clause in a PQL statement:

    WHERE status = 'ACTIVE'

LineItem status changes

To better match the UI, ComputedStatus.NEEDS_CREATIVES has been renamed to ComputedStatus.INACTIVE. Use LineItem.isMissingCreatives to determine if the line item needs creatives.

Cross selling features

If your network is connected to a cross selling host, you can manage your shared ad units with the SharedAdUnitService. To determine if an AdUnit is shared, use the new isSharedByDistributor and crossSellingDistributor fields. We've also added a skipCrossSellingRuleWarningChecks field to the LineItem object so you can override any cross selling warnings.

Experimental targeting PQL column

We've heard your feedback and are adding an experimental PQL column for line item targeting. Fair warning: experimental means we may make breaking changes as we get your feedback and make improvements. The targeting column will be returned with a Value.Type of "TargetingValue", and the value itself containing a Targeting object:

    <Value.Type>TargetingValue</Value.Type>
<value>
<inventoryTargeting>
<targetedAdUnits>
<adUnitId>33985943</adUnitId>
<includeDescendants>true</includeDescendants>
</targetedAdUnits>
</inventoryTargeting>
</value>

If you've been waiting for a faster way to retrieve line item targeting, try it out and let us know what you think. Head over to the API forum and tell us what works for you, and how we can improve.

Minimum Java version requirement changes to client library for AdWords, AdX, DFP and DFA

Are you using the Google Ads API Java Client Library and Java 5 (1.5)? If so, we have important news: starting April 2015, all releases of the Google Ads API Java Client Library will only be compatible with Java 1.6 and higher.

Why this change is happening
The primary reasons for this change are: Next steps
If you are using Java 6 or higher, then you're all set -- all releases of the client library on github already support your runtime.

If you are still using Java 5 and need to migrate to Java 6 or higher, check out the following adoption guides from Oracle: Still have questions? Feel free to file an issue on the library's issues page or contact us via our Google+ page.

AdsPyGoogle Sunset on January, 5 2015

As an avid reader of this blog, you have undoubtedly already seen the announcement that our dear old friend, the client library known as ‘AdsPyGoogle,’ will be sunset on January 5, 2015. Yes—we too at Google are very sad about this.

Fret not! In its place, we have a more than capable replacement in the form of our new GoogleAds Python client library which is more lightweight, has far fewer dependencies, boasts improved utilities and functionality, and perhaps most importantly, supports Python 2.7 as well as 3.x.

If you need a starting point on how to perform this switch, we have a blog post detailing the differences between the two, as well as a nifty migration guide on Github.

As usual, if you have any questions, feedback, or comments, please don’t hesitate to reach out on the DFP or AdWords forums.

Life of a DFP Video Line Item Part I

Your DFP network is already serving thousands of image, text, and custom ads. But now you want to start monetizing your video content. This two-part blog post will get you started with video ads. We'll start with creating and trafficking your ad using the DFP API, and then show you how to display it using the IMA SDK.

Before you start

If you're new to video ads, check out this help center article for a little more background. This post shows how to use a VAST redirect creative, so you'll need to host a VAST tag and your video ad before making the creative in DFP. If you just want an example VAST tag to get up and running, you can use the XML here.

Note that this example tag will only return VAST for the first request. Subsequent requests will need to update the correlator timestamp in the URL. The IMA SDK will handle this for you, so there's no problem using this as your example URL.

Creating the video ad unit

If your network doesn't have a video ad unit already, you'll need to create one. Set the fields as you would for any other ad unit, but use a size appropriate for video and the VIDEO_PLAYER environment type.

    Size videoSize = new Size();
videoSize.setWidth(640);
videoSize.setHeight(480);
videoSize.setIsAspectRatio(false);

AdUnitSize videoAdUnitSize = new AdUnitSize();
videoAdUnitSize.setSize(videoSize);
videoAdUnitSize.setEnvironmentType(EnvironmentType.VIDEO_PLAYER);

Making a video creative

Beginning in v201403, you can create and update VAST redirect creatives with the DFP API. If video features are enabled on your network, creating VAST redirect creatives takes just a few lines of code. Let's start by setting some standard creative fields:

    VastRedirectCreative vastRedirectCreative = new VastRedirectCreative();
vastRedirectCreative.setName("My first VAST redirect creative");
vastRedirectCreative.setAdvertiserId(advertiserId);

Now set the size of your video to match your AdUnit:

    Size size = new Size();
size.setWidth(640);
size.setHeight(480);
vastRedirectCreative.setSize(size);

Finally, you need to set your VAST XML. For this example, we'll use VAST XML with a linear advertisement. Linear video ads are analogous to television commercials and can play before, after, or in the middle of your content.

    vastRedirectCreative.setVastXmlUrl(vastXmlUrl);
vastRedirectCreative.vastRedirectType(VastRedirectType.LINEAR);
Creative[] creatives = creativeService.createCreatives(new Creative[] {
vastRedirectCreative});
Creative masterCreative = creatives[0];

This is your master creative. When working with video, DFP uses CreativeSets which have master and companion creatives. Companion creatives are typically displayed alongside the content video, and tie in with the video ad. The line items you create for video will be associated with a creative set, so you need to create one using your VAST redirect creative as the master. For simplicity, we won't use any companions here.

    CreativeSet creativeSet = new CreativeSet();
creativeSet.setName("My VAST Redirect Creative Set");
creativeSet.setMasterCreativeId(masterCreative.getId());
creativeSet.setCompanionCreativeIds(new long[] {});
CreativeSet createdCreativeSet =
creativeSetService.createCreativeSet(creativeSet);

Creating a video line item

Now we need a line item to serve the video creative set. We'll just highlight the differences for video line items here, so if you aren't familiar with creating line items, check out our complete example on GitHub.

In addition to the usual line item fields, you have the option to set position targeting. Using VideoPositionType.PREROLL will target videos where ads can play before the content starts.

    VideoPosition videoPosition = new VideoPosition();
videoPosition.setPositionType(VideoPositionType.PREROLL);
VideoPositionTarget videoPositionTarget = new VideoPositionTarget();
videoPositionTarget.setVideoPosition(videoPosition);
VideoPositionTargeting videoPositionTargeting = new VideoPositionTargeting();
videoPositionTargeting.setTargetedPositions(
new VideoPositionTarget[] {videoPositionTarget});

Video line items can also target content in a variety of ways with ContentTargeting. If your network is connected to a content source you can use your content hierarchies to target a genre, season, or any other hierarchy you configured. If you're unsure of how to get the content metadata hierarchy key IDs, take a look at this example.

    // Create content targeting.
ContentMetadataKeyHierarchyTargeting contentMetadataTargeting =
new ContentMetadataKeyHierarchyTargeting();
contentMetadataTargeting.setCustomTargetingValueIds(
new long[] {contentCustomTargetingValueId});

ContentTargeting contentTargeting = new ContentTargeting();
contentTargeting.setTargetedContentMetadata(
new ContentMetadataKeyHierarchyTargeting[] {contentMetadataTargeting});

Now add these to the line item's targeting object. Don't forget to set the environment type to VIDEO_PLAYER.

    Targeting targeting = new Targeting();
targeting.setContentTargeting(contentTargeting);
targeting.setVideoPositionTargeting(videoPositionTargeting);
// Target your video AdUnit
targeting.setInventoryTargeting(inventoryTargeting);

LineItem lineItem = new LineItem();
lineItem.setEnvironmentType(EnvironmentType.VIDEO_PLAYER);
lineItem.setTargeting(targeting);

Make sure to set all the required fields as you would for any other line item, and then create it.

Wrapping things up

Let’s do a quick recap. We now have an AdUnit for a standard video size, our VastRedirectCreative of a matching size in a CreativeSet, and our video LineItem targeted the AdUnit. If your network has a content source connected, you may have targeted certain content as well.

The last step is to create a LineItemCreativeAssociation to connect the CreativeSet with the LineItem.

    LineItemCreativeAssociation lica = new LineItemCreativeAssociation();
lica.setLineItemId(lineItemId);
lica.setCreativeSetId(creativeSetId);
LineItemCreativeAssociation[] licas =
licaService.createLineItemCreativeAssociations(
new LineItemCreativeAssociation[] {lica});

Finally, your video ad is ready to serve. The next question is, how do you actually serve it? Stay tuned for the exciting conclusion: Life of a Video Line Item Part II.

Sunset of DFP API v201311 and earlier, and the removal of ClientLogin

This is a friendly reminder that, on February 27, 2015, we will sunset DFP API versions v201311, v201308, and v201306. At that point, requests to these versions will fail. We'll also remove them from our online documentation and the client libraries. If you are currently using one of these versions, this is an excellent time to begin migrating to a supported version. See the release notes for a list of the many new features in our recent API versions.

Going forward, all DFP API versions will follow a consistent deprecation schedule: versions will be supported for one year, deprecated for one quarter, then sunset. This means each of our quarterly API versions will be available for 15 months from the time of release. This deprecation schedule enables us to spend more time improving the latest versions with new features.

Note that v201311 is the last version that supports ClientLogin, which was officially deprecated across all of Google on April 20, 2012. If your application is not yet using OAuth2, you must migrate before Feb 27, 2015.

If this task seems daunting, don't fret, we have you covered. On our Developer page, we have a helpful OAuth2 guide to make sure the transition is as smooth as possible. As an added reason to switch, the DFP API now supports OAuth2 service accounts. You can add service account users directly in the DFP UI. For more information, see here for a guide on how to use a service account user with the DFP API.

If you have any feedback or comments about this deprecation, or the API in general, please feel free to leave them on our forum.

Using LINQ with the DFP API

By now you're probably familiar with using PQL in the DFP API. The SQL-like filtering provides an expressive way of working with DFP, but occasionally you'll want to filter on a field that isn't supported by PQL. Luckily, if you're using the .NET library, you can utilize LINQ to augment your filtering capabilities.

Filter on any field

Similar to PQL, LINQ provides a friendly syntax for filtering iterables. As you page through entities from DFP, you can leverage LINQ to add that extra filtering with just a few lines of code.

This example finds all ImageCreatives that are missing altText - a field specific to the subclass and not filterable with PQL.

    CreativePage page = new CreativePage();
var creativesMissingAltText = new List();

// Create statement to select image creatives.
StatementBuilder statementBuilder = new StatementBuilder()
.Where("creativeType = :creativeType")
.OrderBy("id ASC")
.Limit(StatementBuilder.SUGGESTED_PAGE_LIMIT)
.WithBindVartiableValue("creativeType", "ImageCreative");

// Page through all creatives and select those that are missing the
// altText property with LINQ.
do {
page =
creativeService.getCreativesByStatement(statementBuilder.ToStatement());

creativesMissingAltText.AddRange(
from ImageCreative creative in page.results
where creative.altText == ""
select creative);

statementBuilder.IncreaseOffsetBy(StatementBuilder.SUGGESTED_PAGE_LIMIT);
} while (statementBuilder.GetOffset() < page.totalResultSetSize);

Console.WriteLine("Found {0} ImageCreatives missing altText",
creativesMissingAltText.Count);

While LINQ offers a way to extend filtering, it's important not to ignore PQL. You'll notice this example used PQL to pre-filter on the creative type. Working with smaller result sets will save you network overhead and processing cycles.

Filtering with regular expressions

Now let's take a look at a more complex example. In this scenario, your application needs to validate the htmlSnippet of CustomCreatives. LINQ allows you to use regular expressions while filtering to extract the matches. Here we'll use a regular expression to make sure URLs in the htmlSnippet point to a certain subdomain.

    // Make sure any URLs to mydomain go through the CDN.
Regex subdomainRegex = new Regex(@"https?://(?!cdn\.).*?mydomain.com");
var errors =
from CustomCreative creative in creativesToValidate
let matches = subdomainRegex.Matches(creative.htmlSnippet)
where matches.Count > 0
select new {
creativeId = creative.id,
matchedUrls = from Match match in matches select match.Value
};

foreach (var error in errors) {
Console.WriteLine("Invalid urls found in creative {0}: {1}",
error.creativeId, error.matchedUrls.Join(","));
}
LINQ also supports common functions like Average and Max, making it easy to interact with DFP entities. For more LINQ examples, check out 101 LINQ Samples. You just might find the missing link you need for your DFP application.

‘Decorating’ your Python DFP API applications

Python has tons of cool idioms and features that are often overlooked or underutilized. List comprehensions to cut back on the use of unnecessary loops, decorators to wrap functions with annotations, and generator functions are just some that can be applied to working with the DFP API.

In this post, we'll tackle one of our most asked questions using decorators: "Why am I running into CONCURRENT_MODIFICATION or QUOTA_EXCEEDED errors, and how do I avoid this?".

Addressing these errors using decorators

CONCURRENT_MODIFICATION and QUOTA_EXCEEDED errors are similar in nature - the requests you’re making are failing, but not necessarily because the data you’re sending over is bad. In the first case, one of the objects you’re trying to modify is being updated elsewhere, but you likely want to try again after pulling down the same set of objects. You could certainly write code that retries your operations in all of your services for each object, but it may get a bit hard to maintain (especially with duplicated code). A much cleaner implementation would be to use a decorator!

The Python wiki has an entry under the decorators section that shows how a generic decorator might work for retrying a call. With a few modifications, we can tailor this to capture the two types of errors that might arise:

  import time
from functools import wraps

RESPONSES_TO_RETRY = ['CONCURRENT_MODIFICATION', 'QUOTA_EXCEEDED']

def retry(tries=4, delay=3, backoff=2):
''' Decorator that implements an exponential backoff for retrying on errors.

Args:
tries: int number of times to execute the wrapped function before failing
delay: int time to delay in seconds before the FIRST retry
backoff: int multiplier to extend the initial delay by for each retry
'''
def decorated_function_with_retry(func):
@wraps(func)
def function_to_retry(*args, **kwargs):
local_tries, local_delay = tries, delay
while local_tries > 1:
try:
return func(*args, **kwargs)
except Exception, e:
if [response for response in RESPONSES_TO_RETRY
if response in e.fault['faultstring']]:
print '%s, Retrying in %d seconds...' % (str(e),
local_delay)
time.sleep(local_delay)
local_tries -= 1
local_delay *= backoff
return func(*args, **kwargs)
return function_to_retry
return decorated_function_with_retry

Say you were making a call to update line items - with large networks, it’s not unlikely that someone might be editing the line item at the same time. Since you’d want to pull down the most recent copy of the line item any time the update fails, you would want to abstract out the update method to include the getLineItemsByStatement call, e.g.,

  @retry()
def fetch_and_update_line_item(statement):
# call to get the line item in question
response = line_item_service.getLineItemsByStatement(
statement.ToStatement())

updated_line_items = []
if 'results' in response:
for line_item in response['results']:
# Do something with your line items here and add them to
# updated_line_items.

line_item_service.updateLineItems(updated_line_items)

This would effectively allow you to, in the event of the update failing due to concurrent modification, pull down and update a new copy of the line item. Using the default constructor will retry 4 times with 3, 6, and 12 second delays in between.

To wrap things up, decorators are incredibly useful constructs in Python and are useful for the DFP API for several reasons:

  • Your application will be less flaky and less affected by intermittent application issues.
  • You’re less likely to run into quota errors.
  • This would prevent overwriting other changes (in the case of retrying failed calls on concurrent modification errors).
  • You could also use something like this to log errors on your end, which could help reveal poor code health or inefficient processes.

Make use of decorators in your code, and you'll soon be sitting pretty.

Announcing OAuth 2.0 service account support for the DFP API

Until now, the DFP API only supported the OAuth 2.0 native/installed application flow. The OAuth 2.0 service account flow was only supported it you had a Google Apps for Business Account. Today, we’re unveiling the new OAuth 2.0 service account flow for DFP. This authorization flow has been simplified to no longer require a Google Apps domain. We’ve also updated the DFP web UI to allow service accounts to be added to be a DFP network.

Why should I use service accounts?

Service accounts allow access to Google APIs without the need for user interaction by authenticating solely with server-to-server interactions. Other OAuth 2.0 flows require user interaction or having an application cache a refresh token.

How do I use service accounts?

  1. Generate a service account key from the Google Developers Console.
  2. Add the service account to your DFP network by going to the Admin tab and clicking the Add a service account user button.
  3. Fill in the form with your Name, Email, Teams (if applicable), and Role. Then, click Save.
  4. View existing service account users by going to the Users tab and then clicking the Service Account filter.

With the *.p12 key generated from the Google Developers Console and the service account added to the DFP network, you can now generate an OAuth 2.0 token. For example, using the Java client library:

    GoogleCredential credential = new GoogleCredential.Builder().setTransport(
new NetHttpTransport())
.setJsonFactory(new GsonFactory())
.setServiceAccountId("****@developer.gserviceaccount.com")
.setServiceAccountScopes("https://www.googleapis.com/auth/dfp")
.setServiceAccountPrivateKeyFromP12File(new File("/path/to/key.p12"))
.build();

For more information, see our updated guide on using service accounts with DFP.

Announcing v201408 of the DFP API

Today, we launch v201408 of the DFP API. This release features the addition of a new table to the Publisher Query Language service, some changes to the LineItem.Goal object, a multitude of enhancements to our Sales Manager services, as well as changes to our server endpoint and scope URLs. A detailed list of these features and what’s changed can be found on our release notes page.


New Endpoint URL


Version v201408 of the DFP API changes the endpoint URL for requests from https://www.google.com to https://ads.google.com. For example:
https://ads.google.com/apis/ads/publisher/v201408/CompanyService?wsdl
All of our DFP API client libraries have been updated to reference this URL starting with the v201408 release. If you are using a supported version of the client libraries, then no changes will be required. Otherwise, please update your code to make requests against this new URL.

Line Item goals, Sales Manager refactorings, and more PQL support


In v201408, we have added the field of Goal.goalType to the LineItem.Goal; this replaces what was formerly lineItem.duration and adds back support to create / update the line item types impacted in v201405 (listed here).

We've also done some significant refactoring of our Sales Manager API services adding premiums to rateCard objects. Prior to this version, there was a RateCardCustomizationService as well as a RateCardCustomizationGroupService; both were required to add a feature premium to an existing rateCard. This has now been replaced with a singular service named PremiumRateService.

In addition, we've also heard you loud and clear that PQL tables make development easier - in v201408, we provide support for the Audience_Segment_Category table.

New OAuth 2.0 Scope


With the release of v201408 of the DFP API, we will be introducing a new OAuth 2.0 scope. This scope identifies the service that your application will access during the authorization process.
https://www.googleapis.com/auth/dfp
This new scope better aligns with the naming conventions of many of the other Google APIs.

Starting from today, you should use the new scope when authorizing access for the DFP API regardless of the DFP API version. All our current DFP API client libraries use this new scope.

But I have refresh tokens from the deprecated scope...


Don't worry if your client code is using refresh tokens authorized with the deprecated scope - they will still work. However, new authorizations should specify the new scope.

Nicholas Chen, DFP API Team