Category Archives: Google Ads Developer Blog

The blog for information about the AdWords, AdSense, DoubleClick and AdMob APIs and SDKs.

Introducing MCC Scripts: Efficient Management across Accounts

MCC scripts is a powerful new way to manage your AdWords accounts at scale through simple JavaScript code. You can make cross-account changes, create customized reports to save time, and even pull data from Google Spreadsheets. In March, we announced that MCC scripts are available for Beta signup. Today, we are excited to make this feature available for all users.

To get started with MCC scripts, log in to your My Client Center account, and navigate to My Client Center->Scripts.
Here are some of the ways you can save time with MCC scripts:
  • High quality cross-account reports: Generate well-formatted custom reports in HTML, PDF or Google Spreadsheets for all your client accounts. You can save these reports to Google Drive, to an external server, or include them as an email attachment.
  • Cross-account optimization: Analyze performance and adjust bids in all your client accounts at scale.
  • Troubleshooting and maintenance tools: Scan your client accounts for potential issues like paused campaigns, broken URLs, capped budgets, conflicting negative keywords, etc.
We have put together several resources to get you started:
  • Getting started guide: Our getting started guide provides a technical overview of MCC scripts and how to use it.
  • Reference docs: Refer to the technical reference for MccApp at https://developers.google.com/adwords/scripts/docs/reference/mccapp/index
  • Code snippets: Not sure how to use a particular feature? You can click the “Show examples” button on the Scripts editor or refer to our code snippets page to view a list of code snippets for the most common use cases in AdWords scripts. We have expanded this section to include snippets that shows various features of MCC Scripts.
  • Solutions: Looking for some ready-to-use scripts? Check out our solutions section, which we've just expanded to include solutions specifically tailored to MCC.
Don't be shy with questions if you're just getting started with AdWords scripts--our forum is here to help! You can also provide feedback via the Google Ads Developers Google+ page.

AdWords scripts – New code snippets are now available!

We have added new code snippets to cover the new services released over the last year. You can view these code snippets by either clicking the Code examples button on the Scripts Editor window in the AdWords UI, or through the examples page on AdWords scripts documentation.



We hope you find these new code snippets useful. If you wish to see more code snippets or have feedback about the new ones, let us know on our developer forum. You can also follow our Google+ page for updates about AdWords scripts.

Changes to AdWords scripts execution logs

As part of our ongoing efforts to improve the performance of AdWords scripts, we are making some changes to the way we provide execution logs for scripts.

Starting May 15, 2014, we will only retain detailed execution logs for scripts that ran during the last 90 days. If you need to retrieve changes made by scripts from an earlier date, you can refer to your account’s change history.

If you have any questions about this change, let us know on the forum or on our Google Ads Developers Google+ page.

How to Create a Google Mobile Ads Splash Screen Interstitial on Android

Previously, we showed you how to create a splash screen interstitial on iOS. Today we’ll discuss how to trigger an interstitial on an Android app launch.

The cleanest solution is to have an app launch Activity for showing the splash screen image and loading/showing the interstitial. This special splash screen activity should be the activity that launches when the user starts the app. In the splash screen activity’s onCreate method, the first task is to make an ImageView and set it as the content view.


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ImageView image = new ImageView(this);
// Assumes you have a resource with the name kitten.
image.setImageResource(R.drawable.kitten);
setContentView(image);

Next, create and load the interstitial ad. Setting an AdListener is needed in order to know when the ad succeeds or fails to load. If the interstitial loads within a reasonable time limit, we’ll show it. If it fails, we’ll move on to the main activity.


interstitial = new InterstitialAd(this);
interstitial.setAdUnitId(AD_UNIT_ID);
interstitial.setAdListener(new AdListener() {
@Override
public void onAdLoaded() {
if (!interstitialCanceled) {
waitTimer.cancel();
interstitial.show();
}
}

@Override
public void onAdFailedToLoad(int errorCode) {
startMainActivity();
}
});

The “reasonable time limit” mentioned earlier is enforced by creating a timer to stop waiting for the interstitial. If the interstitial doesn’t load fast enough (in this case 5 seconds), we skip it and proceed to the main activity.


waitTimer = new Timer();
waitTimer.schedule(new TimerTask() {
@Override
public void run() {
interstitialCanceled = true;
SplashScreenActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
startMainActivity();
}
});
}
}, 5000);
} // end of onCreate implementation.

private void startMainActivity() {
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
finish();
}

Handing Early Exits

The code so far assumes that the user will stay in the activity for the duration of the interstitial loading. But what if the user hits the back or home button before the interstitial loads or the timer goes off? The interstitial will actually continue loading and could be shown on top of the home screen! That would be a poor user experience.

