The AdWords API is no longer supported. Use the Google Ads API instead.

Best Practices

This guide covers some best practices you can implement to optimize the efficiency and performance of your AdWords API applications.

Ongoing maintenance

To ensure that your app runs uninterrupted:

  • Keep your developer contact email in the AdWords API Center up-to-date. This is the alias we use to contact you. If we're unable to contact you regarding compliance with the API Terms and Conditions, your API access may be revoked without your prior knowledge. Avoid using a personal email address tied to an individual or an unmonitored account.

  • To be informed of issues, such as product changes, maintenance downtime, deprecation dates, and so on, subscribe to our

The forum is regularly monitored by the AdWords API team, making it the ideal place to post API questions.

  • Keep your app compliant with the AdWords API Terms and Conditions (T&C) and Required Minimum Functionality (RMF). If required, the token review and compliance team will reach out to you via your contact email. If you have questions or concerns about the T&C or RMF, you can reach out to the review team by responding to the email they sent you when reviewing your developer token application.


Batch operations

Making a request to the API entails a number of fixed costs, such as round-trip network latency, serialization and deserialization processing, and calls to backend systems. To lessen the impact of these fixed costs and increase overall performance, most mutate() methods in the API are designed to accept an array of operations. By batching multiple operations into each request, you can reduce the number of requests you make and the associated fixed costs. If possible, avoid making requests with only one operation.

For example, suppose you're adding 50,000 keywords to a campaign across multiple ad groups. Instead of making 50,000 requests with 1 keyword each, make 100 requests with 500 keywords each, or even 10 requests with 5,000 keywords each. Note that there are limits on the number of operations allowed in a request, so you may need to adjust your batch size to achieve optimal performance.

An additional benefit of making fewer, larger requests is that your app is less likely to encounter a request-based rate limit.

Page large responses

Always specify the pageSize parameter in requests to the API. This will split the response into multiple chunks if necessary.

If pageSize is not specified when using one of our client libraries, your request will fail (RESOURCE_EXHAUSTED) if the response exceeds 4 MB. Even if you're not using one of our client libraries, you should still set the pageSize since large responses can exhaust the available memory on your system.

Start with a pageSize of 1000 and fine tune as needed to improve performance.

Group operations

Operations that all target the same ad group or campaign will process faster than the same number of operations targeting many different ad groups or campaigns. Grouping together operations that target the same ad group or campaign reduces the total number of ad groups or campaigns targeted in the request, improving overall performance.

Concurrent requests to the same ad group or campaign may generate a CONCURRENT_MODIFICATION error. Grouping operations that modify the same ad group or campaign in a single request decreases the chance of such a conflict.

Take the example above of adding 50,000 keywords to a campaign across multiple ad groups. Before breaking the operations into batches, a simple approach is to sort the keywords by the ad group they target. This increases the chance that all of the keywords for the same ad group will fall within the same request. It also decreases the total number of ad groups targeted in a single request. More advanced approaches can be applied to ensure that related operations are grouped into as few requests as possible while still maintaining large batches.

Reuse access tokens

Reusing the same OAuth2 access token across threads and processes reduces the overhead of periodically refreshing tokens, and reduces the likelihood that your app will be rate limited due to excessive token refreshes. Learn more about optimizing OAuth2 requests.

Send sparse objects

When objects are sent to the API, fields must be deserialized, validated, and stored in the database. Passing in full objects when you only want to update a few fields can result in extra processing time and decreased performance. To mitigate this, the AdWords API supports sparse updates, allowing you to populate only the fields in an object that you wish to change or that are required. Fields that are unpopulated or have null values are left unchanged, increasing the performance of your requests.

For example, an app that updates keyword-level bids can benefit from using sparse updates, as only the adGroupID, criterionID, and bids fields would need to be populated. In a test using 150 keywords, a 20% performance increase was seen using sparse updates instead of passing fully populated objects.

Use compression

The AdWords API supports gzip compression on SOAP messages in both requests and responses. To enable gzip compression in a response, include these two HTTP headers in your request:

  • User-Agent: containing the string "gzip"
  • Accept-Encoding: with the value gzip


User-Agent: My App (gzip)
Accept-Encoding: gzip

If you're using a client library, see its documentation on enabling compression.

Error handling and management

During development, you're likely to encounter errors. This section describes considerations and strategies when building error management into your app.

