A common use case of the AdWords API is to manage campaigns in an AdWords account. This guide will introduce you to the basic AdWords objects like Campaign, AdGroup, etc. that are required for campaign management, explain how they are related to one another, and how to work with them.
We recommend that you brush up your knowledge of AdWords as an advertising platform, and basic concepts about how the AdWords API works before reading this guide. Code examples in this guide use the AdWords API Java library. If you are looking for a client library in another programming language, you can check our complete list of client libraries. Also, the use of a client library is recommended but optional; you may use any SOAP kit in the programming language of your choice to make calls to the API.
Hierarchy and scope
Every AdWords account can be viewed as a hierarchy of objects. Under each account, there are Campaigns that represent advertisement campaigns you are running. Each campaign has multiple AdGroups, which are used to group your ads into logical collections. Each AdGroup has multiple AdGroupAds and AdGroupCriteria. AdGroupAd represents an ad that you are running, and AdGroupCriterion represents a criterion (e.g. keyword) that defines how the ads get triggered.
You can designate criteria at the campaign level which define campaign-wide rules on how the ads get triggered. Finally, there are ad extensions at the campaign level that allow you to provide extra information like phone number, street address, etc. to your ads.
Every object in AdWords is identified by its own ID. Some of these IDs are unique on a global level, while others are only unique within a confined scope, i.e., not on a global level. The uniqueness of each object ID within AdWords is listed below.
Object ID | Scope of uniqueness | Globally unique? |
---|---|---|
Budget ID | Global | Yes |
Campaign ID | Global | Yes |
AdGroup ID | Global | Yes |
Ad ID | Ad Group | No. (AdGroupId, AdId) pair is globally unique. |
AdGroupCriterion ID | Ad Group | No. (AdGroupId, CriterionId) pair is globally unique. |
CampaignCriterion ID | Campaign | No. (CampaignId, CriterionId) pair is globally unique. |
Ad Extensions | Campaign | No. (CampaignId, AdExtensionId) pair is globally unique. |
Feed ID | Global | Yes |
Feed Item ID | Global | Yes |
Feed Attribute ID | Feed | No |
Feed Mapping ID | Global | Yes |
Label ID | Global | Yes |
The above ID rules can be useful when designing a local database to store your AdWords objects.
If an object is derived from another object, then it will also have a
Type
field. For instance, TextAd
has a
Type
field to denote that it is derived from the Ad
object. If you're
using a dynamic language, you can use this field to check if an object is of
a certain type, e.g., check if an Ad
object is of type
TextAd
.
Methods and operations
The AdWords API provides services to manage AdWords objects. For instance,
CampaignService
manages Campaigns,
AdGroupService manages AdGroups, and so on. All such services expose two
standard methods: get
and mutate
.
The get method
As the name implies, get
is used to retrieve AdWords objects.
For instance, you can use
CampaignService.get
to retrieve the list of campaigns.
Every get
method takes a
Selector as input, and returns a
Page as a
result. The AdWords API doesn't return all the fields of an object by default;
you need to specify the list of
fields you want to retrieve when building the selector. You can use
predicates to filter your results,
ordering to sort your results and
dateRange to limit the time period for which you are retrieving the results.
You also need to specify
paging if you are pulling a lot of objects since the AdWords API will raise
a
SizeLimitError.RESPONSE_SIZE_LIMIT_EXCEEDED error if you try to pull a lot
of objects without paging. The following code snippet shows the above concepts
in action, where we retrieve and display all the campaigns in an account.
final int PAGE_SIZE = 100; int offset = 0; // Create selector. Selector selector = new Selector(); selector.setFields(new String[] {"Id", "Name"}); selector.setOrdering(new OrderBy[] {new OrderBy("Name", SortOrder.ASCENDING)}); selector.setPaging(new Paging(offset, PAGE_SIZE)); CampaignPage page = null; do { // Get all campaigns. page = campaignService.get(selector); // Display campaigns. if (page.getEntries() != null) { for (Campaign campaign : page.getEntries()) { System.out.println("Campaign with name \"" + campaign.getName() + "\" and id \"" + campaign.getId() + "\" was found."); } } else { System.out.println("No campaigns were found."); } offset += PAGE_SIZE; selector.getPaging().setStartIndex(offset); } while (offset < page.getTotalNumEntries());
You can learn more about selectors and their behaviors in this blog post or this video. In case you need to quickly look up the available selector fields for different services, you can refer to this guide.
Our client library distribution includes code examples for get methods of all the campaign management methods. For example, you can find the Java client library examples for campaign management services under the basicoperations and campaignmanagement folders of the code examples section.
The query method
The query
method is an alternative to get
that
doesn't use selectors, but rather a SQL-like language called
AWQL. The query
method is supported by most common services, although there still may be a few
where you have to use get
. AWQL does not support mutating data.
To show the power of AWQL, consider the example above. Instead of spending four lines writing the selector, you could alternatively write a single string that contains all the same information.
String awql = "SELECT Id, Name ORDER BY Name ASC LIMIT " + offset + "," + PAGE_SIZE;
Note that there is no FROM clause. This is because the service whose
query
method you are using already dictates what you are
selecting from. AWQL only supports the FROM clause when used for reports.
To use this string, you would simply call the service's query
method.
page = campaignService.query(awql);
The results of this call are the same as the results of the get
call in the example above. Overall, this can be a more succinct and intuitive
way to write the same requests as you would with a get
call. Use
whichever method you find easier; both are provided for your convenience. To
learn more, see the AWQL guide.
The mutate method
As the name implies, the mutate
method is used to mutate
(create, update or remove) an AdWords object. To mutate any object, you
need to build an appropriate
Operation object. For instance, you need to create a
CampaignOperation to mutate a
Campaign. The
operator field defines the type of operation you wish to perform (ADD, SET,
REMOVE), and the operand field holds the object you want to mutate. This code
snippet adds a campaign:
// Create campaign. Campaign campaign = new Campaign(); campaign.setName("Interplanetary Cruise #" + System.currentTimeMillis()); campaign.setStatus(CampaignStatus.PAUSED); campaign.setBiddingStrategy(new ManualCPC()); // You can optionally provide these field(s). campaign.setStartDate(new DateTime().plusDays(1).toString("yyyyMMdd")); campaign.setEndDate(new DateTime().plusDays(30).toString("yyyyMMdd")); campaign.setAdServingOptimizationStatus(AdServingOptimizationStatus.ROTATE); campaign.setFrequencyCap(new FrequencyCap(5L, TimeUnit.DAY, Level.ADGROUP)); // Only the budgetId should be sent, all other fields will be ignored by CampaignService. // You can use BudgetService to create a shared budget. Budget budget = new Budget(); budget.setBudgetId(budgetId); campaign.setBudget(budget); // Set the campaign network options to Search and Search Network. NetworkSetting networkSetting = new NetworkSetting(); networkSetting.setTargetGoogleSearch(true); networkSetting.setTargetSearchNetwork(true); networkSetting.setTargetContentNetwork(false); networkSetting.setTargetPartnerSearchNetwork(false); campaign.setNetworkSetting(networkSetting); GeoTargetTypeSetting geoTarget = new GeoTargetTypeSetting(); geoTarget.setPositiveGeoTargetType(GeoTargetTypeSettingPositiveGeoTargetType.DONT_CARE); KeywordMatchSetting keywordMatch = new KeywordMatchSetting(); keywordMatch.setOptIn(Boolean.FALSE); TargetRestrictSetting targetRestrict = new TargetRestrictSetting(); targetRestrict.setUseAdGroup(Boolean.TRUE); campaign.setSettings(new Setting[] {geoTarget, keywordMatch, targetRestrict}); // Create operations. CampaignOperation operation = new CampaignOperation(); operation.setOperand(campaign); operation.setOperator(Operator.ADD); CampaignOperation[] operations = new CampaignOperation[] {operation}; // Add campaigns. CampaignReturnValue result = campaignService.mutate(operations); // Display campaigns. for (Campaign campaignResult : result.getValue()) { System.out.println("Campaign with name \"" + campaignResult.getName() + "\" and id \"" + campaignResult.getId() + "\" was added."); }
Our client library distribution includes code examples for the mutate method of all the campaign management services. For example, you can find the Java client library examples for campaign management services under the basicoperations and campaignmanagement folders of the code examples section.
A common question associated with mutating objects is about the number of objects of a given type an AdWords account can hold. The limits for various types of AdWords objects are listed in this help center article. However, you should use this limit only as a guide when planning your campaigns and should not hard code these limits into your application.
Another point to keep in mind while making mutate calls is that it is better to send multiple operations per request than sending multiple requests with one operation per request, since this reduces the number of roundtrips to the server and thus increase your application performance. You should also try to group your requests by operations to a particular parent entity to increase performance. For example, if you are adding ads, then try to group your requests to add ads to one ad group at a time instead of a single request that adds ads to multiple ad groups. You can read more about these on our best practices guide.
The operator field
As discussed previously with the mutate
method, the
operator
field tells the AdWords API the nature of the mutate operation you wish to
perform - ADD, SET or REMOVE. As the name implies, ADD is for creating a new
object, SET is for updating an existing object, and REMOVE is for removing an
existing object. However, depending on how AdWords manages a certain type of
object, some of the operators may not be applicable for some services.
For example, an AdWords campaign cannot be permanently removed once you create it—you can only mark it as removed. While it is "removed" you can still query its details and stats.
The AdWords API doesn't support the REMOVE operator in CampaignService; you need to update a Campaign by changing its status to REMOVED using the SET operator. On the other hand, campaign targets are immutable—you can only use ADD or REMOVE on these objects. More details on how AdWords treats different objects are shown below:
Type | Newly Added | Enabled | Paused | Removed / Disabled |
---|---|---|---|---|
Campaign | action : mutate operation: ADD status : ENABLED |
action : mutate operation: SET status : ENABLED |
action : mutate operation: SET status: PAUSED |
action : mutate operation : SET status: REMOVED |
AdGroup | action: mutate operation: ADD status: ENABLED |
action : mutate operation: SET status : ENABLED |
action: mutate operation: SET status : PAUSED |
action : mutate operation: SET status: REMOVED |
AdGroupAd | action : mutate operation: ADD status: ENABLED |
action : mutate operation : SET status : ENABLED |
action : mutate operation : SET status : PAUSED |
action: mutate operation : REMOVE status: DISABLED |
BiddableAdGroupCriterion | action: mutate operation: ADD status: ENABLED |
action: mutate operation: SET status: ENABLED |
action: mutate operation: SET status: PAUSED |
action: mutate operation: REMOVE status: REMOVED |
UserList | action: mutate operation: ADD status: OPEN |
N/A | N/A | action: mutate operation: SET status: CLOSED |
Experiment | action: mutate operation: ADD status: ENABLED |
N/A | N/A | action: mutate operation: SET status: REMOVED |
Feed | action: mutate operation: ADD status: ENABLED |
N/A | N/A | action: mutate operation: REMOVE status: REMOVED |
FeedMapping | action: mutate operation: ADD status: ENABLED |
N/A | N/A | action: mutate operation: REMOVE status: REMOVED |
FeedItem | action: mutate operation: ADD status: ENABLED |
N/A | N/A | action: mutate operation: REMOVE status: REMOVED |
CustomerFeed | action: mutate operation: ADD status: ENABLED |
N/A | N/A | action: mutate operation: REMOVE status: REMOVED |
CampaignFeed | action: mutate operation: ADD status: ENABLED |
N/A | N/A | action: mutate operation: REMOVE status: REMOVED |
AdGroupFeed | action: mutate operation: ADD status: ENABLED |
N/A | N/A | action: mutate operation: REMOVE status: REMOVED |
Concurrent mutates
When building an AdWords API application, you will often find yourself mutating AdWords objects in parallel, such as when you are using multiple threads to get better throughput for your application, or maybe you have multiple users updating the same object using your application. So it is important to understand how AdWords handles concurrent mutate requests for the same object and to develop your application accordingly.
The general rule of mutating an AdWords object is that you cannot modify the same object concurrently. This includes updating the object from multiple threads in the same application or from different applications (e.g. your application and a simultaneous AdWords Editor session). The AdWords API doesn't provide a way to lock an object before updating, rather, it uses an optimistic approach for locking the objects. If the AdWords API finds that an object is being updated simultaneously by more than one source, it will raise a CONCURRENT_MODIFICATION_ERROR. You can learn more about AdWords API concurrency management in this blog post.
Asynchronous vs. synchronous mutates
AdWords API mutate methods are synchronous—meaning that if you make an API call, then the call returns only after the objects are mutated, or the call fails. While this approach is relatively simple to code, you also need to worry about several other things like load balancing, wasted resources while the machines wait for API calls to complete, etc.
An alternate approach is to mutate the objects asynchronously using MutateJobService. Using MutateJobService, you can create jobs that consist of potentially large batches of operations. Once the job is submitted, AdWords API servers execute the jobs in an asynchronous manner. This frees up your machine to perform other operations and periodically check the job status for completion. Another benefit of using asynchronous APIs is that they incur only 50% of the API cost of synchronous API calls. You can learn more about asynchronous APIs in this video or in batch processing guide.
Mutate validation
The validateOnly
SOAP header allows you to test your API calls,
without having to change any data. It is useful in checking for missing
parameters and incorrect field values. To use this feature, set
RequestHeader
's validateOnly
field to true
.
The client libraries set this to false
by default.
When overridden to true
, your request will be fully validated as
if it were going to be executed, but the final execution will be skipped. An
empty response will be returned if there are no errors. If validation fails,
useful error messages will be returned with messages about what failed.
Here's an example of how to set up validateOnly
using our Java
library.
Credential oAuth2Credential = new OfflineCredentials.Builder() .forApi(Api.ADWORDS) .fromFile() .build() .generateCredential(); AdWordsSession session = new AdWordsSession.Builder() .fromFile() .withOAuth2Credential(oAuth2Credential) .build(); session.setValidateOnly(true);
All API calls made using this session will now have the validateOnly
header set to true.
The validateOnly
header is particularly useful in checking ads
for common policy violations. Sometimes ads can be automatically rejected if
they fail certain criteria, like using specific words, punctuation,
capitalization, or length. If you try to upload ads in batches, one bad ad
could cause your entire batch to fail. Testing a new ad with validateOnly
will allow you to easily see which ads would be rejected. You can refer to
this code example to see this application in action.
Even without using the client library, all you need to do is set up the right SOAP header and you can still validate your mutate requests.