We account for this edge case by implementing the onPause and onResume methods from the activity lifecycle. In onPause, we stop the timer and set the interstitialCanceled flag so the interstitial doesn’t get immediately shown. In onResume, we show the interstitial if it’s ready when the user returns to the app again, otherwise we start the main activity.


@Override
public void onPause() {
waitTimer.cancel();
interstitialCanceled = true;
super.onPause();
}

@Override
public void onResume() {
super.onResume();
if (interstitial.isLoaded()) {
interstitial.show();
} else if (interstitialCanceled) {
startMainActivity();
}
}

If you’re wondering why interstitialCanceled is checked again before starting the main application, it’s because onResume gets called immediately after onCreate the first time the app is loaded. And on the first app launch, we do want to wait for the interstitial to load.

A complete implementation is available in our googleads-mobile-android-examples repo on GitHub. Give us a shout on the forum if you have any questions about implementing the Google Mobile Ads SDK in your mobile applications. You can also find us on Google+.

Change to ClickType value in AdWords API reports

We are making a minor change to the values returned in the ClickType column in AdWords API reports. Starting the week of May 26th, 2014, AdWords API reports will return "Product listing ad" instead of "Offer" as the display value for click types corresponding to Product Listing Ads.

If you depend on the ClickType field, verify that your applications won't be negatively affected by the change in value.

If you have questions or feedback about this change, let us know on our forum or via the Google Ads Developers Google+ page.

Reminder: DFP API v201302 and earlier will be deprecated on August 1, 2014

After successfully removing several older versions of the DFP API earlier this month, we’re continuing our 'Spring Cleaning' by reminding everyone that support for version v201302 or earlier of the DFP API will end on August 1st, 2014. If you are still using one of those versions after that date, all requests will fail and your application will cease to work until you migrate to a supported version. Please reference the release notes for all changes to the API when migrating to a newer version.

In addition, please note that ClientLogin support is being phased out and that you will have to migrate to OAuth 2.0 in order to authenticate starting with v201403. Please reference our OAuth 2.0 implementation guide for help with this process.

If you have any questions about this upcoming change or anything else related to the DFP API, please contact us on the forum or via our Google+ page.

Reminder: AdWords API is sunsetting CONVERSION DURATION THRESHOLD feed placeholder

This is a reminder that the CONVERSION DURATION THRESHOLD placeholder is sunsetting starting on April 28th, 2014.

Starting on the sunset date, AdWords accounts will be migrated to use the new CONVERSION TYPE ID placeholder for a four-week time period. During this period, some AdWords accounts that you access via the AdWords API may be migrated, and some may not. Read on to find out how to determine if a feed has been migrated or not. Migration of all AdWords accounts is scheduled to complete by end of May, 2014.

How will an existing conversion duration threshold be migrated?

If you used CONVERSION DURATION THRESHOLD in a Feed Mapping prior to the sunset date, then we will automatically migrate those values after the sunset date - and they will be accessible via the AdWords API v201402 as follows:
  • New AdCallMetricsConversion will be automatically created for you with the existing conversion duration threshold.

    Note: If you have 3 feed items with call duration threshold, where two of them are set to 120 seconds, and one of them are set to 30 seconds, then only two AdCallMetricsConversion will be created - one with AdCallMetricsConversion.phoneCallDuration set to 120 seconds, and another one set to 30 seconds.

  • Feed attributes using CONVERSION DURATION THRESHOLD will remain, setting and reading those values will not produce errors. However, any associated feed attribute values will not be honored.

  • A new feed attribute will be automatically created in your existing feed, and it will be automatically be mapped to the new CONVERSION TYPE ID placeholder type.

  • The new conversion type ID feed attribute will be associated to the newly created AdCallMetricsConversion.

Note that in order to get the name and field attribute ID of the newly created conversion type ID field attribute, you should use the FeedMappingService to determine the feed attribute ID that is associated with the CONVERSION TYPE ID placeholder type.

How do I know if a Feed has been migrated?

If a feed has been migrated, you will be able to see that the Feed has an attribute associated to the CONVERSION TYPE ID placeholder type. You can use the FeedMappingService to determine this.

How do I set conversion duration threshold on a migrated Feed?

If you’d like to continue using conversion duration threshold, then you must upgrade to the AdWords API v201402.

In a migrated feed, the CONVERSION TYPE ID feed item attribute value refers to an AdCallMetricsConversion object by ID. To set the conversion duration threshold, you must update the associated AdCallMetricsConversion object’s phoneCallDuration field. Please note that doing this will impact other feed items that are associated to the same AdCallMetricsConversion object.

Alternatively, you can also associate the CONVERSION TYPE ID feed item attribute value to a different AdCallMetricsConversion:
  • Re-use an existing AdCallMetricsConversion that has the right phone call duration
  • Use the ConversionTrackerService to create new AdCallMetricsConversion with the phoneCallDuration field set
