This guide introduces AdWords API objects and methods, using some common campaign management tasks as examples. It then describes the services offered by the API, with links to corresponding reference pages.
The AdWords API is meant for advanced Google Ads users. If you're new to Google Ads, or need to brush up on basic Google Ads concepts, check out the Google Ads basics pages.
Object hierarchy and scope
Every Google Ads account can be viewed as a hierarchy of objects.
Under each account, there are one or more Campaigns
that
represent advertising campaigns you are running.
Each campaign has multiple AdGroups
,
used to group your ads into logical collections.
Each AdGroup has multiple AdGroupAds
and
AdGroupCriteria
. An AdGroupAd
represents an ad that you're running. An AdGroupCriterion represents a criterion - a keyword - that
defines how the ads get triggered.
You can designate campaign criteria, that define campaign-wide rules on how ads get triggered. You can also specify campaign-wide budgets and dates.
Finally, there are ad extensions at the campaign level, that allow you to provide extra information to your ads, like phone number, street address, etc.
Object ID uniqueness
Every object in Google Ads is identified by its own ID. Some of these IDs are unique on a global level across all Google Ads accounts, while others are unique only within a confined scope. The uniqueness of each object ID within Google Ads 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 |
UserList ID | Global | Yes |
These ID rules can be useful when designing a local database to store your Google Ads objects.
If an object is derived from another object, it will also have a Type
field.
For instance, TextAd
has a
Type
field to indicate that it's derived from the Ad
object. If you're using a
dynamic language, you can use this field to check an object's type, for example,
to see if an Ad
object is of type TextAd
.
Methods and operations
The AdWords API provides services to manage Google Ads 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
The get()
method is used to retrieve Google Ads 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're retrieving the results.
You also need to specify
paging
if you are pulling a lot of objects. 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, which retrieves and displays all the campaigns in an account,
demonstrates these concepts in action:
Java
// Get the CampaignService. CampaignServiceInterface campaignService = adWordsServices.get(session, CampaignServiceInterface.class); int offset = 0; // Create selector. SelectorBuilder builder = new SelectorBuilder(); Selector selector = builder .fields(CampaignField.Id, CampaignField.Name) .orderAscBy(CampaignField.Name) .offset(offset) .limit(PAGE_SIZE) .build(); CampaignPage page; do { // Get all campaigns. page = campaignService.get(selector); // Display campaigns. if (page.getEntries() != null) { for (Campaign campaign : page.getEntries()) { System.out.printf("Campaign with name '%s' and ID %d was found.%n", campaign.getName(), campaign.getId()); } } else { System.out.println("No campaigns were found."); } offset += PAGE_SIZE; selector = builder.increaseOffsetBy(PAGE_SIZE).build(); } while (offset < page.getTotalNumEntries());
C#
using (CampaignService campaignService = (CampaignService) user.GetService(AdWordsService.v201809.CampaignService)) { // Create the selector. Selector selector = new Selector() { fields = new string[] { Campaign.Fields.Id, Campaign.Fields.Name, Campaign.Fields.Status }, paging = Paging.Default }; CampaignPage page = new CampaignPage(); try { do { // Get the campaigns. page = campaignService.get(selector); // Display the results. if (page != null && page.entries != null) { int i = selector.paging.startIndex; foreach (Campaign campaign in page.entries) { Console.WriteLine( "{0}) Campaign with id = '{1}', name = '{2}' and " + "status = '{3}' was found.", i + 1, campaign.id, campaign.name, campaign.status); i++; } } selector.paging.IncreaseOffset(); } while (selector.paging.startIndex < page.totalNumEntries); Console.WriteLine("Number of campaigns found: {0}", page.totalNumEntries); } catch (Exception e) { throw new System.ApplicationException("Failed to retrieve campaigns", e); }
Python
# Initialize appropriate service. campaign_service = client.GetService('CampaignService', version='v201809') # Construct selector and get all campaigns. offset = 0 selector = { 'fields': ['Id', 'Name', 'Status'], 'paging': { 'startIndex': str(offset), 'numberResults': str(PAGE_SIZE) } } more_pages = True while more_pages: page = campaign_service.get(selector) # Display results. if 'entries' in page: for campaign in page['entries']: print('Campaign with id "%s", name "%s", and status "%s" was ' 'found.' % (campaign['id'], campaign['name'], campaign['status'])) else: print('No campaigns were found.') offset += PAGE_SIZE selector['paging']['startIndex'] = str(offset) more_pages = offset < int(page['totalNumEntries'])
PHP
$campaignService = $adWordsServices->get($session, CampaignService::class); // Create selector. $selector = new Selector(); $selector->setFields(['Id', 'Name']); $selector->setOrdering([new OrderBy('Name', SortOrder::ASCENDING)]); $selector->setPaging(new Paging(0, self::PAGE_LIMIT)); $totalNumEntries = 0; do { // Make the get request. $page = $campaignService->get($selector); // Display results. if ($page->getEntries() !== null) { $totalNumEntries = $page->getTotalNumEntries(); foreach ($page->getEntries() as $campaign) { printf( "Campaign with ID %d and name '%s' was found.\n", $campaign->getId(), $campaign->getName() ); } } // Advance the paging index. $selector->getPaging()->setStartIndex( $selector->getPaging()->getStartIndex() + self::PAGE_LIMIT ); } while ($selector->getPaging()->getStartIndex() < $totalNumEntries); printf("Number of results found: %d\n", $totalNumEntries);
Perl
# Create selector. my $paging = Google::Ads::AdWords::v201809::Paging->new({ startIndex => 0, numberResults => PAGE_SIZE }); my $selector = Google::Ads::AdWords::v201809::Selector->new({ fields => ["Id", "Name"], ordering => [ Google::Ads::AdWords::v201809::OrderBy->new({ field => "Name", sortOrder => "ASCENDING" }) ], paging => $paging }); # Paginate through results. # The contents of the subroutine will be executed for each campaign. Google::Ads::AdWords::Utilities::PageProcessor->new({ client => $client, service => $client->CampaignService(), selector => $selector } )->process_entries( sub { my ($campaign) = @_; printf "Campaign with name \"%s\" and id \"%d\" was found.\n", $campaign->get_name(), $campaign->get_id(); });
Ruby
campaign_srv = adwords.service(:CampaignService, API_VERSION) # Get all the campaigns for this account. selector = { :fields => ['Id', 'Name', 'Status'], :ordering => [ {:field => 'Name', :sort_order => 'ASCENDING'} ], :paging => { :start_index => 0, :number_results => PAGE_SIZE } } # Set initial values. offset, page = 0, {} begin page = campaign_srv.get(selector) if page[:entries] page[:entries].each do |campaign| puts "Campaign ID %d, name '%s' and status '%s'" % [campaign[:id], campaign[:name], campaign[:status]] end # Increment values to request the next page. offset += PAGE_SIZE selector[:paging][:start_index] = offset end end while page[:total_num_entries] > offset if page.include?(:total_num_entries) puts "\tTotal number of campaigns found: %d." % [page[:total_num_entries]] end
VB.NET
Using campaignService As CampaignService = CType( user.GetService( AdWordsService.v201809.CampaignService), CampaignService) ' Create the selector. Dim selector As New Selector selector.fields = New String() { _ Campaign.Fields.Id, Campaign.Fields.Name, Campaign.Fields.Status } selector.paging = Paging.Default Dim page As New CampaignPage Try Do ' Get the campaigns. page = campaignService.get(selector) ' Display the results. If ((Not page Is Nothing) AndAlso (Not page.entries Is Nothing)) Then Dim i As Integer = selector.paging.startIndex For Each campaign As Campaign In page.entries Console.WriteLine( "{0}) Campaign with id = '{1}', name = '{2}' and status = " & "'{3}' was found.", i + 1, campaign.id, campaign.name, campaign.status) i += 1 Next End If selector.paging.IncreaseOffset() Loop While (selector.paging.startIndex < page.totalNumEntries) Console.WriteLine("Number of campaigns found: {0}", page.totalNumEntries) Catch e As Exception Throw New System.ApplicationException("Failed to retrieve campaign(s).", e) End Try
Refer to the selector fields reference page for the available selector fields for different services.
Our client libraries include code samples using the get()
method for all the campaign management services.
You can find the client library examples for campaign management services for each language below.
Java
C#
Python
PHP
Perl
Ruby
VB.NET
The query()
method
The query()
method is an alternative to get()
that uses a SQL-like language called
the AdWords Query Language (AWQL), instead of selectors. Coding the same
request in AWQL is usually more efficient. The query()
method is supported by most
common services. Note that AWQL does not support mutating data.
To show the efficiency of AWQL, consider the example above. Instead of writing four lines for the selector, you could write a single string that contains all the same information.
Java
ServiceQuery serviceQuery = new ServiceQuery.Builder() .fields(CampaignField.Id, CampaignField.Name, CampaignField.Status) .orderBy(CampaignField.Name) .limit(0, PAGE_SIZE) .build();
C#
// Create the query. SelectQuery query = new SelectQueryBuilder() .Select(Campaign.Fields.Name, Campaign.Fields.Id, Campaign.Fields.Status) .OrderByAscending(Campaign.Fields.Name) .DefaultLimit() .Build();
Python
query = (adwords.ServiceQueryBuilder() .Select('Id', 'Name', 'Status') .Where('Status').EqualTo('ENABLED') .OrderBy('Name') .Limit(0, PAGE_SIZE) .Build())
PHP
$query = (new ServiceQueryBuilder()) ->select(['Id', 'Name', 'Status']) ->orderByAsc('Name') ->limit(0, self::PAGE_LIMIT) ->build();
Perl
my $query = Google::Ads::AdWords::Utilities::ServiceQueryBuilder->new( {client => $client}) ->select(["Id", "Name", "Status"]) ->order_by("Name") ->build();
Ruby
# Get all the campaigns for this account. query_builder = adwords.service_query_builder do |b| b.select('Id', 'Name', 'Status') b.order_by_asc('Name') b.limit(0, PAGE_SIZE) end query = query_builder.build
VB.NET
' Create the query. Dim query As SelectQuery = New SelectQueryBuilder() _ .Select(Campaign.Fields.Name, Campaign.Fields.Id, Campaign.Fields.Status) _ .OrderByAscending(Campaign.Fields.Name) _ .DefaultLimit() _ .Build()
Note that there is no FROM
clause. This is because the service whose
query()
method you're using already dictates what you're 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.
Java
CampaignPage page = null; do { serviceQuery.nextPage(page); // Get all campaigns. page = campaignService.query(serviceQuery.toString()); // Display campaigns. if (page.getEntries() != null) { for (Campaign campaign : page.getEntries()) { System.out.printf("Campaign with name '%s' and ID %d was found.%n", campaign.getName(), campaign.getId()); } } else { System.out.println("No campaigns were found."); } } while (serviceQuery.hasNext(page));
C#
CampaignPage page = new CampaignPage(); int i = 0; try { do { // Get the campaigns. page = campaignService.query(query); // Display the results. if (page != null && page.entries != null) { foreach (Campaign campaign in page.entries) { Console.WriteLine( "{0}) Campaign with id = '{1}', name = '{2}' and status = " + "'{3}' was found.", i + 1, campaign.id, campaign.name, campaign.status); i++; } } query.NextPage(page); } while (query.HasNextPage(page)); Console.WriteLine("Number of campaigns found: {0}", page.totalNumEntries); } catch (Exception e) { throw new System.ApplicationException("Failed to retrieve campaigns", e); }
Python
for page in query.Pager(campaign_service): # Display results. if 'entries' in page: for campaign in page['entries']: print('Campaign with id "%s", name "%s", and status "%s" was ' 'found.' % (campaign['id'], campaign['name'], campaign['status'])) else: print('No campaigns were found.')
PHP
do { // Advance the paging offset in subsequent iterations only. if (isset($page)) { $query->nextPage(); } // Make a request using an AWQL string. This request will return the // first page containing up to `self::PAGE_LIMIT` results $page = $campaignService->query(sprintf('%s', $query)); // Display results from second and subsequent pages. if ($page->getEntries() !== null) { foreach ($page->getEntries() as $campaign) { printf( "Campaign with ID %d and name '%s' was found.\n", $campaign->getId(), $campaign->getName() ); } } } while ($query->hasNext($page)); printf( "Number of results found: %d\n", $page->getTotalNumEntries() );
Perl
Google::Ads::AdWords::Utilities::PageProcessor->new({ client => $client, service => $client->CampaignService(), query => $query, page_size => PAGE_SIZE } )->process_entries( sub { my ($campaign) = @_; printf "Campaign with name \"%s\" and id \"%d\" was found.\n", $campaign->get_name(), $campaign->get_id(); });
Ruby
loop do page_query = query.to_s page = campaign_srv.query(page_query) if page[:entries] page[:entries].each do |campaign| puts "Campaign ID %d, name '%s' and status '%s'" % [campaign[:id], campaign[:name], campaign[:status]] end end break unless query.has_next(page) query.next_page end if page.include?(:total_num_entries) puts "\tTotal number of campaigns found: %d." % page[:total_num_entries] end
VB.NET
Dim page As New CampaignPage() Dim i As Integer = 0 Try Do ' Get the campaigns. page = campaignService.query(query) ' Display the results. If ((Not page Is Nothing) AndAlso (Not page.entries Is Nothing)) Then For Each campaign As Campaign In page.entries Console.WriteLine( "{0}) Campaign with id = '{1}', name = '{2}' and status = " & "'{3}' was found.", i, campaign.id, campaign.name, campaign.status) i += 1 Next End If query.NextPage(page) Loop While (query.HasNextPage(page)) Console.WriteLine("Number of campaigns found: {0}", page.totalNumEntries) Catch e As Exception Throw New System.ApplicationException("Failed to retrieve campaign(s).", e) End Try
The above code produces the same results as a call to the get()
method. AWQL
can be a more succinct and intuitive way to write the same requests you would
with calling get()
. To learn more, see the AWQL
guide.
The mutate()
method
The mutate()
method is used to mutate (create, update, or remove) an Google
Ads object.
To mutate an object, you must build a corresponding
Operation
object. For instance, you must create a
CampaignOperation
to mutate a
Campaign
.
The operator
field defines the
type of operation you want to perform (ADD
, SET
, or REMOVE
). The operand field holds the object you want to
mutate. The following code snippet adds campaigns:
Java
// Get the CampaignService. CampaignServiceInterface campaignService = adWordsServices.get(session, CampaignServiceInterface.class); // Create campaign. Campaign campaign = new Campaign(); campaign.setName("Interplanetary Cruise #" + System.currentTimeMillis()); // Recommendation: Set the campaign to PAUSED when creating it to prevent // the ads from immediately serving. Set to ENABLED once you've added // targeting and the ads are ready to serve. campaign.setStatus(CampaignStatus.PAUSED); BiddingStrategyConfiguration biddingStrategyConfiguration = new BiddingStrategyConfiguration(); biddingStrategyConfiguration.setBiddingStrategyType(BiddingStrategyType.MANUAL_CPC); // You can optionally provide a bidding scheme in place of the type. ManualCpcBiddingScheme cpcBiddingScheme = new ManualCpcBiddingScheme(); biddingStrategyConfiguration.setBiddingScheme(cpcBiddingScheme); campaign.setBiddingStrategyConfiguration(biddingStrategyConfiguration); // You can optionally provide these field(s). campaign.setStartDate(DateTime.now().plusDays(1).toString("yyyyMMdd")); campaign.setEndDate(DateTime.now().plusDays(30).toString("yyyyMMdd")); campaign.setFrequencyCap(new FrequencyCap(5L, TimeUnit.DAY, Level.ADGROUP)); // Only the budgetId should be sent, all other fields will be ignored by CampaignService. Budget budget = new Budget(); budget.setBudgetId(budgetId); campaign.setBudget(budget); campaign.setAdvertisingChannelType(AdvertisingChannelType.SEARCH); // 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); // Set options that are not required. GeoTargetTypeSetting geoTarget = new GeoTargetTypeSetting(); geoTarget.setPositiveGeoTargetType(GeoTargetTypeSettingPositiveGeoTargetType.DONT_CARE); campaign.setSettings(new Setting[] {geoTarget}); // You can create multiple campaigns in a single request. Campaign campaign2 = new Campaign(); campaign2.setName("Interplanetary Cruise banner #" + System.currentTimeMillis()); campaign2.setStatus(CampaignStatus.PAUSED); BiddingStrategyConfiguration biddingStrategyConfiguration2 = new BiddingStrategyConfiguration(); biddingStrategyConfiguration2.setBiddingStrategyType(BiddingStrategyType.MANUAL_CPC); campaign2.setBiddingStrategyConfiguration(biddingStrategyConfiguration2); Budget budget2 = new Budget(); budget2.setBudgetId(budgetId); campaign2.setBudget(budget2); campaign2.setAdvertisingChannelType(AdvertisingChannelType.DISPLAY); // Create operations. CampaignOperation operation = new CampaignOperation(); operation.setOperand(campaign); operation.setOperator(Operator.ADD); CampaignOperation operation2 = new CampaignOperation(); operation2.setOperand(campaign2); operation2.setOperator(Operator.ADD); CampaignOperation[] operations = new CampaignOperation[] {operation, operation2}; // Add campaigns. CampaignReturnValue result = campaignService.mutate(operations); // Display campaigns. for (Campaign campaignResult : result.getValue()) { System.out.printf("Campaign with name '%s' and ID %d was added.%n", campaignResult.getName(), campaignResult.getId()); }
C#
List<CampaignOperation> operations = new List<CampaignOperation>(); for (int i = 0; i < NUM_ITEMS; i++) { // Create the campaign. Campaign campaign = new Campaign { name = "Interplanetary Cruise #" + ExampleUtilities.GetRandomString(), advertisingChannelType = AdvertisingChannelType.SEARCH, // Recommendation: Set the campaign to PAUSED when creating it to prevent // the ads from immediately serving. Set to ENABLED once you've added // targeting and the ads are ready to serve. status = CampaignStatus.PAUSED }; BiddingStrategyConfiguration biddingConfig = new BiddingStrategyConfiguration { biddingStrategyType = BiddingStrategyType.MANUAL_CPC }; campaign.biddingStrategyConfiguration = biddingConfig; campaign.budget = new Budget { budgetId = budget.budgetId }; // Set the campaign network options. campaign.networkSetting = new NetworkSetting { targetGoogleSearch = true, targetSearchNetwork = true, targetContentNetwork = false, targetPartnerSearchNetwork = false }; // Set the campaign settings for Advanced location options. GeoTargetTypeSetting geoSetting = new GeoTargetTypeSetting { positiveGeoTargetType = GeoTargetTypeSettingPositiveGeoTargetType.DONT_CARE, negativeGeoTargetType = GeoTargetTypeSettingNegativeGeoTargetType.DONT_CARE }; campaign.settings = new Setting[] { geoSetting }; // Optional: Set the start date. campaign.startDate = DateTime.Now.AddDays(1).ToString("yyyyMMdd"); // Optional: Set the end date. campaign.endDate = DateTime.Now.AddYears(1).ToString("yyyyMMdd"); // Optional: Set the frequency cap. FrequencyCap frequencyCap = new FrequencyCap { impressions = 5, level = Level.ADGROUP, timeUnit = TimeUnit.DAY }; campaign.frequencyCap = frequencyCap; // Create the operation. CampaignOperation operation = new CampaignOperation { @operator = Operator.ADD, operand = campaign }; operations.Add(operation); } try { // Add the campaign. CampaignReturnValue retVal = campaignService.mutate(operations.ToArray()); // Display the results. if (retVal != null && retVal.value != null && retVal.value.Length > 0) { foreach (Campaign newCampaign in retVal.value) { Console.WriteLine( "Campaign with name = '{0}' and id = '{1}' was added.", newCampaign.name, newCampaign.id); } } else { Console.WriteLine("No campaigns were added."); } } catch (Exception e) { throw new System.ApplicationException("Failed to add campaigns.", e); }
Python
operations = [{ 'operator': 'ADD', 'operand': { 'name': 'Interplanetary Cruise #%s' % uuid.uuid4(), # Recommendation: Set the campaign to PAUSED when creating it to # stop the ads from immediately serving. Set to ENABLED once you've # added targeting and the ads are ready to serve. 'status': 'PAUSED', 'advertisingChannelType': 'SEARCH', 'biddingStrategyConfiguration': { 'biddingStrategyType': 'MANUAL_CPC', }, 'endDate': (datetime.datetime.now() + datetime.timedelta(365)).strftime('%Y%m%d'), # Note that only the budgetId is required 'budget': { 'budgetId': budget_id }, 'networkSetting': { 'targetGoogleSearch': 'true', 'targetSearchNetwork': 'true', 'targetContentNetwork': 'false', 'targetPartnerSearchNetwork': 'false' }, # Optional fields 'startDate': (datetime.datetime.now() + datetime.timedelta(1)).strftime('%Y%m%d'), 'frequencyCap': { 'impressions': '5', 'timeUnit': 'DAY', 'level': 'ADGROUP' }, 'settings': [ { 'xsi_type': 'GeoTargetTypeSetting', 'positiveGeoTargetType': 'DONT_CARE', 'negativeGeoTargetType': 'DONT_CARE' } ] } }, { 'operator': 'ADD', 'operand': { 'name': 'Interplanetary Cruise banner #%s' % uuid.uuid4(), 'status': 'PAUSED', 'biddingStrategyConfiguration': { 'biddingStrategyType': 'MANUAL_CPC' }, 'endDate': (datetime.datetime.now() + datetime.timedelta(365)).strftime('%Y%m%d'), # Note that only the budgetId is required 'budget': { 'budgetId': budget_id }, 'advertisingChannelType': 'DISPLAY' } }] campaigns = campaign_service.mutate(operations) # Display results. for campaign in campaigns['value']: print('Campaign with name "%s" and id "%s" was added.' % (campaign['name'], campaign['id']))
PHP
$campaignService = $adWordsServices->get($session, CampaignService::class); $operations = []; // Create a campaign with required and optional settings. $campaign = new Campaign(); $campaign->setName('Interplanetary Cruise #' . uniqid()); $campaign->setAdvertisingChannelType(AdvertisingChannelType::SEARCH); // Set shared budget (required). $campaign->setBudget(new Budget()); $campaign->getBudget()->setBudgetId($budget->getBudgetId()); // Set bidding strategy (required). $biddingStrategyConfiguration = new BiddingStrategyConfiguration(); $biddingStrategyConfiguration->setBiddingStrategyType( BiddingStrategyType::MANUAL_CPC ); // You can optionally provide a bidding scheme in place of the type. $biddingScheme = new ManualCpcBiddingScheme(); $biddingStrategyConfiguration->setBiddingScheme($biddingScheme); $campaign->setBiddingStrategyConfiguration($biddingStrategyConfiguration); // Set network targeting (optional). $networkSetting = new NetworkSetting(); $networkSetting->setTargetGoogleSearch(true); $networkSetting->setTargetSearchNetwork(true); $networkSetting->setTargetContentNetwork(true); $campaign->setNetworkSetting($networkSetting); // Set additional settings (optional). // Recommendation: Set the campaign to PAUSED when creating it to stop // the ads from immediately serving. Set to ENABLED once you've added // targeting and the ads are ready to serve. $campaign->setStatus(CampaignStatus::PAUSED); $campaign->setStartDate(date('Ymd', strtotime('+1 day'))); $campaign->setEndDate(date('Ymd', strtotime('+1 month'))); // Set frequency cap (optional). $frequencyCap = new FrequencyCap(); $frequencyCap->setImpressions(5); $frequencyCap->setTimeUnit(TimeUnit::DAY); $frequencyCap->setLevel(Level::ADGROUP); $campaign->setFrequencyCap($frequencyCap); // Set advanced location targeting settings (optional). $geoTargetTypeSetting = new GeoTargetTypeSetting(); $geoTargetTypeSetting->setPositiveGeoTargetType( GeoTargetTypeSettingPositiveGeoTargetType::DONT_CARE ); $geoTargetTypeSetting->setNegativeGeoTargetType( GeoTargetTypeSettingNegativeGeoTargetType::DONT_CARE ); $campaign->setSettings([$geoTargetTypeSetting]); // Create a campaign operation and add it to the operations list. $operation = new CampaignOperation(); $operation->setOperand($campaign); $operation->setOperator(Operator::ADD); $operations[] = $operation; // Create a campaign with only required settings. $campaign = new Campaign(); $campaign->setName('Interplanetary Cruise #' . uniqid()); $campaign->setAdvertisingChannelType(AdvertisingChannelType::DISPLAY); // Set shared budget (required). $campaign->setBudget(new Budget()); $campaign->getBudget()->setBudgetId($budget->getBudgetId()); // Set bidding strategy (required). $biddingStrategyConfiguration = new BiddingStrategyConfiguration(); $biddingStrategyConfiguration->setBiddingStrategyType( BiddingStrategyType::MANUAL_CPC ); $campaign->setBiddingStrategyConfiguration($biddingStrategyConfiguration); $campaign->setStatus(CampaignStatus::PAUSED); // Create a campaign operation and add it to the operations list. $operation = new CampaignOperation(); $operation->setOperand($campaign); $operation->setOperator(Operator::ADD); $operations[] = $operation; // Create the campaigns on the server and print out some information for // each created campaign. $result = $campaignService->mutate($operations); foreach ($result->getValue() as $campaign) { printf( "Campaign with name '%s' and ID %d was added.\n", $campaign->getName(), $campaign->getId() ); }
Perl
# Create campaigns. my $num_campaigns = 2; my @operations = (); for (my $i = 0 ; $i < $num_campaigns ; $i++) { my (undef, undef, undef, $mday, $mon, $year) = localtime(time); my $today = sprintf("%d%02d%02d", ($year + 1900), ($mon + 1), $mday); (undef, undef, undef, $mday, $mon, $year) = localtime(time + 60 * 60 * 24); my $tomorrow = sprintf("%d%02d%02d", ($year + 1900), ($mon + 1), $mday); my $campaign = Google::Ads::AdWords::v201809::Campaign->new({ name => "Interplanetary Cruise #" . uniqid(), # Bidding strategy (required). biddingStrategyConfiguration => Google::Ads::AdWords::v201809::BiddingStrategyConfiguration->new({ biddingStrategyType => "MANUAL_CPC", # You can optionally provide a bidding scheme in place of the type. } ), # Budget (required) - note only the budgetId is required. budget => Google::Ads::AdWords::v201809::Budget->new({budgetId => $budgetId}), # Create a Search Network with Display Select campaign. # To create a Display Only campaign, omit networkSetting and use the # DISPLAY advertisingChannelType. # NetworkSetting (optional). networkSetting => Google::Ads::AdWords::v201809::NetworkSetting->new({ targetGoogleSearch => 1, targetSearchNetwork => 1, targetContentNetwork => 1, targetPartnerSearchNetwork => 0 } ), # Advertising channel type (required). advertisingChannelType => "SEARCH", # Frequency cap (non-required). frequencyCap => Google::Ads::AdWords::v201809::FrequencyCap->new({ impressions => 5, timeUnit => "DAY", level => "ADGROUP" } ), settings => [ # Advanced location targeting settings (non-required). Google::Ads::AdWords::v201809::GeoTargetTypeSetting->new({ positiveGeoTargetType => "DONT_CARE", negativeGeoTargetType => "DONT_CARE" } ), ], # Additional properties (non-required). startDate => $today, endDate => $tomorrow, # Recommendation: Set the campaign to PAUSED when creating it to stop # the ads from immediately serving. Set to ENABLED once you've added # targeting and the ads are ready to serve. status => "PAUSED" }); # Create operation. my $campaign_operation = Google::Ads::AdWords::v201809::CampaignOperation->new({ operator => "ADD", operand => $campaign }); push @operations, $campaign_operation; } # Add campaigns. my $result = $client->CampaignService()->mutate({operations => \@operations}); # Display campaigns. foreach my $campaign (@{$result->get_value()}) { printf "Campaign with name \"%s\" and id \"%s\" was added.\n", $campaign->get_name(), $campaign->get_id(); }
Ruby
campaign_srv = adwords.service(:CampaignService, API_VERSION) # Create campaigns. campaigns = [ { :name => "Interplanetary Cruise #%d" % (Time.new.to_f * 1000).to_i, # Recommendation: Set the campaign to PAUSED when creating it to stop the # ads from immediately serving. Set to ENABLED once you've added # targeting and the ads are ready to serve. :status => 'PAUSED', :bidding_strategy_configuration => { :bidding_strategy_type => 'MANUAL_CPC' }, # Budget (required) - note only the budget ID is required. :budget => {:budget_id => budget_id}, :advertising_channel_type => 'SEARCH', # Optional fields: :start_date => DateTime.parse((Date.today + 1).to_s).strftime('%Y%m%d'), :network_setting => { :target_google_search => true, :target_search_network => true, :target_content_network => true }, :settings => [ { :xsi_type => 'GeoTargetTypeSetting', :positive_geo_target_type => 'DONT_CARE', :negative_geo_target_type => 'DONT_CARE' } ], :frequency_cap => { :impressions => '5', :time_unit => 'DAY', :level => 'ADGROUP' } }, { :name => "Interplanetary Cruise banner #%d" % (Time.new.to_f * 1000).to_i, :status => 'PAUSED', :bidding_strategy_configuration => { :bidding_strategy_type => 'MANUAL_CPC' }, :budget => {:budget_id => budget_id}, :advertising_channel_type => 'DISPLAY' } ] # Prepare for adding campaign. operations = campaigns.map do |campaign| {:operator => 'ADD', :operand => campaign} end # Add campaign. response = campaign_srv.mutate(operations) if response and response[:value] response[:value].each do |campaign| puts "Campaign with name '%s' and ID %d was added." % [campaign[:name], campaign[:id]] end else raise new StandardError, 'No campaigns were added.' end
VB.NET
Dim operations As New List(Of CampaignOperation) For i As Integer = 1 To NUM_ITEMS ' Create the campaign. Dim campaign As New Campaign campaign.name = "Interplanetary Cruise #" & ExampleUtilities.GetRandomString campaign.advertisingChannelType = AdvertisingChannelType.SEARCH ' Recommendation: Set the campaign to PAUSED when creating it to prevent ' the ads from immediately serving. Set to ENABLED once you've added ' targeting and the ads are ready to serve. campaign.status = CampaignStatus.PAUSED Dim biddingConfig As New BiddingStrategyConfiguration() biddingConfig.biddingStrategyType = BiddingStrategyType.MANUAL_CPC campaign.biddingStrategyConfiguration = biddingConfig ' Set the campaign budget. campaign.budget = New Budget campaign.budget.budgetId = budget.budgetId ' Set the campaign network options. campaign.networkSetting = New NetworkSetting campaign.networkSetting.targetGoogleSearch = True campaign.networkSetting.targetSearchNetwork = True campaign.networkSetting.targetContentNetwork = False campaign.networkSetting.targetPartnerSearchNetwork = False ' Set the campaign geo target and keyword match settings. Dim geoSetting As New GeoTargetTypeSetting geoSetting.positiveGeoTargetType = GeoTargetTypeSettingPositiveGeoTargetType.DONT_CARE geoSetting.negativeGeoTargetType = GeoTargetTypeSettingNegativeGeoTargetType.DONT_CARE campaign.settings = New Setting() {geoSetting} ' Optional: Set the start date. campaign.startDate = DateTime.Now.AddDays(1).ToString("yyyyMMdd") ' Optional: Set the end date. campaign.endDate = DateTime.Now.AddYears(1).ToString("yyyyMMdd") ' Optional: Set the frequency cap. Dim frequencyCap As New FrequencyCap frequencyCap.impressions = 5 frequencyCap.level = Level.ADGROUP frequencyCap.timeUnit = TimeUnit.DAY campaign.frequencyCap = frequencyCap ' Create the operation. Dim operation As New CampaignOperation operation.operator = [Operator].ADD operation.operand = campaign operations.Add(operation) Next Try ' Add the campaign. Dim retVal As CampaignReturnValue = campaignService.mutate(operations.ToArray()) ' Display the results. If ((Not retVal Is Nothing) AndAlso (Not retVal.value Is Nothing) AndAlso (retVal.value.Length > 0)) Then For Each newCampaign As Campaign In retVal.value Console.WriteLine( "Campaign with name = '{0}' and id = '{1}' was added.", newCampaign.name, newCampaign.id) Next Else Console.WriteLine("No campaigns were added.") End If Catch e As Exception Throw New System.ApplicationException("Failed to add campaigns.", e) End Try End Using
Our client libraries include code examples using the
mutate()
method for all the campaign management services.
When mutating objects, there are limits to the number of objects of a given type an Google Ads account can hold. The limits for various types of Google Ads objects are listed in this help center article. You should use these limits only as a guide when planning your campaigns, rather than hard-coding them into your application.
When calling mutate()
, it's better to send multiple operations per request,
than to send multiple requests with one operation per request. Sending multiple
operations per request reduces the number of roundtrips to the server and improves
your app's performance.
Another optimization trick is to group your requests by operations to a single parent entity. For example, if you're adding ads, try grouping your requests to one ad group at a time, instead of one request to multiple ad groups. See the Best Practices guide for more information.
The operator field
As mentioned above, the
operator
field
indicates the type of mutate operation you wish to perform: ADD
, SET
, or
REMOVE
.
ADD
is for creating a new object, SET
is for updating an existing object,
and REMOVE
is for removing an existing object. However, some operators may not
be applicable for some services.
For example, an Google Ads 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.
In contrast, campaign targets cannot be changed—you can only use ADD
or
REMOVE
on these objects.
The table below details how to control the flow of different Google Ads objects to achieve a desired status:
Type | Add new object | Enable | Pause | Remove / Disable |
---|---|---|---|---|
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 |
Budget |
action : mutate() operation: ADD status : ENABLED |
N/A | N/A | 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 |
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
If you have multiple users updating the same object with your app, or if you're mutating Google Ads objects in parallel using multiple threads for better throughput, it's important to understand how Google Ads handles concurrent mutate requests for the same object.
An Google Ads object cannot be modified concurrently by more than one source. This
includes updating the object from multiple threads in the same application, or from different applications
(for example, your app and a simultaneous AdWords Editor session). The API doesn't
provide a way to lock an object before updating: If two sources try to simultaneously
mutate an object, the API raises 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: API calls return a response only
after the objects are mutated, requiring you to wait for a response to each request.
While this approach is relatively simple to code, it could negatively impact load balancing,
and cause wasted resources while the machines wait for a call to complete.
An alternate approach is to mutate the objects asynchronously using BatchJobService, which provides a way to perform batches of operations on multiple services without waiting for the operations to complete. Once the batch job is submitted, AdWords API servers execute the operations asynchronously, freeing your machine to perform other operations, and to periodically check the job status for completion.
See the Batch Processing guide for more on asynchronous processing.
Mutate validation
The validateOnly
SOAP header allows you to test your API calls without actually executing the call against
real data: You can test for missing parameters and incorrect field values without actually
executing the operation.
To use this feature, set the validateOnly
field to true
in the RequestHeader
. The client
libraries set this to false
by default.
The request is fully validated as if it were going to be executed, but the final execution is skipped. If no errors are found, an empty response is returned. If validation fails, error messages indicate the failure points.
Here's an example of how to set up validateOnly
, using the 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 have the validateOnly
header set to true
.
The validateOnly
header is particularly useful in testing ads for common
policy violations. Ads are automatically rejected if they violate policies 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
allows you to easily
see which ads would be rejected. Refer to the
code example for
handling policy violation errors
to see this in action.
If you're not using a client library, all you need to do is set up the right
SOAP header and you can still validate your mutate()
requests.
AdWords API services
This section describes the services provided by the AdWords API, with links to reference pages containing additional details for each service.
The AdWords API services can be grouped into four functional categories:
Campaign data management
Use the campaign data management services to work with Google Ads campaigns and their associated entities. Each campaign data management service corresponds to an entity in the campaign data hierarchy.
Service | Description |
---|---|
CampaignService | Create, update, and remove campaigns. A campaign organizes one or more ad groups, and has its own budget, bidding strategy, serving date range, and targeting settings. |
AdGroupService | Create, update, and remove ad groups. An ad group organizes a set of ads and criteria together, and also provides the default bid for its criteria. |
AdGroupAdService | Create, update, and remove ads. |
CampaignExtensionSettingService | Create, update, and remove ad extensions. Campaign ad extensions enrich standard text ads by adding location information, additional links, or a phone number, to all ads within a campaign. |
CampaignCriterionService AdGroupCriterionService |
Create, update, and remove criteria. A criterion describes the conditions that determine whether an ad should appear. |
ConversionTrackerService OfflineConversionFeedService |
Measure the effectiveness of your ads and keywords by learning what happens after a user clicks on your ad. OfflineConversionFeedService handles importing offline conversions. |
DataService | Retrieve ads campaign management data, based on specified criteria. |
FeedService FeedItemService FeedMappingService AdGroupFeedService CampaignFeedService | Create custom data feeds to manage site, phone, and app link extensions. |
AdwordsUserListService | Create, update, and remove user lists. User lists and user list criteria display ads to people who have previously triggered a conversion event on your website. |
BudgetService | Create, update, and remove budgets. Used to manage budgets that can be shared across campaigns. |
Optimization
Use the optimization services to retrieve performance statistics and discover ideas for new criteria.
Service | Description |
---|---|
ReportDefinitionService | Create and download a variety of performance reports. |
TargetingIdeaService | Generate new keyword and placement ideas based on parameters you specify. |
TrafficEstimatorService | Get traffic estimates for proposed campaigns, ad groups, and keywords. |
DraftService and TrialService | Create new drafts and trials for testing your campaign settings. See this guide for details. |
Account Management
Use the account management services to track your account activity.
Service | Description |
---|---|
CustomerService | Retrieve basic details about a client account. |
CustomerSyncService | Retrieve a record of campaign data changes within a specified date range. |
ManagedCustomerService | Manage client accounts and links between manager and client accounts. |
Utility
Use these utility services to perform various useful tasks with the AdWords API.
Service | Description |
---|---|
BatchJobService | Process a large batch of campaign data operations asynchronously. Batch processing jobs take longer to complete than synchronous calls to the standard web services, but offer other advantages as described in the Batch Processing guide. |
MediaService | Upload and retrieve IDs for media you use in media-based ads (such as image or video ads). |
ConstantDataService | Retrieve constant values used by the API. |
LocationCriterionService | Retrieve the ID of a Location criterion. |
Campaign data
Working with campaign data is one of the fundamental tasks you perform with the AdWords API. The table below describes each campaign data entity and its relationship with other campaign data.
Entity
Child Entities (quantity)
|
Data Type | Description |
---|---|---|
Campaign
Ad groups (1+)
Campaign target lists (7)
Campaign ad extensions (0+)
Campaign criteria (0+)
|
Campaign
|
Campaigns organize one or more ad groups, and have their own budget, bidding strategy, and serving date range. |
Ad Group
Ads (1+)
Criteria (1+)
|
AdGroup
|
An ad group organizes a set of ads and criteria, and also provides the default bid for its criteria. |
Ad
Ad extension overrides (0+)
|
AdGroupAd
|
Available ad types are documented in the API reference as subclasses of
the abstract Ad
type. |
Criterion
None
|
AdGroupCriterion ,
CampaignCriterion |
A criterion describes the conditions that determine if an ad should appear (biddable criterion) or should not appear (negative criterion). An ad group criterion affects ads in the parent ad group. A campaign criterion, which is always a negative criterion, defines conditions that prevent the campaign's ads from showing. |
Ad Extension
None
|
CampaignExtensionSetting
|
Campaign ad extensions enrich standard text ads by adding location information, additional links, or a phone number, to all ads within a campaign. |
Feed
None
|
Feed
|
Feeds act as conduits for data to ad extensions (sitelink, phone, app). |
User List
None
|
UserList
|
User lists keep track of which users have previously expressed interest in your website. You can target ads to this set of users by creating a user list criterion and linking it to an existing user list. |
Budget
None
|
Budget
|
Budgets are used for managing the amount of money spent on campaigns. A Budget can be shared across different campaigns and the system will determine the optimal allocation. |