In addition to this section, see the troubleshooting guide for more information on managing errors.

Distinguish request sources

Some apps are primarily interactive, issuing API calls directly in response to user-initiated actions in a UI. Others work primarily offline, issuing API calls as part of a periodic backend process. Many apps combine the two. When thinking about error management, it can be useful to distinguish these different types of requests.

For user-initiated requests, your primary concern should be providing a good experience for your users. Use the specific error that occurred to provide the user with as much context as possible in the UI. Where possible, offer easy steps they can take to resolve the error (see suggestions below).

For backend-initiated requests, implement handlers for the different types of errors your app may encounter (see suggestions below). Always include a default handler to address rare or previously unseen errors. A good approach for a default handler is to add the failed operation and error to a queue for a human operator to review and determine an appropriate resolution.

Distinguish error types

Below are four broad categories of errors, each of which should be handled differently. Though these categories don't encompass all possible errors, and some may fit into more than one category, they can nevertheless serve as a starting point for structuring your app's error handling. Refer to Common Errors for more details about a particular error.

  1. Authentication and authorization errors

    • Authentication refers to whether your app has been given permission by a user to access Google Ads on their behalf. Authentication is managed through credentials generated by the OAuth2 flow.

    • Authorization refers to whether your app, authenticated and acting as a user, is allowed to work with the particular Google Ads data it is trying to read or write.

      The most common reason an authentication error arises from factors beyond your control is when the authenticated user revokes the permission they gave your app to act on their behalf. For example, if your app manages separate Google Ads accounts for independent clients and authenticates separately as each client when managing that client's account, a client could revoke your app's access at any time. Depending on when your access was revoked, the API may directly return an AuthenticationError.OAUTH_TOKEN_REVOKED error, or the built-in credential objects in the client libraries may throw a token revoked exception. In either case, if your app has a UI for your clients, it could ask them to relaunch the OAuth2 flow to reestablish your app's permission to act on their behalf.

      Another common reason an authorization error arises from factors beyond your control is due to changes in your manager account hierarchy. Apps working with a single manager account hierarchy usually authenticate as an administrator user of their top-level manager account, since this user has the authority to access all of the sub-accounts in the hierarchy. If a user of a sub-account removes the manager link, your app will receive an AuthorizationError.USER_PERMISSION_DENIED error when attempting to access that account. You can use ManagedCustomerService to check whether the sub-account has indeed been removed from the hierarchy.

      Another reason an authorization error can arise is when the user your app authenticated as has their access rights changed. For example, suppose another user with administrator rights on the Google Ads account changes your app's authenticated user's rights to read-only. In this case, all mutate requests will fail with an AuthorizationError.USER_HAS_READONLY_PERMISSION error.

      For either example, your app could provide directions for the user, or escalate the issue to an account manager for resolution.

  2. Retryable errors

    Some errors can indicate a temporary problem that may be resolved by retrying the request after a short pause. These include CONCURRENT_MODIFICATION, UNEXPECTED_INTERNAL_API_ERROR, and RATE_EXCEEDED.

    For user-initiated requests, one strategy is to immediately indicate an error in your UI and give the user an option to trigger a retry. Alternatively, your app could first automatically retry the request, only exposing the error in the UI after reaching a maximum number of retries or total user wait time.

    For backend-initiated requests, your app should automatically retry the request up to a maximum number of retries.

    When you retry requests, use an exponential backoff policy. For example, if you first pause 5 seconds before the first retry, you could pause 10 seconds after the second and 20 seconds after the third retry. Exponential backoff helps ensure you are not calling the API too aggressively.

    For RATE_EXCEEDED errors, the amount of time your app pauses before attempting to retry should be at least longer than the retryAfterSeconds field in the error. See the Rate Limits guide for more details. Other retryable errors can be retried sooner but should still follow an exponential backoff policy.

  3. Validation errors

    Validation errors indicate that an input to an operation was not acceptable. Some examples include PolicyViolationError, DateError, DateRangeError, StringLengthError, UrlError, and many others.

    Validation errors occur most commonly in user-initiated requests, where a user has entered invalid input. In these cases, you should provide an appropriate error message to the user based on the specific API error you received. You can also validate user input for common mistakes before making an API call, making your app more responsive and your API usage more efficient.

    For backend-initiated requests, your app could add the failed operation to a queue for a human operator to review.

  4. Sync-related errors

    Many Google apps maintain a local database to store their Google Ads objects. One challenge to this approach is that the local database may go out of sync with the actual objects in Google Ads. For example, a user might delete an ad group directly in Google Ads, but the app and local database are unaware of the change and will issue API calls as if the ad group existed. These sync issues can manifest as a variety of errors such as INVALID_ID, DUPLICATE_CAMPAIGN_NAME, DUPLICATE_ADGROUP_NAME, AD_NOT_UNDER_ADGROUP, CANNOT_OPERATE_ON_REMOVED_ADGROUPAD, and many others.

    For user-initiated requests, one possible strategy is to alert the user to a possible sync problem, immediately launch a job that retrieves the relevant class of Google Ads objects and updates the local database, then prompt the user to refresh the UI.

    For backend-initiated requests, some errors provide enough information for your app to automatically and incrementally correct your local database. For example, CANNOT_OPERATE_ON_REMOVED_ADGROUPAD should cause your app to mark that ad as removed in your local database. Errors that you cannot handle in this way could cause your app to launch a more complete sync job or be added to a queue for a human operator to review.