In a migrated feed, if you continue to set the attribute value associated with the CONVERSION DURATION THRESHOLD placeholder, then those values will be ignored.

Can I start using the new placeholder before the Feed gets migrated?

Yes. Starting from the sunset date, you will be able to use the new CONVERSION TYPE ID placeholder in your feed. If you are using the placeholder in your feed and set the attribute value to a valid AdCallMetricsConversion ID, then the CONVERSION TYPE ID value will be used, and the CONVERSION DURATION THRESHOLD value will be ignored.

If you choose to do this prior to the automatic migration - don’t worry. The automatic migration process will not overwrite your existing CONVERSION TYPE ID values with CONVERSION DURATION THRESHOLD values.

We are here to help

If you have any questions about this upcoming change or anything else related to the AdWords API, please contact us on the AdWords API forum or via the Google Ads Developers Google+ page.

Ending support for VAST 1 and F2F in the IMA SDK

On May 5, 2014, in the spirit of spring cleaning, the IMA Flash SDK will be dropping support for several rarely-used formats and SDKs:

  • VAST 1 XML format. The IMA Flash SDK will continue to support VAST 2 and will continue to improve on its existing beta support for VAST 3. For more information about what versions of VAST, VPAID and VMAP the IMA Flash SDK supports, visit the Video Features and SDK Compatibility page.
  • Flash-in-Flash (F2F) creatives. VPAID, the industry standard for interactive video ads, is the recommended alternative for replacing F2F creatives. The IMA Flash SDK currently supports VPAID 1 and has beta support for VPAID 2. 
  • IMA Flash SDK v1. This version of the SDK will no longer be guaranteed to work and won't receive bug fixes, updates, or responses to support issues. V3 of the IMA Flash SDK will be the only fully supported version of the SDK.
  • Dart Shell SDK. This DoubleClick SDK will no longer be guaranteed to work and won't receive bug fixes, updates, or responses to support issues.

What will happen if VAST 1 or an F2F creative is sent to the SDK?

If a VAST 1 ad tag response or F2F creative is sent to the SDK, the SDK will raise an AdErrorEvent with an appropriate error. For example, a VAST 1.0 response will return an AdErrorCodes.VAST_PARSING_ERROR which can be handled with the following ActionScript modified from the Flash IMA SDK example app:

  // ...
import com.google.ads.ima.api.AdErrorCodes;

private function initAdsLoader():void {
// ...
adsLoader.addEventListener(AdErrorEvent.AD_ERROR, adsLoadErrorHandler);
}

private function adsLoadErrorHandler(event:AdErrorEvent):void {
// ...
if (event.error.errorCode == AdErrorCodes.VAST_PARSING_ERROR) {
trace("Invalid VAST format.");
// Error handling logic...
}
}

Other questions?

Questions about these support changes or other questions about the Flash IMA SDK? Check out the IMA SDK Flash Quick Start Guide or drop us a line on the IMA SDK forum. Follow our Google+ page for other announcements and updates.

Troubleshooting and error handling – handling exceptions thrown by the DFP API (Part II)

In our previous blog post on exception handling in the DFP API, we went over the first of two major scenarios where adding exception handling can help you troubleshoot issues when they occur. In this blog post, we finish off by discussing how to handle exceptions that occur when retrieving entities.

Retrieving entities

When retrieving entities, you may have run into errors such as ServerError, QuotaError, or client library specific errors like RemoteException. Generally these errors are not caused by user error, but caused by the API server being busy, or by issues with the entities you are retrieving being too large or corrupted. If you’re already following our best practices of paging through your entities with our suggested page size and are still running into these errors from time-to-time, you can tackle these issues by writing code to handle the exceptions.

The general way we recommend you reduce the page size, wait a few seconds, and then retry the request to handle most errors you can receive. If it continues to fail, repeat this process up to five times. This will give you an idea of whether the failure is a temporary server error, or if there is a deeper issue. The following is an example that augments the GetAllLineItemsExample from the Google Ads API Java Client Library showing how to do this. It reduces the page size for each retry by halving it, and starts off the wait time between retries at two seconds, doubling it with each retry.
  private static final int MAX_RETRY_LIMIT = 5;
private static final long BASE_WAIT_TIME = 2000;

