For developers who want to run ads in iOS versions of their apps, we are releasing an update to our Google AdMob Ads SDK. This new version of the SDK is consistent with Apple’s reported decision regarding developer usage of the universal device identifier (UDID). Our goal is to help all developers and publishers continue to reach users on mobile, grow their businesses and make money, in accordance with the policies of the mobile platforms on which they build.
Developers and publishers building their businesses on the iOS platform can download the new SDK here. Stay tuned for more new SDK features and updates in the coming weeks.
Posted by: Mark Schaaf, Google Mobile Ads
If you are an advanced AdSense Management API user, your application may have run into one of the several different limits we have in place. We’ve created a new documentation page to keep track of system limits, but here’s a small description of what they are and what you can do to avoid them.
This limit refers to the number of requests your project can make via the API in a single day, across all of your users or AdSense accounts. This is set to 10,000 queries per day for all new projects.
If you’re running into the limit, feel free to request more from the “Quotas” page for your project, in the APIs Console. We’ll look at your request and project usage history, then decide an appropriate limit to set in place.
The various “list” methods in the AdSense Management API are paginated, with a default size of 10,000 entries per page. You can configure this limit yourself in your request with the maxResults parameter, but you can’t set it to any value greater than 10,000.
For regular, unpaginated reports, the maximum number of rows that the API will return is 50,000. If your report is larger than that, it will be truncated at 50,000 rows.
Pagination in reports should only be used when strictly necessary, as it’s generally only useful to applications running in devices with severe storage constraints. Because of this, paginated reports are limited to 5,000 rows and any attempt to obtain data beyond the 5000th row will return an error.
Let us know in our forum if you have any questions!
- Sérgio Gomes, AdSense API Team
One of the less common management tasks in DoubleClick for Advertisers is setting up the sites that host the placements you wish to target. Some questions have come our way recently regarding how to manage sites and when you want to use getSitesByCriteria versus getDFASites. Let’s take a second to clear this up.
There are two types of sites you will deal with in DFA:
An additional DFA site has to be mapped whenever you begin creating placements for a new website for the first time. So how do you go about setting these up?
The first step to creating a new DFA Site is to find the site you want in the Site Directory. You can use the getSitesByCriteria operation for this. Since you cannot use Site Directory sites without mapping them to a DFA Site first, the only time you should use the getSitesByCriteria operation is when you’re looking for additional sites to map into your account. In all other instances, getDfaSites is probably the operation you’re looking for.
// Get the site service using the Google Ads APIs Client Library. DfaSession session = new DfaSession.Builder().fromFile().build(); SiteRemote siteService = new DfaServices().get(session, SiteRemote.class); // Get sites which match the URL you are looking for. String targetUrl = "www.google.com"; SiteSearchCriteria searchCriteria = new SiteSearchCriteria(); searchCriteria.setSearchString(targetUrl); SiteRecordSet siteRecordSet = siteService.getSitesByCriteria(searchCriteria); // Find the site with the exact URL. long directorySiteId = 0; if (siteRecordSet.getRecords().length != 0) { for (Site result : siteRecordSet.getRecords()) { if (Arrays.asList(result.getUrls()).contains(searchString)) { directorySiteId = result.getId(); } } } if (directorySiteId == 0) { System.out.println("No site with that exact URL was found!"); }
If the site you need doesn’t exist in the directory, you can add it through the website interface. The API does not support adding new sites to the site directory.
Using the site ID you obtained in Step 1, you can create a DFA site in your account. This is also your first opportunity to modify your personal settings for this site.
// Create a DFA site. DfaSite dfaSite = new DfaSite(); dfaSite.setName("DFA Site for Site " + directorySiteId); dfaSite.setSiteDirectorySiteId(directorySiteId); dfaSite.setNetworkId(myNetworkId); // Set any other optional parameters you want. SiteTagSettings tagSettings = new SiteTagSettings(); tagSettings.setIncludeClickTrackingStringInTags(true); dfaSite.setTagSettings(tagSettings); // Save DFA site. DfaSiteSaveResult saveResult = siteService.saveDfaSite(dfaSite); long dfaSiteId = saveResult.getId(); System.out.printf( "DFA site with ID \"%s\" was created.%n", dfaSiteId); // Make as many placements as you need! Placement placement = new Placement(); placement.setDfaSiteId(dfaSiteId);
The site service contains methods that you won’t typically use during trafficking administration. Once your sites are set up, the operations to retrieve DFA sites are the only ones you’ll need. If you still have any questions about creating or managing sites with the API, please visit our forum.
As you may have recently read on the Inside AdWords blog we’ve increased various limits for Google AdWords accounts. Most notably it’s now possible to have up to 10,000 campaigns and three million keywords in an account. These and other product limits are listed in the AdWords Help Center, with additional API technical limits available on the System Limits page.
As a reminder, when dealing with large numbers of API objects it’s best to utilize paging in your requests, which allows you to fetch the data in smaller batches. The example code in our client libraries demonstrates how to use paging effectively. However, paging alone is insufficient to retrieve data sets with over 10,000 items and in those situations we recommend you either use predicates to limit the size of the results or use report downloads to get the full set of data.
If you have questions about these new limits or how they affect your API development you can reach us on the forum or during our regular office hours.
- Eric Koleda, AdWords API Team
Today we’ve published a new tutorial on scheduling AdSense reports with Google Apps Script.
By following the tutorial, you’ll learn how to create a script that’s executed every hour to retrieve data from the AdSense API and send a report of the evolution of several metrics over the current day. The report data will then be visualized using an area chart.
You’ll also learn how to add a user interface to let you configure the recipient of the report, the metrics included in the chart, the hours of the day and days of the week for the report sending, as shown in the image below.
The following is an example of chart that will be sent with the email.
This tutorial is an example of how Google Apps Script can provide easy ways to automate tasks across Google products and third party services. Check the tutorials page to learn the different things that you can do using this cloud scripting language.
For any additional questions, visit our AdSense API forum or the Google Apps Script forum. You can also check the schedule for our Office Hours Hangouts and join us for a chat on this and other topics -- visit the right column of this blog to find our schedule.
- Silvano Luciani, AdSense API Team
https://adwords.google.com/api/adwords/reportdownload/v201109
We would like to announce the release of the DFP Showcase application for iOS and Android, as well as v2 of the Ad Catalog project for Android.
DFP Showcase is a sample project that features the various creative types you can display in mobile applications with DoubleClick for Publishers (DFP) Mobile. DFP Mobile provides publishers the ability to set up campaigns with different ad types, and uses the Google AdMob Ads SDK to display the ads in mobile applications.
The DFP Showcase application features expandable ads, image animation, click to map, and more!
You can download DFP Showcase directly or clone the source code from the dfpshowcase-android or dfpshowcase-ios repositories.
We are pleased to announce the release of Ad Catalog v2 for Android. This new version shows examples of best practices for ad placement in four different types of layouts - TabView, ListView, OpenGLView, and ScrollView.
Here are some details about the implementation of these examples:
You can get v2 of the Ad Catalog by downloading a zip file from the google-mobile-dev download page or by cloning the source code.
Have any questions, comments, or feature requests for the DFP Showcase or Ad Catalog projects? Let us know on the forum, or join us during office hours! Also, stay tuned for the release of Ad Catalog v2 for iOS.
- Eric Leichtenschlag, AdMob Team
We previously talked about docking AdMob ads to the bottom or top of a UITableView. In response to that post, we’ve had a lot of developers asking us about embedding AdMob ads within the UITableView cells, so we wanted to share how this can be best achieved.
Placing ads within a Table View in iOS as list items can bring up a number of issues:
Table Views in iOS are populated by implementing the tableView:cellForRowAtIndexPath: method. Cell objects are often reused so that new ones aren’t instantiated each time the Table View is refreshed (by a scroll for example). There are two ways that ads can be implemented within Table View cells:
Using one GADBannerView throughout the table does decrease ad diversity but generally increases the CTR for the ads that are shown because the user will more likely see the ads that are displayed. The example below will show how to implement this approach as it is the better practice.
For the purposes of this example, let’s assume that every 10th element in the list is going to be an ad. This means tableView:cellForRowAtIndexPath: will be set up with a conditional that modifies the placement of the GADBannerView for every tenth cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { int row = [indexPath row]; // Assume that kFrequencyAdsInCells is 10 so every 10th row is an ad // Don't want first item to be an ad so use 10-1=9 instead of 0 if ((row % kFrequencyAdsInCells) == (kFrequencyAdsInCells)) { cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; //Need to create a new cell object if (cell == nil) { cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease]; } // If bannerView_ has a superview, then it has been added to a cell if (!bannerView_.superview) { // First ad request made, make the ad request and add it to this cell [self requestAd]; } // The banner will be removed from the other cell and put into here [cell.contentView addSubview:bannerView_]; } …
Since ads are being inserted into the Table View now, any previous mapping to data in the model will be lost. Some quick math is necessary here to figure out how the rows in the Table View line up.
// Complete in cellForRowAtIndexPath: if not ad // Make sure we get all of the items from our model row = row - floor((float)row/kFrequencyAdsInCells); cell.textLabel.text = [dataController_ objectInListAtIndex:row];
The methods tableView:NumberOfRowsInSection: and tableView:heightForRowAtIndexPath: will need to be modified as well. The method tableView:NumberOfRowsInSection: would now return the number of elements (including ads in that number) and tableView:heightForRowAtIndexPath: would return the height of an ad for every tenth cell, respectively.
If you have any questions about embedding ads within a UITableView, or even any questions about the SDK in general, feel free to post them in our forum. Keep an eye out for AdCatalog v2 for all kinds of advanced layouts options integrated in the project.
// Get the LineItemService. $lineItemService = $user->GetService('LineItemService', 'v201201'); // Calculate time from thirty days ago. $thirtyDaysAgo = date(DateTimeUtils::$DFP_DATE_TIME_STRING_FORMAT, strtotime('-30 day')); // Create bind variables. $vars = MapUtils::GetMapEntries(array( 'thirtyDaysAgo' => new TextValue($thirtyDaysAgo))); // Create statement object to only select line items that // have been modified in the last 30 days. $filterStatement = new Statement( "WHERE lastModifiedDateTime >= :thirtyDaysAgo " . "LIMIT 500", $vars); // Get line items by statement. $page = $lineItemService->getLineItemsByStatement($filterStatement);
Since launching the AdSense Management API in October last year, we’ve received a number of questions and feedback from you while coding your applications. Today, we’ll address the most frequently asked questions and share some best practices.
Right now, the only authentication method we support is OAuth, but don’t let that intimidate you; OAuth 2.0 supports several authentication methods, for web server, client-side and installed applications and devices, which together cover all use cases.
You can find more information on how to authenticate in your favourite client library language in our client library guide or the more generic OAuth 2.0 documentation.
If you don’t take steps to store your users’ authentication data or set the appropriate flags on your request, the authentication process will run them through a permission-granting dialog similar to the one below every time:
In order to avoid this and improve the experience for users of your web or installed application, you should store their authentication data.
There are two types of token that we need to know about here: access tokens and refresh tokens. Access tokens give you immediate access to a user’s data, and are short-lived, whereas refresh tokens are long-lived, allowing you to generate new access tokens when you need them, even if the user isn’t present.
For installed or web applications we recommend storing both, and using the refresh token to generate a new access token whenever the one you stored expires.
For client-side applications, things should be a little easier, as all it should take is a redirect. The OAuth 2.0 documentation for client-side applications has all the information you need.
For more information on request tokens, you can check the relevant section in the OAuth 2.0 documentation, or the “Persisting authentication data” section in our client library guide if you’re using one of the client libraries.
Every application has different needs, so the answer to this question will no doubt depend on what you’re doing. There are, however, a few guidelines we can give you.
First of all, try to collect data on the same frequency that you analyze it. That is, if you’re interested in daily performance, there’s no need for you to collect data more often than once a day, as our reporting can compile that data for you.
On the other hand, if you’re trying to get data as frequently as possible, bear in mind that we cache our report data for 60 seconds. There’s thus no point in running the same report more often than once a minute; the data you get won’t be any fresher, and you’ll just be wasting your request quota.
Most reports are based on a time dimension such as DATE, WEEK or MONTH, which is to say that they’re grouped by that particular dimension.
Not all reports need to be based on a time dimension, however. In fact, a very useful report for those of you with many international visitors is to get a breakdown of visitors per country. In order to get that, just set your start and end dates and choose COUNTRY_CODE or COUNTRY_NAME as the dimension.
You can combine both approaches as well, to get a breakdown per country for every month, for example.
To get some more background on reports and the concepts behind them, check out our Diving into Reports blog post.
We’ve got a whole bunch of resources for you, from the reference documentation to our client library guide and code examples for several programming languages.
If that doesn’t help, take a look in our forum, and you might find a similar question or get a chance to post your own. You can also join us in a Hangout during our regular office hours. We’ll be around to give you a hand in either case!
We’ve received questions asking us what happens new ad networks are added to an existing AdWhirl application. In this post we’ll explain how older versions of your apps will handle a new ad network configuration.
Say you published an application using AdWhirl, configured to use two ad networks. Now it’s time to release the next version, and you’d like to add a third ad network while you’re at it. But how will that affect the ad network request distribution for users running an older version of your application, which doesn’t have the new ad network SDK bundled? Older versions will request the updated configuration for both iOS and Android, but the two SDKs will process the configuration differently.
When the iOS SDK parses the new configuration, it will only consider an ad network valid if it meets certain conditions, including having the corresponding network adapter. If the adapter doesn’t exist, then that network will be ignored. Your ad network percentages will then be normalized based on the total valid percentage of allocations.
Let’s demonstrate this with the above example. Say your original app had two ad networks, Network 1 and Network 2; now you’re adding Network 3 to the next version of your app. If your new ad network configuration sends 30% of requests to Network 1, 10% to Network 2, and 60% to Network 3, users running an app version without Network 3 will send 75% of the total ad requests to Network 1 and 25% of requests to Network 2. Backfill priority will be the same as specified on the server, but it will not include network 3.
When the Android SDK parses the new configuration, it will blindly add all networks as valid choices. When it tries to make a request to an ad network whose SDK is not available, the request will fail gracefully. However, AdWhirl will then rollover to your backfill priority. What does this mean for the ad network percentage distribution?
Using the same example configuration, the 60% of requests to Network 3 will fail for users with an older version, and AdWhirl will rollover to your top backfill option. If your top backfill option is Network 2, then Network 2 will consume the Network 3 traffic - you will have 30% of all requests going to Network 1, and 70% to Network 2. This is likely not what you would expect, so be careful when adding new networks to an existing Android application.
In summary, the iOS SDK will respect the percentages given to the valid ad networks (expected), but the Android SDK will send the invalid ad network traffic to the top backfill option (unexpected).
We value your feedback, so please post to our developer forum if you have any questions about AdWhirl.