Handle partial failures

By default, requests to the API are atomic: If an error occurs during just one operation in the request, all of the operations are aborted. Atomicity is a safe default, but in many cases is undesirable, as the operations might be independent and only the failed ones need to be reviewed. There are two strategies to address this default behavior.

The first strategy is to review the errors in the response, correlate them with the operation(s) that threw the errors, and issue a new request with only the operations that did not throw errors. These operations should now succeed. You could also pass the operations that threw errors to your error handling mechanism (see above) or queue them for review by a human operator.

The second strategy is to enable the partial failure flag in your API requests. When you enable this flag, each operation is treated independently, and an error in one will not prevent the others from being committed. Errors in specific operations are still returned normally. All of our client libraries support this flag.

The primary benefits of using the partial failure flag are simplicity and fewer API calls, as valid operations are committed automatically without you needing to retry them. For most apps, partial failure is appropriate.

However, in some apps it's more useful to have greater control over error handling. For example, suppose an app does not want policy errors in one ad to prevent other ads from being committed, but it does want other errors (such as those that signal a more significant issue) to abort the entire request. To implement this idea, the app should employ the first strategy above.

In either case, note that certain errors can reflect a dependence between operations either one of which would have been valid on its own. Examples include AdGroupAdError.ENTITY_REFERENCED_IN_MULTIPLE_OPS and AdParamError.AD_PARAM_CANNOT_BE_SPECIFIED_MULTIPLE_TIMES.

Sync backends

If your app's users have manual access to Google Ads accounts, they may make changes that your app is not aware of, causing your app's local database to go out of sync. As noted above, you can address sync-related errors reactively when they occur, but you can also seek to prevent them proactively. One proactive strategy is to run a nightly sync job on all your accounts, retrieving the Google Ads objects in your accounts and comparing against your local database. To make the retrieval efficient, consider using structure reports rather than the regular API services.

Log errors

All errors should be logged to facilitate debugging and monitoring. At a minimum, log the request ID, the operations that caused the error, and the error itself. Other information to log includes customer ID, API service, round-trip request latency, number of retries, and the raw SOAP request and response.

The client libraries provide built-in SOAP logging capabilities as well as the ability to retrieve the requestId header.

Be sure to monitor trends in API errors so that you can detect and address problems with your app. Consider building your own solution or employing one of many available commercial tools that can use your logs to produce interactive dashboards and send automated alerts.


Use test accounts

Test accounts are Google Ads accounts that do not actually serve ads. You can use a test account to experiment with the AdWords API and test that your app's connectivity, campaign management logic, or other processing are working as expected. Your developer token does not need to be approved to use it on a test account, so you can start developing with the AdWords API immediately after requesting a developer token, even before your app is reviewed.

Batch targeting ideas

When generating targeting ideas using TargetingIdeaService, the TargetingIdeaSelector accepts a RequestType of either IDEAS or STATS. STATS requests can be used to retrieve statistics of known keywords. To retrieve statistics for multiple keywords, combine them in a single request by listing the keywords in the RelatedToQuerySearchParameter. One TargetingIdea will be returned for each keyword. This is more efficient than making a separate request for each keyword.