public static void runExample(DfpServices dfpServices, DfpSession session)
throws Exception {
int pageLimit = StatementBuilder.SUGGESTED_PAGE_LIMIT;

// Get the LineItemService.
LineItemServiceInterface lineItemService =
dfpServices.get(session, LineItemServiceInterface.class);
// Create a statement to select all line items.
StatementBuilder statementBuilder =
new StatementBuilder().orderBy("id ASC").limit(pageLimit).offset(0);

// Default for total result set size.
int totalResultSetSize = 0, retryCount = 0;
LineItemPage page = null;
long waitTime = BASE_WAIT_TIME;

do {
// Reset these values for each page.
retryCount = 0;
pageLimit = StatementBuilder.SUGGESTED_PAGE_LIMIT;
waitTime = BASE_WAIT_TIME;
page = null;

do {
try {
System.out.printf(
"Getting line items with page size of %d at offset %d (attempt " +
"%d)...\n", pageLimit,
statementBuilder.getOffset(), retryCount + 1);
// Get line items by statement.
page = lineItemService.getLineItemsByStatement(
statementBuilder.toStatement());
System.out.printf("Attempt %d succeeded.\n\n", retryCount + 1);
} catch (Exception e) {
pageLimit /= 2;
System.out.printf(
"Attempt %d failed. Retrying in %d milliseconds with page size " +
"of %d...\n",
retryCount + 1, waitTime, pageLimit);
Thread.sleep(waitTime);
waitTime *= 2;
statementBuilder.limit(pageLimit);
retryCount++;
}
} while (page == null && retryCount < MAX_RETRY_LIMIT);

if (page != null) {
totalResultSetSize = page.getTotalResultSetSize();
// Your code to handle the line item page, e.g., save it to a database.
} else {
throw new Exception(String.format(
"Failed to get line items at offset %s with page size %d after " +
"%d attempts.",
statementBuilder.getOffset(), pageLimit, retryCount));
}

statementBuilder.increaseOffsetBy(pageLimit);
} while (statementBuilder.getOffset() < totalResultSetSize);

System.out.printf("Number of results found: %d\n", totalResultSetSize);
}
Using the above code, the output would look like the following if the first three attempts failed, but the fourth one succeeded for the first page.
Getting line items with page size of 500 at offset 0 (attempt 1)...
Attempt 1 failed. Retrying in 2000 milliseconds with page size of 250...
Getting line items with page size of 250 at offset 0 (attempt 2)...
Attempt 2 failed. Retrying in 4000 milliseconds with page size of 125...
Getting line items with page size of 125 at offset 0 (attempt 3)...
Attempt 3 failed. Retrying in 8000 milliseconds with page size of 62...
Getting line items with page size of 62 at offset 0 (attempt 4)...
Attempt 4 succeeded.

Getting line items with page size of 500 at offset 62 (attempt 1)...
Attempt 1 succeeded.
If you’re getting exceptions that weren't addressed by our examples and are unclear on how to diagnose them, then you can always write to us on the API forums. Include the requestId of the call that failed, especially in the case that you receive a SERVER_ERROR.

Improved validation of ad group mobile bid modifiers

Starting on April 22nd, 2014, a v201309 or v201402 AdGroupBidModifierService.mutate request will fail with a CriterionError and reason CANNOT_BID_MODIFY_CRITERION_TYPE if all of the following conditions are met for the same criterion:
  • The criterion is a Platform criterion for the mobile platform ID (30001)
  • The Campaign has a CampaignCriterion for the mobile platform criterion with a bidModifier set to 0 (this is displayed as a Bid adj. of -100% under Settings in the AdWords UI)
  • The AdGroupBidModifier has the same mobile platform criterion and attempts to set the bidModifier to any value other than 0
The AdWords API and UI will start rejecting such requests because allowing this combination could give the impression that the ad group will serve ads for the mobile platform criterion when in fact it will not.

For example, assume you create a campaign with a CampaignCriterion containing the following criterion and bid modifier:

<criterion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="Platform">
<id>30001</id>
<type>PLATFORM</type>
<Criterion.Type>Platform</Criterion.Type>
<platformName>HighEndMobile</platformName>
</criterion>
<!-- This will appear as "-100%" in the UI. -->
<bidModifier>0.0</bidModifier>
If you attempt to create an AdGroupBidModifier containing the following criterion and bid modifier for any ad group in the campaign on or after April 22nd, 2014, it will fail because the non-zero ad group bid modifier of 1.25 would have no effect:

<criterion xmlns:ns2="https://adwords.google.com/api/adwords/cm/v201402"
xsi:type="ns2:Platform">
<ns2:id>30001</ns2:id>
</criterion>
<!-- This will appear as "+125%" in the UI. Any other non-zero
value will also fail. -->
<bidModifier>1.25</bidModifier>
Before April 22nd, 2014, please take the following actions to ensure a smooth transition for your application:
  • Make sure that your application will be able to properly handle the error
  • Examine your existing campaigns and ad groups and address any bid modifiers that meet the conditions above
Not using bid adjustments in your campaigns and ad groups? Check out our bid modifiers guide to learn how to use this powerful feature of AdWords.

Still have questions? Feel free to visit us on the AdWords API Forum or our Google+ page.