Advanced Operations Samples

The code samples below provide examples of common advanced operations using the AdWords API. Client Library.

Add an ad customizer feed

#!/usr/bin/env python
#
# Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Adds an ad customizer feed.

Associates the feed with customer and adds an ad that uses the feed to populate
dynamic data.

"""


from datetime import datetime
from uuid import uuid4

# Import appropriate classes from the client library.
from googleads import adwords
from googleads import errors


FEED_NAME = 'Interplanetary Feed Name %s' % uuid4()
ADGROUPS = [
    'INSERT_ADGROUP_ID_1_HERE',
    'INSERT_ADGROUP_ID_2_HERE'
]


def CreateAdsWithCustomizations(client, adgroup_ids, feed_name):
  """Creates ExpandedTextAds that use ad customizations for specified AdGroups.

  Args:
    client: an AdWordsClient instance.
    adgroup_ids: a list containing the AdGroup ids to add ExpandedTextAds to.
    feed_name: the name of the feed used to apply customizations.

  Raises:
    GoogleAdsError: if no ExpandedTextAds were added.
  """
  # Get the AdGroupAdService
  adgroup_ad_service = client.GetService('AdGroupAdService', 'v201809')

  expanded_text_ad = {
      'xsi_type': 'ExpandedTextAd',
      'headlinePart1': 'Luxury Cruise to {=%s.Name}' % feed_name,
      'headlinePart2': 'Only {=%s.Price}' % feed_name,
      'description': 'Offer ends in {=countdown(%s.Date)}!' % feed_name,
      'finalUrls': ['http://www.example.com'],
  }

  # We add the same ad to both ad groups. When they serve, they will show
  # different values, since they match different feed items.
  operations = [{
      'operator': 'ADD',
      'operand': {
          'adGroupId': adgroup,
          'ad': expanded_text_ad
      }
  } for adgroup in adgroup_ids]

  response = adgroup_ad_service.mutate(operations)

  if response and 'value' in response:
    for ad in response['value']:
      print ('Created an ad with ID "%s", type "%s", and status "%s".'
             % (ad['ad']['id'], ad['ad']['Ad.Type'], ad['status']))
  else:
    raise errors.GoogleAdsError('No ads were added.')


def CreateCustomizerFeed(client, feed_name):
  """Creates a new AdCustomizerFeed.

  Args:
    client: an AdWordsClient instance.
    feed_name: the name for the new AdCustomizerFeed.

  Returns:
    The new AdCustomizerFeed.
  """
  # Get the AdCustomizerFeedService
  ad_customizer_feed_service = client.GetService('AdCustomizerFeedService',
                                                 'v201809')
  customizer_feed = {
      'feedName': feed_name,
      'feedAttributes': [
          {'type': 'STRING', 'name': 'Name'},
          {'type': 'STRING', 'name': 'Price'},
          {'type': 'DATE_TIME', 'name': 'Date'}
      ]
  }

  feed_service_operation = {
      'operator': 'ADD',
      'operand': customizer_feed
  }

  response = ad_customizer_feed_service.mutate([feed_service_operation])

  if response and 'value' in response:
    feed = response['value'][0]
    feed_data = {
        'feedId': feed['feedId'],
        'nameId': feed['feedAttributes'][0]['id'],
        'priceId': feed['feedAttributes'][1]['id'],
        'dateId': feed['feedAttributes'][2]['id']
    }
    print ('Feed with name "%s" and ID %s was added with:\n'
           '\tName attribute ID %s and price attribute ID %s and date attribute'
           'ID %s') % (feed['feedName'], feed['feedId'], feed_data['nameId'],
                       feed_data['priceId'], feed_data['dateId'])
    return feed
  else:
    raise errors.GoogleAdsError('No feeds were added')


def RestrictFeedItemToAdGroup(client, feed_item, adgroup_id):
  """Restricts the feed item to an ad group.

  Args:
    client: an AdWordsClient instance.
    feed_item: The feed item.
    adgroup_id: The ad group ID.
  """
  # Get the FeedItemTargetService
  feed_item_target_service = client.GetService(
      'FeedItemTargetService', 'v201809')

  # Optional: Restrict the first feed item to only serve with ads for the
  # specified ad group ID.
  ad_group_target = {
      'xsi_type': 'FeedItemAdGroupTarget',
      'feedId': feed_item['feedId'],
      'feedItemId': feed_item['feedItemId'],
      'adGroupId': adgroup_id
  }

  operation = {'operator': 'ADD', 'operand': ad_group_target}

  response = feed_item_target_service.mutate([operation])
  new_ad_group_target = response['value'][0]

  print('Feed item target for feed ID %s and feed item ID %s was created to '
        'restrict serving to ad group ID %s' %
        (new_ad_group_target['feedId'],
         new_ad_group_target['feedItemId'],
         new_ad_group_target['adGroupId']))


def CreateCustomizerFeedItems(client, adgroup_ids, ad_customizer_feed):
  """Creates FeedItems for the specified AdGroups.

  These FeedItems contain values to use in ad customizations for the AdGroups.

  Args:
    client: an AdWordsClient instance.
    adgroup_ids: a list containing two AdGroup Ids.
    ad_customizer_feed: the AdCustomizerFeed we're associating the FeedItems
        with.

  Raises:
    GoogleAdsError: if no FeedItems were added.
  """
  # Get the FeedItemService
  feed_item_service = client.GetService('FeedItemService', 'v201809')
  now = datetime.now()
  mars_date = datetime(now.year, now.month, 1, 0, 0)
  venus_date = datetime(now.year, now.month, 15, 0, 0)
  time_format = '%Y%m%d %H%M%S'

  feed_item_operations = [
      CreateFeedItemAddOperation(
          'Mars', '$1234.56', mars_date.strftime(time_format),
          ad_customizer_feed),
      CreateFeedItemAddOperation(
          'Venus', '$1450.00', venus_date.strftime(time_format),
          ad_customizer_feed)
  ]

  response = feed_item_service.mutate(feed_item_operations)

  if 'value' in response:
    for feed_item in response['value']:
      print 'Added FeedItem with ID %d.' % feed_item['feedItemId']
  else:
    raise errors.GoogleAdsError('No FeedItems were added.')

  for feed_item, adgroup_id in zip(response['value'], adgroup_ids):
    RestrictFeedItemToAdGroup(client, feed_item, adgroup_id)


def CreateFeedItemAddOperation(name, price, date, ad_customizer_feed):
  """Creates a FeedItemOperation.

  The generated FeedItemOperation will create a FeedItem with the specified
  values when sent to FeedItemService.mutate.

  Args:
    name: the value for the name attribute of the FeedItem.
    price: the value for the price attribute of the FeedItem.
    date: the value for the date attribute of the FeedItem.
    ad_customizer_feed: the AdCustomizerFeed we're associating the FeedItems
        with.

  Returns:
    A new FeedItemOperation for adding a FeedItem.
  """
  feed_item = {
      'feedId': ad_customizer_feed['feedId'],
      'attributeValues': [
          {
              'feedAttributeId': ad_customizer_feed['feedAttributes'][0]['id'],
              'stringValue': name
          },
          {
              'feedAttributeId': ad_customizer_feed['feedAttributes'][1]['id'],
              'stringValue': price
          },
          {
              'feedAttributeId': ad_customizer_feed['feedAttributes'][2]['id'],
              'stringValue': date
          }
      ]
  }

  operation = {
      'operator': 'ADD',
      'operand': feed_item
  }

  return operation


def main(client, adgroup_ids, feed_name=FEED_NAME):
  # Create a customizer feed. One feed per account can be used for all ads.
  ad_customizer_feed = CreateCustomizerFeed(client, feed_name)
  # Add feed items containing the values we'd like to place in ads.
  CreateCustomizerFeedItems(client, adgroup_ids, ad_customizer_feed)
  # All set! We can now create ads with customizations.
  CreateAdsWithCustomizations(client, adgroup_ids, feed_name)


if __name__ == '__main__':
  # Initialize client object.
  adwords_client = adwords.AdWordsClient.LoadFromStorage()
  main(adwords_client, ADGROUPS)

Add an ad group level bid modifier

#!/usr/bin/env python
#
# Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Adds an ad group level mobile bid modifier override for a campaign.

To get your ad groups, run get_ad_groups.py.

The LoadFromStorage method is pulling credentials and properties from a
"googleads.yaml" file. By default, it looks for this file in your home
directory. For more information, see the "Caching authentication information"
section of our README.

"""

from googleads import adwords


AD_GROUP_ID = 'INSERT_AD_GROUP_ID_HERE'
BID_MODIFIER = 'INSERT_BID_MODIFIER_HERE'


def main(client, ad_group_id, bid_modifier):
  # Initialize appropriate service.
  ad_group_bid_modifier_service = client.GetService(
      'AdGroupBidModifierService', version='v201809')

  # Mobile criterion ID.
  criterion_id = '30001'

  # Prepare to add an ad group level override.
  operation = {
      # Use 'ADD' to add a new modifier and 'SET' to update an existing one. A
      # modifier can be removed with the 'REMOVE' operator.
      'operator': 'ADD',
      'operand': {
          'adGroupId': ad_group_id,
          'criterion': {
              'xsi_type': 'Platform',
              'id': criterion_id
          },
          'bidModifier': bid_modifier
      }
  }

  # Add ad group level mobile bid modifier.
  response = ad_group_bid_modifier_service.mutate([operation])
  if response and response['value']:
    modifier = response['value'][0]
    value = modifier['bidModifier'] if 'bidModifier' in modifier else 'unset'
    print ('Campaign ID %s, AdGroup ID %s, Criterion ID %s was updated with '
           'ad group level modifier: %s' %
           (modifier['campaignId'], modifier['adGroupId'],
            modifier['criterion']['id'], value))
  else:
    print 'No modifiers were added.'


if __name__ == '__main__':
  # Initialize client object.
  adwords_client = adwords.AdWordsClient.LoadFromStorage()

  main(adwords_client, AD_GROUP_ID, BID_MODIFIER)

Add a page feed specifying URLs for a DSA campaign

#!/usr/bin/env python
#
# Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Adds page feed to specify URLs to use with your Dynamic Search Ads campaign.

To create a Dynamic Search Ads campaign, run add_dynamic_search_ad_campaign.py.
To get campaigns, run get_campaigns.py.

The LoadFromStorage method is pulling credentials and properties from a
"googleads.yaml" file. By default, it looks for this file in your home
directory. For more information, see the "Caching authentication information"
section of our README.
"""

from collections import namedtuple
import uuid

from googleads import adwords


AD_GROUP_ID = 'INSERT_AD_GROUP_ID_HERE'
CAMPAIGN_ID = 'INSERT_CAMPAIGN_ID_HERE'

# Used to keep track of DSA page feed details.
_DSAFeedDetails = namedtuple(
    '_DSAFeedDetails', ['feed_id', 'url_attribute_id', 'label_attribute_id'])
# ID that corresponds to the labels.
DSA_LABEL_FIELD_ID = 2
# The criterion type to be used for DSA page feeds.
DSA_PAGE_FEED_CRITERION_TYPE = 61
DSA_PAGE_URL_LABEL = 'discounts'
# ID that corresponds to the page URLs.
DSA_PAGE_URLS_FIELD_ID = 1


def main(client, campaign_id, ad_group_id):
  # Get the page feed details. This code example creates a new feed, but you can
  # fetch and re-use an existing feed.
  feed_details = _CreateFeed(client)
  _CreateFeedMapping(client, feed_details)
  _CreateFeedItems(client, feed_details, DSA_PAGE_URL_LABEL)

  # Associate the page feed with the campaign.
  _UpdateCampaignDSASetting(client, campaign_id, feed_details.feed_id)

  # Optional: Target web pages matching the feed's label in the ad group.
  _AddDSATargeting(client, ad_group_id, DSA_PAGE_URL_LABEL)

  print 'Dynamic page feed setup complete for campaign ID "%d".' % campaign_id


def _CreateFeed(client):
  """Creates the feed for DSA page URLs.

  Args:
    client: an AdWordsClient instance.

  Returns:
    A _DSAFeedDetails instance containing details about the created feed.
  """
  # Get the FeedService.
  feed_service = client.GetService('FeedService', version='v201809')

  # Create operation.
  operation = {
      # Create the feed.
      'operand': {
          'name': 'DSA Feed %s' % uuid.uuid4(),
          # Create attributes.
          'attributes': [
              {'type': 'URL_LIST', 'name': 'Page URL'},
              {'type': 'STRING_LIST', 'name': 'Label'}
          ],
          'origin': 'USER'
      },
      'operator': 'ADD'
  }

  # Add the feed.
  feed = feed_service.mutate([operation])['value'][0]
  return _DSAFeedDetails(feed['id'], feed['attributes'][0]['id'],
                         feed['attributes'][1]['id'])


def _CreateFeedMapping(client, feed_details):
  """Creates the feed mapping for DSA page feeds.

  Args:
    client: an AdWordsClient instance.
    feed_details: a _DSAFeedDetails instance.
  """
  # Get the FeedMappingService.
  feed_mapping_service = client.GetService('FeedMappingService',
                                           version='v201809')

  # Create the operation.
  operation = {
      # Create the feed mapping.
      'operand': {
          'criterionType': DSA_PAGE_FEED_CRITERION_TYPE,
          'feedId': feed_details.feed_id,
          # Map the feedAttributeIds to the fieldId constants.
          'attributeFieldMappings': [
              {
                  'feedAttributeId': feed_details.url_attribute_id,
                  'fieldId': DSA_PAGE_URLS_FIELD_ID
              },
              {
                  'feedAttributeId': feed_details.label_attribute_id,
                  'fieldId': DSA_LABEL_FIELD_ID
              }
          ]
      },
      'operator': 'ADD'
  }

  # Add the feed mapping.
  feed_mapping_service.mutate([operation])


def _CreateFeedItems(client, feed_details, label_name):
  """Creates the page URLs in the DSA page feed.

  Args:
    client: an AdWordsClient instance.
    feed_details: a _DSAFeedDetails instance.
    label_name: a str containing the page feed URL label.
  """
  # Get the FeedItemService.
  feed_item_service = client.GetService('FeedItemService', version='v201809')

  # For page feed URL recommendations and rules, see:
  # https://support.google.com/adwords/answer/7166527
  urls = ('http://www.example.com/discounts/rental-cars?id={feeditem}',
          'http://www.example.com/discounts/hotel-deals?id={feeditem}',
          'http://www.example.com/discounts/flight-deals?id={feeditem}')

  # Create the operation.
  operations = [{
      # Create the feed item.
      'operand': {
          'feedId': feed_details.feed_id,
          'attributeValues': [
              {
                  'feedAttributeId': feed_details.url_attribute_id,
                  'stringValues': [url]
              },
              {
                  'feedAttributeId': feed_details.label_attribute_id,
                  'stringValues': [label_name]
              }
          ]
      },
      'operator': 'ADD'
  } for url in urls]

  # Add the feed item.
  feed_item_service.mutate(operations)


def _UpdateCampaignDSASetting(client, campaign_id, feed_id):
  """Updates the campaign DSA setting to DSA pagefeeds.

  Args:
    client: an AdWordsClient instance.
    campaign_id: a str Campaign ID.
    feed_id: a str page Feed ID.

  Raises:
    ValueError: If the given campaign is found not to be a dynamic search ad
    campaign.
  """
  # Get the CampaignService.
  campaign_service = client.GetService('CampaignService', version='v201809')

  selector = {
      'fields': ['Id', 'Settings'],
      'predicates': [{
          'field': 'Id',
          'operator': 'EQUALS',
          'values': [campaign_id]
      }]
  }

  response = campaign_service.get(selector)

  if response['totalNumEntries']:
    campaign = response['entries'][0]
  else:
    raise ValueError('No campaign with ID "%d" exists.' % campaign_id)

  if not campaign['settings']:
    raise ValueError('This is not a DSA campaign.')

  dsa_setting = None

  campaign_settings = campaign['settings']

  for setting in campaign_settings:
    if setting['Setting.Type'] == 'DynamicSearchAdsSetting':
      dsa_setting = setting
      break

  if dsa_setting is None:
    raise ValueError('This is not a DSA campaign.')

  dsa_setting['pageFeed'] = {
      'feedIds': [feed_id]
  }

  # Optional: Specify whether only the supplied URLs should be used with your
  # Dynamic Search Ads.
  dsa_setting['useSuppliedUrlsOnly'] = True

  operation = {
      'operand': {
          'id': campaign_id,
          'settings': campaign_settings
      },
      'operator': 'SET'
  }

  campaign_service.mutate([operation])
  print 'DSA page feed for campaign ID "%d" was updated with feed ID "%d".' % (
      campaign_id, feed_id)


def _AddDSATargeting(client, ad_group_id, label_name):
  """Set custom targeting for the page feed URLs based on a list of labels.

  Args:
    client: an AdWordsClient instance.
    ad_group_id: a str AdGroup ID.
    label_name: a str label name.

  Returns:
    A suds.sudsobject.Object representing the newly created webpage criterion.
  """
  # Get the AdGroupCriterionService.
  ad_group_criterion_service = client.GetService('AdGroupCriterionService',
                                                 version='v201809')

  # Create the operation.
  operation = {
      'operand': {
          'xsi_type': 'BiddableAdGroupCriterion',
          'adGroupId': ad_group_id,
          # Create a webpage criterion.
          'criterion': {
              'xsi_type': 'Webpage',
              'parameter': {
                  'criterionName': 'Test criterion',
                  # Add a condition for label=specified_label_name.
                  'conditions': [{
                      'operand': 'CUSTOM_LABEL',
                      'argument': label_name
                  }],
              }
          },
          # Set a custom bid for this criterion
          'biddingStrategyConfiguration': {
              'bids': [{
                  'xsi_type': 'CpcBid',
                  'bid': {
                      'microAmount': 1500000
                  }
              }]
          }
      },
      'operator': 'ADD'
  }

  criterion = ad_group_criterion_service.mutate([operation])['value'][0]
  print 'Web page criterion with ID "%d" and status "%s" was created.' % (
      criterion['criterion']['id'], criterion['userStatus'])
  return criterion


if __name__ == '__main__':
  # Initialize client object.
  adwords_client = adwords.AdWordsClient.LoadFromStorage()
  main(adwords_client, CAMPAIGN_ID, AD_GROUP_ID)

Add a DSA campaign

#!/usr/bin/env python
#
# Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""This example adds a Dynamic Search Ads campaign.

To get campaigns, run get_campaigns.py.

The LoadFromStorage method is pulling credentials and properties from a
"googleads.yaml" file. By default, it looks for this file in your home
directory. For more information, see the "Caching authentication information"
section of our README.
"""


import datetime
import uuid
from googleads import adwords


def main(client):
  budget = _CreateBudget(client)
  campaign_id = _CreateCampaign(client, budget)
  ad_group_id = _CreateAdGroup(client, campaign_id)
  _CreateExpandedDSA(client, ad_group_id)
  _AddWebPageCriteria(client, ad_group_id)

  print 'Dynamic Search Ads campaign setup is complete.'


def _CreateBudget(client):
  """Creates the budget.

  Args:
    client: an AdWordsClient instance.

  Returns:
    a suds.sudsobject.Object representation of the created budget.
  """
  budget_service = client.GetService('BudgetService', version='v201809')

  # Create the campaign budget
  operation = {
      'operand': {
          'name': 'Interplanetary Cruise Budget #%d' % uuid.uuid4(),
          'deliveryMethod': 'STANDARD',
          'amount': {
              'microAmount': 500000
          }
      },
      'operator': 'ADD'
  }

  budget = budget_service.mutate([operation])['value'][0]

  print 'Budget with ID "%d" and name "%s" was created.' % (
      budget['budgetId'], budget['name'])

  return budget


def _CreateCampaign(client, budget):
  """Creates the campaign.

  Args:
    client: an AdWordsClient instance.
    budget: a suds.sudsobject.Object representation of a created budget.

  Returns:
    An integer campaign ID.
  """
  campaign_service = client.GetService('CampaignService')

  operations = [{
      'operator': 'ADD',
      'operand': {
          'name': 'Interplanetary Cruise #%d' % uuid.uuid4(),
          # 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': 'PAUSED',
          'advertisingChannelType': 'SEARCH',
          'biddingStrategyConfiguration': {
              'biddingStrategyType': 'MANUAL_CPC',
          },
          'budget': budget,
          # Required: Set the campaign's Dynamic Search Ad settings.
          'settings': [{
              'xsi_type': 'DynamicSearchAdsSetting',
              # Required: Set the domain name and language.
              'domainName': 'example.com',
              'languageCode': 'en'
          }],
          # Optional: Set the start date.
          'startDate': (datetime.datetime.now() +
                        datetime.timedelta(1)).strftime('%Y%m%d'),
          # Optional: Set the end date.
          'endDate': (datetime.datetime.now() +
                      datetime.timedelta(365)).strftime('%Y%m%d'),
      }
  }]

  campaign = campaign_service.mutate(operations)['value'][0]
  campaign_id = campaign['id']

  print 'Campaign with ID "%d" and name "%s" was added.' % (
      campaign_id, campaign['name'])

  return campaign_id


def _CreateAdGroup(client, campaign_id):
  """Creates an ad group.

  Args:
    client: an AdWordsClient instance.
    campaign_id: an integer campaign ID.

  Returns:
    An integer ad group ID.
  """
  ad_group_service = client.GetService('AdGroupService')

  operations = [{
      'operator': 'ADD',
      'operand': {
          'campaignId': campaign_id,
          'adGroupType': 'SEARCH_DYNAMIC_ADS',
          'name': 'Earth to Mars Cruises #%d' % uuid.uuid4(),
          'status': 'PAUSED',
          'biddingStrategyConfiguration': {
              'bids': [{
                  'xsi_type': 'CpcBid',
                  'bid': {
                      'microAmount': '3000000'
                  },
              }]
          }
      }
  }]

  ad_group = ad_group_service.mutate(operations)['value'][0]
  ad_group_id = ad_group['id']

  print 'Ad group with ID "%d" and name "%s" was created.' % (
      ad_group_id, ad_group['name'])

  return ad_group_id


def _CreateExpandedDSA(client, ad_group_id):
  """Creates the expanded Dynamic Search Ad.

  Args:
    client: an AdwordsClient instance.
    ad_group_id: an integer ID of the ad group in which the DSA is added.
  """
  # Get the AdGroupAdService.
  ad_group_ad_service = client.GetService('AdGroupAdService')

  # Create the operation
  operations = [{
      'operator': 'ADD',
      'operand': {
          'xsi_type': 'AdGroupAd',
          'adGroupId': ad_group_id,
          # Create the expanded dynamic search ad. This ad will have its
          # headline and final URL auto-generated at serving time according to
          # domain name specific information provided by DynamicSearchAdsSetting
          # at the campaign level.
          'ad': {
              'xsi_type': 'ExpandedDynamicSearchAd',
              # Set the ad description.
              'description': 'Buy your tickets now!',
              'description2': 'Discount ends soon'
          },
          # Optional: Set the status.
          'status': 'PAUSED',
      }
  }]

  # Create the ad.
  ad = ad_group_ad_service.mutate(operations)['value'][0]['ad']

  # Display the results.
  print ('Expanded dynamic search ad with ID "%d", description "%s", and '
         'description 2 "%s" was added'
         % (ad['id'], ad['description'], ad['description2']))


def _AddWebPageCriteria(client, ad_group_id):
  """Adds a web page criterion to target Dynamic Search Ads.

  Args:
    client: an AdWordsClient instance.
    ad_group_id: an integer ID of the ad group the criteria is being added to.
  """
  ad_group_criterion_service = client.GetService('AdGroupCriterionService',
                                                 version='v201809')

  operations = [{
      'operator': 'ADD',
      # Create biddable ad group criterion.
      'operand': {
          'xsi_type': 'BiddableAdGroupCriterion',
          'adGroupId': ad_group_id,
          # Create a webpage criterion for special offers for children.
          'criterion': {
              'xsi_type': 'Webpage',
              'parameter': {
                  'criterionName': 'Special offers for children.',
                  'conditions': [
                      {
                          'operand': 'URL',
                          'argument': '/marscruise/children'
                      },
                      {
                          'operand': 'PAGE_TITLE',
                          'argument': 'Special Offer'
                      }
                  ]
              }
          },
          'userStatus': 'PAUSED',
          # Optional: set a custom bid.
          'biddingStrategyConfiguration': {
              'bids': [{
                  'xsi_type': 'CpcBid',
                  'bid': {
                      'microAmount': 10000000L
                  }
              }]
          }
      }
  }]

  criterion = ad_group_criterion_service.mutate(operations)['value'][0]

  print 'Webpage criterion with ID "%d" was added to ad group ID "%d".' % (
      criterion['criterion']['id'], criterion['adGroupId'])


if __name__ == '__main__':
  # Initialize client object.
  adwords_client = adwords.AdWordsClient.LoadFromStorage()

  main(adwords_client)

Add an expanded text ad with Upgraded URLs

#!/usr/bin/env python
#
# Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""This example adds an expanded text ad that uses upgraded URLS.

The LoadFromStorage method is pulling credentials and properties from a
"googleads.yaml" file. By default, it looks for this file in your home
directory. For more information, see the "Caching authentication information"
section of our README.

"""

from googleads import adwords
from googleads import errors


ADGROUP_ID = 'INSERT_ADGROUP_ID_HERE'


def main(client, adgroup_id):
  # Initialize appropriate service.
  adgroup_ad_service = client.GetService('AdGroupAdService', version='v201809')

  # Create the expanded text ad
  expanded_text_ad = {
      'xsi_type': 'ExpandedTextAd',
      'headlinePart1': 'Luxury Cruise to Mars',
      'headlinePart2': 'Visit the Red Planet in style.',
      'description': 'Low-gravity fun for everyone!',
      # Specify a list of final URLs. This field cannot be set if URL
      # field is set, or finalUrls is unset. This may be specified at ad,
      # criterion, and feed item levels.
      'finalUrls': [
          'http://www.example.com/cruise/space/',
          'http://www.example.com/locations/mars/'
      ],
      # Specify a list of final mobile URLs. This field cannot be set if URL
      # field is set, or finalUrls is unset. This may be specified at ad,
      # criterion, and feed item levels.
      'finalMobileUrls': [
          'http://mobile.example.com/cruise/space/',
          'http://mobile.example.com/locations/mars/'
      ]
  }

  # Specify a tracking URL for 3rd party tracking provider. You may specify
  # one at customer, campaign, ad group, ad, criterion or feed item levels.
  expanded_text_ad['trackingUrlTemplate'] = (
      'http://tracker.example.com/?season={_season}&promocode={_promocode}'
      '&u={lpurl}'
  )

  expanded_text_ad['urlCustomParameters'] = {
      'parameters': [
          # Since your tracking URL has two custom parameters, provide
          # their values too. This can be provided at campaign, ad group,
          # ad, criterion, or feed item levels.
          {
              'key': 'season',
              'value': 'christmas'
          },
          {
              'key': 'promocode',
              'value': 'NYC123'
          }
      ]
  }

  text_adgroup_ad = {
      'adGroupId': adgroup_id,
      'ad': expanded_text_ad,
      # Optional: Set the status.
      'status': 'PAUSED'
  }

  operations = [{
      'operator': 'ADD',
      'operand': text_adgroup_ad
  }]

  response = adgroup_ad_service.mutate(operations)

  if 'value' in response:
    for adgroup_ad in response['value']:
      print 'AdGroupAd with ID "%s" was added.' % adgroup_ad['ad']['id']
      print 'Upgraded URL properties:'
      print 'Final Urls: %s' % adgroup_ad['ad']['finalUrls']
      print 'Final Mobile URLs: %s' % adgroup_ad['ad']['finalMobileUrls']
      print ('Tracking URL template: %s'
             % adgroup_ad['ad']['trackingUrlTemplate'])
      print 'Custom parameters: %s' % adgroup_ad['ad']['urlCustomParameters']
  else:
    raise errors.GoogleAdsError('Failed to create AdGroupAd.')


if __name__ == '__main__':
  # Initialize client object.
  adwords_client = adwords.AdWordsClient.LoadFromStorage()

  main(adwords_client, ADGROUP_ID)

Add a Gmail ad to an ad group

#!/usr/bin/env python
#
# Copyright 2018 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""This code example adds a Gmail ad to a given ad group.

The ad group's campaign needs to have an AdvertisingChannelType of DISPLAY and
AdvertisingChannelSubType of DISPLAY_GMAIL_AD.

To get your ad groups, run get_ad_groups.py.
"""


# Import appropriate classes from the client library.
from googleads import adwords


ADGROUP_ID = 'INSERT_AD_GROUP_ID_HERE'


def main(client, ad_group_id):
  media_service = client.GetService('MediaService', 'v201809')
  ad_group_ad_service = client.GetService('AdGroupAdService', 'v201809')
  opener = client.proxy_config.BuildOpener()

  try:
    # This ad format doesn't allow the creation of an image using the Image.data
    # field. An image must first be created using the MediaService, and an
    # Image.mediaId must be populated when creating the ad.
    uploaded_logo_image = _CreateImage(
        media_service, opener, 'https://goo.gl/mtt54n')
    uploaded_marketing_image = _CreateImage(
        media_service, opener, 'http://goo.gl/3b9Wfh')

    teaser = {
        'headline': 'Dream',
        'description': 'Create your own adventure',
        'businessName': 'Interplanetary Ships',
        'logoImage': uploaded_logo_image
    }

    # Creates a Gmail ad.
    gmail_ad = {
        'xsi_type': 'GmailAd',
        'teaser': teaser,
        'marketingImage': uploaded_marketing_image,
        'marketingImageHeadline': 'Travel',
        'marketingImageDescription': 'Take to the skies!',
        'finalUrls': ['http://wwww.example.com']
    }

    # Creates ad group ad for the Gmail ad.
    ad_group_ad = {
        'adGroupId': ad_group_id,
        'ad': gmail_ad,
        # Optional: Set additional settings.
        'status': 'PAUSED'
    }

    # Creates ad group ad operations.
    operations = [{
        'operator': 'ADD',
        'operand': ad_group_ad
    }]

    # Adds a Gmail ad.
    ad_group_ads = ad_group_ad_service.mutate(operations)

    # Display results.
    for ad_group_ad in ad_group_ads['value']:
      print ('A Gmail ad with id "%d" and short headline "%s" was '
             'added.' % (ad_group_ad['ad']['id'],
                         ad_group_ad['ad']['teaser']['headline']))
  except Exception as e:
    raise Exception('Failed to create Gmail ad: %s' % e)


def _CreateImage(media_service, opener, url):
  """Creates an image and uploads it to the server.

  Args:
    media_service: a SudsServiceProxy instance for AdWords's MediaService.
    opener: an OpenerDirector instance.
    url: a str URL used to load image data.

  Returns:
    The image that was successfully uploaded.
  """
  # Note: The utf-8 decode is for 2to3 Python 3 compatibility.
  image_data = opener.open(url).read().decode('utf-8')
  image = {
      'type': 'IMAGE',
      'data': image_data,
      'xsi_type': 'Image'
  }

  return media_service.upload(image)[0]


if __name__ == '__main__':
  # Initialize client object.
  adwords_client = adwords.AdWordsClient.LoadFromStorage()
  main(adwords_client, ADGROUP_ID)

Add an HTML 5 ad to an ad group

#!/usr/bin/env python
#
# Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""This example adds an HTML5 ad to a given AdGroup.

To get ad_group_id, run get_ad_groups.py.

The LoadFromStorage method is pulling credentials and properties from a
"googleads.yaml" file. By default, it looks for this file in your home
directory. For more information, see the "Caching authentication information"
section of our README.

"""


import urllib2
from googleads import adwords


AD_GROUP_ID = 'INSERT_AD_GROUP_ID_HERE'


def main(client, ad_group_id):
  # Initialize appropriate service.
  ad_group_ad_service = client.GetService('AdGroupAdService', version='v201809')

  # Create HTML5 media.
  html5_zip = GetHTML5ZipFromUrl('https://goo.gl/9Y7qI2')
  # Create a media bundle containing the zip file with all the HTML5 components.
  media_bundle = {
      'xsi_type': 'MediaBundle',
      'data': html5_zip,
      'entryPoint': 'carousel/index.html',
      'type': 'MEDIA_BUNDLE'
  }

  ad_data = {
      'uniqueName': 'adData',
      'fields': [
          {
              'name': 'Custom_layout',
              'fieldMedia': media_bundle,
              'type': 'MEDIA_BUNDLE'
          },
          {
              'name': 'layout',
              'fieldText': 'Custom',
              'type': 'ENUM'
          }
      ]
  }

  html5_ad = {
      'xsi_type': 'TemplateAd',
      'name': 'Ad for HTML5',
      'templateId': 419,
      'finalUrls': ['https://www.google.com'],
      'displayUrl': 'www.google.com?tip=ENTER_YOUR_OWN_FINAL_AND_DISPLAY_URLS',
      'dimensions': {
          'width': '300',
          'height': '250'
      },
      'templateElements': [ad_data]
  }

  ad_group_ad = {
      'adGroupId': ad_group_id,
      'ad': html5_ad,
      'status': 'PAUSED'
  }

  operations = [
      {
          'operator': 'ADD',
          'operand': ad_group_ad
      }
  ]
  ads = ad_group_ad_service.mutate(operations)

  # Display results.
  for ad in ads['value']:
    print ('New HTML5 Ad with id "%s" and of display url "%s" was added.'
           % (ad['ad']['id'], ad['ad']['displayUrl']))


def GetHTML5ZipFromUrl(url):
  """Retrieve zip file from the given URL."""
  response = urllib2.urlopen(url)
  # Note: The utf-8 decode is for 2to3 Python 3 compatibility.
  return response.read().decode('utf-8')


if __name__ == '__main__':
  # Initialize client object.
  adwords_client = adwords.AdWordsClient.LoadFromStorage()

  main(adwords_client, AD_GROUP_ID)

Add a multi-asset responsive display ad to an ad group

#!/usr/bin/env python
#
# Copyright 2018 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""This example adds a responsive display ad to an ad group.

Image assets are uploaded using AssetService. To get ad groups, run
get_ad_groups.py.

The LoadFromStorage method is pulling credentials and properties from a
"googleads.yaml" file. By default, it looks for this file in your home
directory. For more information, see the "Caching authentication information"
section of our README.

"""


from googleads import adwords
import requests


AD_GROUP_ID = 'INSERT_AD_GROUP_ID_HERE'


def UploadImageAsset(client, url):
  """Uploads the image from the specified url.

  Args:
    client: An AdWordsClient instance.
    url: The image URL.

  Returns:
    The ID of the uploaded image.
  """
  # Initialize appropriate service.
  asset_service = client.GetService('AssetService', version='v201809')

  # Download the image.
  image_request = requests.get(url)

  # Create the image asset.
  image_asset = {
      'xsi_type': 'ImageAsset',
      'imageData': image_request.content,
      # This field is optional, and if provided should be unique.
      # 'assetName': 'Image asset ' + str(uuid.uuid4()),
  }

  # Create the operation.
  operation = {
      'operator': 'ADD',
      'operand': image_asset
  }

  # Create the asset and return the ID.
  result = asset_service.mutate([operation])

  return result['value'][0]['assetId']


def main(client, ad_group_id):
  # Initialize appropriate service.
  ad_group_ad_service = client.GetService('AdGroupAdService', version='v201809')

  # Create the ad.
  multi_asset_responsive_display_ad = {
      'xsi_type': 'MultiAssetResponsiveDisplayAd',
      'headlines': [{
          'asset': {
              'xsi_type': 'TextAsset',
              'assetText': 'Travel to Mars'
          }
      }, {
          'asset': {
              'xsi_type': 'TextAsset',
              'assetText': 'Travel to Jupiter',
          }
      }, {
          'asset': {
              'xsi_type': 'TextAsset',
              'assetText': 'Travel to Pluto'
          }
      }],
      'descriptions': [{
          'asset': {
              'xsi_type': 'TextAsset',
              'assetText': 'Visit the planet in a luxury spaceship.',
          }
      }, {
          'asset': {
              'xsi_type': 'TextAsset',
              'assetText': 'See the planet in style.',
          }
      }],
      'businessName': 'Galactic Luxury Cruises',
      'longHeadline': {
          'asset': {
              'xsi_type': 'TextAsset',
              'assetText': 'Visit the planet in a luxury spaceship.',
          }
      },
      # This ad format does not allow the creation of an image asset by setting
      # the asset.imageData field. An image asset must first be created using
      # the AssetService, and asset.assetId must be populated when creating
      # the ad.
      'marketingImages': [{
          'asset': {
              'xsi_type': 'ImageAsset',
              'assetId': UploadImageAsset(client, 'https://goo.gl/3b9Wfh')
          }
      }],
      'squareMarketingImages': [{
          'asset': {
              'xsi_type': 'ImageAsset',
              'assetId': UploadImageAsset(client, 'https://goo.gl/mtt54n')
          }
      }],
      # Optional values
      'finalUrls': ['http://www.example.com'],
      'callToActionText': 'Shop Now',
      # Set color settings using hexadecimal values. Set allowFlexibleColor to
      # false if you want your ads to render by always using your colors
      # strictly.
      'mainColor': '#0000ff',
      'accentColor': '#ffff00',
      'allowFlexibleColor': False,
      'formatSetting': 'NON_NATIVE',
      # Set dynamic display ad settings, composed of landscape logo image,
      # promotion text, and price prefix.
      'dynamicSettingsPricePrefix': 'as low as',
      'dynamicSettingsPromoText': 'Free shipping!',
      'logoImages': [{
          'asset': {
              'xsi_type': 'ImageAsset',
              'assetId': UploadImageAsset(client, 'https://goo.gl/mtt54n')
          }
      }]
  }

  # Create ad group ad.
  ad_group_ad = {
      'adGroupId': ad_group_id,
      'ad': multi_asset_responsive_display_ad,
      # Optional.
      'status': 'PAUSED'
  }

  # Add ad.
  ads = ad_group_ad_service.mutate([
      {'operator': 'ADD', 'operand': ad_group_ad}
  ])
  # Display results.
  if 'value' in ads:
    for ad in ads['value']:
      print ('Added new responsive display ad ad with ID "%d" '
             'and long headline "%s".'
             % (ad['ad']['id'], ad['ad']['longHeadline']['asset']['assetText']))
  else:
    print 'No ads were added.'


if __name__ == '__main__':
  # Initialize client object.
  adwords_client = adwords.AdWordsClient.LoadFromStorage()
  main(adwords_client, AD_GROUP_ID)

Add a responsive display ad

#!/usr/bin/env python
#
# Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""This example adds a responsive display ad to a given ad group.

To get ad_group_id, run get_ad_groups.py.

The LoadFromStorage method is pulling credentials and properties from a
"googleads.yaml" file. By default, it looks for this file in your home
directory. For more information, see the "Caching authentication information"
section of our README.

"""

import urllib2

from googleads import adwords


AD_GROUP_ID = 'INSERT_AD_GROUP_ID_HERE'


def main(client, ad_group_id):
  # Initialize appropriate services.
  ad_group_ad_service = client.GetService('AdGroupAdService', version='v201809')
  media_service = client.GetService('MediaService', version='v201809')
  opener = urllib2.build_opener(*client.proxy_config.GetHandlers())

  try:
    # Create marketing image.
    marketing_image = _CreateImage(media_service, opener,
                                   'https://goo.gl/3b9Wfh')

    # Create square marketing image.
    square_marketing_image = _CreateImage(media_service, opener,
                                          'https://goo.gl/mtt54n')

    # Create a responsive display ad.
    operations = [{
        'operator': 'ADD',
        'operand': {
            'xsi_type': 'AdGroupAd',
            'adGroupId': ad_group_id,
            'ad': {
                'xsi_type': 'ResponsiveDisplayAd',
                'marketingImage': {'mediaId': marketing_image['mediaId']},
                'shortHeadline': 'Travel',
                'longHeadline': 'Travel the World',
                'description': 'Take to the air!',
                'businessName': 'Interplanetary Cruises',
                'finalUrls': ['http://www.example.com'],
                # Optional: Set a square marketing image to the ad.
                'squareMarketingImage': {
                    'mediaId': square_marketing_image['mediaId']
                },
                # Optional: Set call-to-action text.
                'callToActionText': 'Shop Now',
                # Optional: Set dynamic display ad settings, composed of
                # landscape logo image, promotion text, and price prefix.
                'dynamicDisplayAdSettings': _CreateDynamicDisplayAdSettings(
                    media_service, opener),
                # Whitelisted accounts only: Set color settings using
                # hexadecimal numbers.
                # Set allowFlexibleColor to False if you want your ads to render
                # by always using your colors strictly.
                # 'mainColor': '#0000ff',
                # 'accentColor': '#ffff00',
                # 'allowFlexibleColor': False
                # Whitelisted accounts only: Set the format setting that the ad
                # will be served in.
                # 'formatSetting': 'NON_NATIVE'

            },
            # Optional fields.
            'status': 'PAUSED'
        }
    }]

    # Make the mutate request.
    ads = ad_group_ad_service.mutate(operations)

    # Display results.
    for ad in ads['value']:
      print ('ResponsiveDisplayAd with id "%d" and short headline "%s" was '
             'added.' % (ad['ad']['id'], ad['ad']['shortHeadline']))

  except:
    raise Exception('Failed to create responsive display ad.')


def _CreateImage(media_service, opener, url):
  """Creates an image and uploads it to the server.

  Args:
    media_service: a SudsServiceProxy instance for AdWords's MediaService.
    opener: an OpenerDirector instance.
    url: a str URL used to load image data.

  Returns:
    The image that was successfully uploaded.
  """
  # Note: The utf-8 decode is for 2to3 Python 3 compatibility.
  image_data = opener.open(url).read().decode('utf-8')
  image = {
      'type': 'IMAGE',
      'data': image_data,
      'xsi_type': 'Image'
  }

  return media_service.upload(image)[0]


def _CreateDynamicDisplayAdSettings(media_service, opener):
  """Creates settings for dynamic display ad.

  Args:
    media_service: a SudsServiceProxy instance for AdWords's MediaService.
    opener: an OpenerDirector instance.

  Returns:
    The dynamic display ad settings.
  """
  image = _CreateImage(media_service, opener, 'https://goo.gl/dEvQeF')

  logo = {
      'type': 'IMAGE',
      'mediaId': image['mediaId'],
      'xsi_type': 'Image'
  }

  dynamic_settings = {
      'landscapeLogoImage': logo,
      'pricePrefix': 'as low as',
      'promoText': 'Free shipping!',
      'xsi_type': 'DynamicSettings',
  }

  return dynamic_settings


if __name__ == '__main__':
  # Initialize client object.
  adwords_client = adwords.AdWordsClient.LoadFromStorage()

  main(adwords_client, AD_GROUP_ID)

Add a Shopping dynamic remarketing campaign

#!/usr/bin/env python
#
# Copyright 2018 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Adds a Shopping dynamic remarketing campaign for the Display Network.

This example steps through the following:
* Creates a new Display Network campaign.
* Links the campaign with Merchant Center.
* Links the user list to the ad group.
* Creates a responsive display ad to render the dynamic text.

The LoadFromStorage method is pulling credentials and properties from a
"googleads.yaml" file. By default, it looks for this file in your home
directory. For more information, see the "Caching authentication information"
section of our README.
"""


import uuid

from googleads import adwords


MERCHANT_ID = 'INSERT_MERCHANT_CENTER_ID_HERE'
BUDGET_ID = 'INSERT_BUDGET_ID_HERE'
USER_LIST_ID = 'INSERT_USER_LIST_ID_HERE'


def main(client, merchant_id, budget_id, user_list_id):
  opener = client.proxy_config.BuildOpener()

  campaign = CreateCampaign(client, merchant_id, budget_id)
  campaign_id = campaign['id']
  print 'Campaign with name "%s" and ID "%d" was added.' % (
      campaign['name'], campaign_id)

  ad_group = CreateAdGroup(client, campaign_id)
  ad_group_id = ad_group['id']
  print 'Ad group with name "%s" and ID "%d" was added.' % (
      ad_group['name'], ad_group_id)

  ad_group_ad = CreateAd(client, opener, ad_group_id)
  print 'Responsive display ad with ID "%d" was added.' % (
      ad_group_ad['ad']['id'])

  AttachUserList(client, ad_group_id, user_list_id)
  print 'User list with ID "%d" was attached to ad group with ID "%d".' % (
      user_list_id, ad_group_id)


def CreateCampaign(client, merchant_id, budget_id):
  """Creates a new Display Network campaign.

  Args:
    client: an AdWordsClient instance.
    merchant_id: a int merchant center ID.
    budget_id: a int budget ID.

  Returns:
    The campaign that was successfully created.
  """
  campaign_service = client.GetService('CampaignService', 'v201809')

  campaign = {
      'name': 'Shopping campaign #%d' % uuid.uuid4(),
      # Dynamic remarketing campaigns are only available on the Google Display
      # Network.
      'advertisingChannelType': 'DISPLAY',
      'status': 'PAUSED',
      'budget': {
          'budgetId': budget_id
      },
      # This example uses a Manual CPC bidding strategy, but you should select
      # the strategy that best aligns with your sales goals. More details here:
      # https://support.google.com/adwords/answer/2472725
      'biddingStrategyConfiguration': {
          'biddingStrategyType': 'MANUAL_CPC'
      },
      'settings': [{
          'xsi_type': 'ShoppingSetting',
          # Campaigns with numerically higher priorities take precedence over
          # those with lower priorities.
          'campaignPriority': 0,
          'merchantId': merchant_id,
          # Display network campaigns do not support partition by country. The
          # only supported value is "ZZ". This signals that products from all
          # countries are available in this campaign. The actual products which
          # serve are based on the products tagged in the user list entry.
          'salesCountry': 'ZZ',
          # Optional: Enable local inventory ads (items for sale in physical
          # stores.)
          'enableLocal': True,
      }]
  }

  operations = [{
      'operator': 'ADD',
      'operand': campaign
  }]

  return campaign_service.mutate(operations)['value'][0]


def CreateAdGroup(client, campaign_id):
  """Creates a dynamic remarketing campaign.

  Args:
    client: an AdWordsClient instance.
    campaign_id: an int campaign ID.

  Returns:
    The ad group that was successfully created.
  """
  ad_group_service = client.GetService('AdGroupService', 'v201809')

  ad_group = {
      'name': 'Dynamic remarketing ad group',
      'campaignId': campaign_id,
      'status': 'ENABLED'
  }

  operations = [{
      'operator': 'ADD',
      'operand': ad_group
  }]

  return ad_group_service.mutate(operations)['value'][0]


def CreateAd(client, opener, ad_group_id):
  """Creates a ResponsiveDisplayAd.

  Args:
    client: an AdWordsClient instance.
    opener: an OpenerDirector instance.
    ad_group_id: an int ad group ID.

  Returns:
    The ad group ad that was successfully created.
  """
  ad_group_ad_service = client.GetService('AdGroupAdService', 'v201809')
  media_service = client.GetService('MediaService', 'v201809')

  marketing_image_id = _CreateImage(
      media_service, opener, 'https://goo.gl/3b9Wfh')
  logo_image_id = _CreateImage(media_service, opener, 'https://goo.gl/mtt54n')

  ad = {
      'xsi_type': 'ResponsiveDisplayAd',
      # This ad format doesn't allow the creation of an image using the
      # Image.data field. An image must first be created using the MediaService,
      # and Image.mediaId must be populated when creating the ad.
      'marketingImage': {
          'xsi_type': 'Image',
          'mediaId': marketing_image_id
      },
      'shortHeadline': 'Travel',
      'longHeadline': 'Travel the World',
      'description': 'Take to the air!',
      'businessName': 'Interplanetary Cruises',
      'finalUrls': ['http://wwww.example.com'],
      # Optional: Call to action text.
      # Valid texts: https://support.google.com/adwords/answer/7005917
      'callToActionText': 'Apply Now',
      # Optional: Set dynamic display ad settings, composed of landscape logo
      # image, promotion text, and price prefix.
      'dynamicDisplayAdSettings': CreateDynamicDisplayAdSettings(
          client, opener),
      # Optional: Create a logo image and set it to the ad.
      'logoImage': {
          'xsi_type': 'Image',
          'mediaId': logo_image_id
      },
      # Optional: Create a square marketing image and set it to the ad.
      'squareMarketingImage': {
          'xsi_type': 'Image',
          'mediaId': logo_image_id
      },
      # Whitelisted accounts only: Set color settings using hexadecimal values.
      # Set allowFlexibleColor to False if you want your ads to render by always
      # using your colors strictly.
      # 'mainColor': '#000fff',
      # 'accentColor': '#fff000',
      # 'allowFlexibleColor': False,
      # Whitelisted accounts only: Set the format setting that the ad will be
      # served in.
      # 'formatSetting': 'NON_NATIVE'
  }

  ad_group_ad = {
      'ad': ad,
      'adGroupId': ad_group_id
  }

  operations = [{
      'operation': 'ADD',
      'operand': ad_group_ad
  }]

  return ad_group_ad_service.mutate(operations)['value'][0]


def AttachUserList(client, ad_group_id, user_list_id):
  """Links the provided ad group and user list.

  Args:
    client: an AdWordsClient instance.
    ad_group_id: an int ad group ID.
    user_list_id: an int user list ID.

  Returns:
    The ad group criterion that was successfully created.
  """
  ad_group_criterion_service = client.GetService(
      'AdGroupCriterionService', 'v201809')

  user_list = {
      'xsi_type': 'CriterionUserList',
      'userListId': user_list_id
  }

  ad_group_criterion = {
      'xsi_type': 'BiddableAdGroupCriterion',
      'criterion': user_list,
      'adGroupId': ad_group_id
  }

  operations = [{
      'operator': 'ADD',
      'operand': ad_group_criterion
  }]

  return ad_group_criterion_service.mutate(operations)['value'][0]


def CreateDynamicDisplayAdSettings(client, opener):
  """Creates dynamic display ad settings.

  Args:
    client: an AdWordsClient instance.
    opener: an OpenerDirector instance.

  Returns:
    A dict containing the dynamic display ad settings.
  """
  media_service = client.GetService('MediaService', 'v201809')

  logo = {
      'xsi_type': 'Image',
      'mediaId': _CreateImage(media_service, opener, 'https://goo.gl/dEvQeF')
  }

  dynamic_settings = {
      'landscapeLogoImage': logo,
      'pricePrefix': 'as low as',
      'promoText': 'Free shipping!'
  }

  return dynamic_settings


def _CreateImage(media_service, opener, url):
  """Creates an image and uploads it to the server.

  Args:
    media_service: a SudsServiceProxy instance for AdWords's MediaService.
    opener: an OpenerDirector instance.
    url: a str URL used to load image data.

  Returns:
    The image that was successfully uploaded.
  """
  # Note: The utf-8 decode is for 2to3 Python 3 compatibility.
  image_data = opener.open(url).read().decode('utf-8')
  image = {
      'type': 'IMAGE',
      'data': image_data,
      'xsi_type': 'Image'
  }

  return media_service.upload(image)[0]


if __name__ == '__main__':
  # Initialize client object.
  adwords_client = adwords.AdWordsClient.LoadFromStorage()

  main(adwords_client, MERCHANT_ID, BUDGET_ID, USER_LIST_ID)

Add a universal app campaign

#!/usr/bin/env python
#
# Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""This example adds a Universal App campaign.

To get campaigns, run get_campaigns.py. To upload image assets for this
campaign, run upload_image.py.

The LoadFromStorage method is pulling credentials and properties from a
"googleads.yaml" file. By default, it looks for this file in your home
directory. For more information, see the "Caching authentication information"
section of our README.

"""


import datetime
import uuid
from googleads import adwords


def main(client):
  # Initialize appropriate services.
  campaign_service = client.GetService('CampaignService', version='v201809')

  budget_id = CreateBudget(client)

  # Create the Universal App campaign.
  universal_app_campaign = {
      'name': 'Interplanetary Cruise App #%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': 'MULTI_CHANNEL',
      'advertisingChannelSubType': 'UNIVERSAL_APP_CAMPAIGN',
      # Set the campaign's bidding strategy. Universal app campaigns only
      # support TARGET_CPA bidding strategy.
      'biddingStrategyConfiguration': {
          # Set the target CPA to $1 / app install.
          'biddingScheme': {
              'xsi_type': 'TargetCpaBiddingScheme',
              'targetCpa': {
                  'microAmount': '1000000'
              }
          },
          'biddingStrategyType': 'TARGET_CPA'
      },
      # Note that only the budgetId is required
      'budget': {
          'budgetId': budget_id
      },
      # Optional fields
      'startDate': (datetime.datetime.now() +
                    datetime.timedelta(1)).strftime('%Y%m%d'),
      'endDate': (datetime.datetime.now() +
                  datetime.timedelta(365)).strftime('%Y%m%d'),
  }

  universal_app_campaign['settings'] = [
      # Set the campaign's assets and ad text ideas. These values will
      # be used to generate ads.
      {
          'xsi_type': 'UniversalAppCampaignSetting',
          'appId': 'com.labpixies.colordrips',
          'appVendor': 'VENDOR_GOOGLE_MARKET',
          'description1': 'A cool puzzle game',
          'description2': 'Remove connected blocks',
          'description3': '3 difficulty levels',
          'description4': '4 colorful fun skins',
          # Optional: You can set up to 20 image assets for your campaign.
          # See upload_image.py for an example on how to upload images.
          #
          # 'imageMediaIds': [INSERT_IMAGE_MEDIA_ID(s)_HERE]
      }
  ]

  # Optimize this campaign for getting new users for your app.
  universal_app_campaign_setting = universal_app_campaign['settings'][0]
  universal_app_campaign_setting['universalAppBiddingStrategyGoalType'] = (
      'OPTIMIZE_FOR_INSTALL_CONVERSION_VOLUME')

  # Optional: If you select the OPTIMIZE_FOR_IN_APP_CONVERSION_VOLUME goal type,
  # then also specify your in-app conversion types so AdWords can focus your
  # campaign on people who are most likely to complete the corresponding in-app
  # actions.
  #
  # Conversions type IDs can be retrieved using ConversionTrackerService.get.
  # universal_app_campaign['selectiveOptimization'] = {
  #     'conversionTypeIds': [INSERT_CONVERSION_TYPE_ID(s)_HERE]
  # }

  # Optional: Set the campaign settings for Advanced location options.
  universal_app_campaign['settings'].append({
      'xsi_type': 'GeoTargetTypeSetting',
      'positiveGeoTargetType': 'DONT_CARE',
      'negativeGeoTargetType': 'DONT_CARE'
  })

  # Construct operations and add campaigns.
  operations = [{
      'operator': 'ADD',
      'operand': universal_app_campaign
  }]

  campaigns = campaign_service.mutate(operations)['value']

  # Display results.
  if campaigns:
    for campaign in campaigns:
      print ('Universal App Campaign with name "%s" and id "%s" was added.'
             % (campaign['name'], campaign['id']))
      # Optional: Set the campaign's location and language targeting. No other
      # targeting criteria can be used for Universal App campaigns.
      SetCampaignTargetingCriteria(client, campaign)
  else:
    print 'No Universal App campaigns were added.'


def CreateBudget(client):
  """Creates a budget and returns its budgetId.

  Args:
    client: An AdWordsClient instance.

  Returns:
    An int budgetId for the created Budget.
  """
  budget_service = client.GetService('BudgetService', version='v201809')

  # Create a budget.
  budget = {
      'name': 'Interplanetary Cruise App Budget #%s' % uuid.uuid4(),
      'amount': {
          'microAmount': '50000000'
      },
      'deliveryMethod': 'STANDARD',
      'isExplicitlyShared': False
  }

  budget_operations = [{
      'operator': 'ADD',
      'operand': budget
  }]

  # Create the budget and return its ID.
  budget_id = budget_service.mutate(budget_operations)['value'][0]['budgetId']

  return budget_id


def SetCampaignTargetingCriteria(client, campaign):
  """Sets targeting criteria for the given campaign.

  Args:
    client: An AdWordsClient instance.
    campaign: A suds object representing the campaign we wish to attach
      targeting criteria.
  """
  campaign_criterion_service = client.GetService('CampaignCriterionService')

  # Create locations. The IDs can be found in the documentation or retrieved
  # with the LocationCriterionService.
  criteria = [
      {
          'xsi_type': 'Location',
          'id': 21137  # California
      },
      {
          'xsi_type': 'Location',
          'id': 2484  # Mexico
      },
      {
          'xsi_type': 'Language',
          'id': 1000  # English
      },
      {
          'xsi_type': 'Language',
          'id': 1003  # Spanish
      }
  ]

  operations = [{
      'operator': 'ADD',
      'operand': {
          'campaignId': campaign['id'],
          'criterion': criterion
      }
  } for criterion in criteria]

  response = campaign_criterion_service.mutate(operations)

  if response and 'value' in response:
    # Display the added campaign targets.
    for criterion in response['value']:
      print ('Campaign criteria of type "%s" and id "%s" was added.'
             % (criterion['criterion']['type'],
                criterion['criterion']['id']))


if __name__ == '__main__':
  # Initialize client object.
  adwords_client = adwords.AdWordsClient.LoadFromStorage()

  main(adwords_client)

Create a negative broad match keywords list and attach it to a campaign

#!/usr/bin/env python
#
# Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Attaches a new shared list of negative broad match keywords to a campaign.

The LoadFromStorage method is pulling credentials and properties from a
"googleads.yaml" file. By default, it looks for this file in your home
directory. For more information, see the "Caching authentication information"
section of our README.

"""


import uuid
from googleads import adwords
from googleads import errors


CAMPAIGN_ID = 'INSERT_CAMPAIGN_ID_HERE'


def main(client, campaign_id):
  # Initialize appropriate services.
  shared_set_service = client.GetService('SharedSetService', version='v201809')
  shared_criterion_service = client.GetService('SharedCriterionService',
                                               version='v201809')
  campaign_shared_set_service = client.GetService('CampaignSharedSetService',
                                                  version='v201809')

  # Keywords to create a shared set of.
  keywords = ['mars cruise', 'mars hotels']
  # Create shared negative keyword set.
  shared_set = {
      'name': 'API Negative keyword list - %d' % uuid.uuid4(),
      'type': 'NEGATIVE_KEYWORDS'
  }

  # Add shared set.
  operations = [{
      'operator': 'ADD',
      'operand': shared_set
  }]

  response = shared_set_service.mutate(operations)

  if response and response['value']:
    shared_set = response['value'][0]
    shared_set_id = shared_set['sharedSetId']

    print 'Shared set with ID %d and name "%s" was successfully added.' % (
        shared_set_id, shared_set['name']
    )
  else:
    raise errors.GoogleAdsError('No shared set was added.')

    # Add negative keywords to shared set.
  shared_criteria = [
      {
          'criterion': {
              'xsi_type': 'Keyword',
              'text': keyword,
              'matchType': 'BROAD'
          },
          'negative': True,
          'sharedSetId': shared_set_id
      } for keyword in keywords
  ]

  operations = [
      {
          'operator': 'ADD',
          'operand': criterion
      } for criterion in shared_criteria
  ]

  response = shared_criterion_service.mutate(operations)

  if 'value' in response:
    for shared_criteria in response['value']:
      print 'Added shared criterion ID %d "%s" to shared set with ID %d.' % (
          shared_criteria['criterion']['id'],
          shared_criteria['criterion']['text'],
          shared_criteria['sharedSetId']
      )
  else:
    raise errors.GoogleAdsError('No shared keyword was added.')

    # Attach the articles to the campaign.
  campaign_set = {
      'campaignId': campaign_id,
      'sharedSetId': shared_set_id
  }

  operations = [
      {
          'operator': 'ADD',
          'operand': campaign_set
      }
  ]

  response = campaign_shared_set_service.mutate(operations)

  if 'value' in response:
    print 'Shared set ID %d was attached to campaign ID %d' % (
        response['value'][0]['sharedSetId'], response['value'][0]['campaignId']
    )
  else:
    raise errors.GoogleAdsError('No campaign shared set was added.')


if __name__ == '__main__':
  # Initialize client object.
  adwords_client = adwords.AdWordsClient.LoadFromStorage()

  main(adwords_client, CAMPAIGN_ID)

Find and remove shared sets and shared set criteria

#!/usr/bin/env python
#
# Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Demonstrates how to find and remove shared sets/shared set criterions.

The LoadFromStorage method is pulling credentials and properties from a
"googleads.yaml" file. By default, it looks for this file in your home
directory. For more information, see the "Caching authentication information"
section of our README.

"""

from googleads import adwords


CAMPAIGN_ID = 'INSERT_CAMPAIGN_ID_HERE'
PAGE_SIZE = 500


def main(client, campaign_id):
  # Initialize appropriate services.
  shared_criterion_service = client.GetService('SharedCriterionService',
                                               version='v201809')
  campaign_shared_set_service = client.GetService('CampaignSharedSetService',
                                                  version='v201809')

  shared_set_ids = []
  criterion_ids = []

  # First, retrieve all shared sets associated with the campaign.

  # Create selector for shared sets to:
  # - filter by campaign ID,
  # - filter by shared set type.
  selector = {
      'fields': ['SharedSetId', 'CampaignId', 'SharedSetName', 'SharedSetType',
                 'Status'],
      'predicates': [
          {
              'field': 'CampaignId',
              'operator': 'EQUALS',
              'values': [campaign_id]
          },
          {
              'field': 'SharedSetType',
              'operator': 'IN',
              'values': ['NEGATIVE_KEYWORDS', 'NEGATIVE_PLACEMENTS']
          }
      ],
      'paging': {
          'startIndex': 0,
          'numberResults': PAGE_SIZE
      }
  }

  # Set initial values:
  offset = 0
  page = {'totalNumEntries': 1}

  while page['totalNumEntries'] > offset:
    page = campaign_shared_set_service.get(selector)
    if 'entries' in page:
      for shared_set in page['entries']:
        print 'Campaign shared set ID %d and name "%s"' % (
            shared_set['sharedSetId'], shared_set['sharedSetName']
        )
        shared_set_ids.append(shared_set['sharedSetId'])
    # Increment values to request the next page.
    offset += PAGE_SIZE
    selector['paging']['startIndex'] = offset

  # Next, retrieve criterion IDs for all found shared sets.
  selector = {
      'fields': ['SharedSetId', 'Id', 'KeywordText', 'KeywordMatchType',
                 'PlacementUrl'],
      'predicates': [
          {
              'field': 'SharedSetId',
              'operator': 'IN',
              'values': shared_set_ids
          }
      ],
      'paging': {
          'startIndex': 0,
          'numberResults': PAGE_SIZE
      }
  }

  # Set initial values:
  offset = 0
  page = {'totalNumEntries': 1}

  while page['totalNumEntries'] > offset:
    page = shared_criterion_service.get(selector)
    if 'entries' in page:
      for shared_criterion in page['entries']:
        if shared_criterion['criterion']['type'] == 'KEYWORD':
          print ('Shared negative keyword with ID %d and text "%s" was'
                 'found.' % (shared_criterion['criterion']['id'],
                             shared_criterion['criterion']['text']))
        elif shared_criterion['criterion']['type'] == 'PLACEMENT':
          print ('Shared negative placement with ID %d and url "%s" was'
                 'found.' % (shared_criterion['criterion']['id'],
                             shared_criterion['criterion']['url']))
        else:
          print 'Shared criterion with ID %d was found.' % (
              shared_criterion['criterion']['id'],
          )
        criterion_ids.append({
            'sharedSetId': shared_criterion['sharedSetId'],
            'criterionId': shared_criterion['criterion']['id']
        })
    # Increment values to request the next page.
    offset += PAGE_SIZE
    selector['paging']['startIndex'] = offset

  # Finally, remove the criteria.
  if criterion_ids:
    operations = [
        {
            'operator': 'REMOVE',
            'operand': {
                'criterion': {'id': criterion['criterionId']},
                'sharedSetId': criterion['sharedSetId']
            }
        } for criterion in criterion_ids
    ]

    response = shared_criterion_service.mutate(operations)
    if 'value' in response:
      for criterion in response['value']:
        print ('Criterion ID %d was successfully removed from shared set ID'
               '%d.' % (criterion['criterion']['id'], criterion['sharedSetId']))
  else:
    print 'No shared criteria were removed.'


if __name__ == '__main__':
  # Initialize client object.
  adwords_client = adwords.AdWordsClient.LoadFromStorage()

  main(adwords_client, CAMPAIGN_ID)

Get ad group level bid modifiers

#!/usr/bin/env python
#
# Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Retrieves the ad group level bid modifiers for a campaign.

The LoadFromStorage method is pulling credentials and properties from a
"googleads.yaml" file. By default, it looks for this file in your home
directory. For more information, see the "Caching authentication information"
section of our README.

"""

from googleads import adwords


PAGE_SIZE = 500


def main(client):
  # Initialize appropriate service.
  ad_group_bid_modifier_service = client.GetService(
      'AdGroupBidModifierService', version='v201809')

  # Get all ad group bid modifiers for the campaign.
  selector = {
      'fields': ['CampaignId', 'AdGroupId', 'BidModifier', 'Id'],
      'paging': {
          'startIndex': '0',
          'numberResults': str(PAGE_SIZE)
      }
  }

  # Set initial values.
  offset, page = 0, {}
  more_results = True

  while more_results:
    page = ad_group_bid_modifier_service.get(selector)
    if page['entries']:
      for modifier in page['entries']:
        value = (modifier['bidModifier'] if 'bidModifier' in modifier
                 else 'unset')
        print ('Campaign ID %s, AdGroup ID %s, Criterion ID %s has ad group '
               'level modifier: %s' %
               (modifier['campaignId'], modifier['adGroupId'],
                modifier['criterion']['id'], value))

      # Increment values to request the next page.
      offset += PAGE_SIZE
      selector['paging']['startIndex'] = str(offset)
    else:
      print 'No ad group bid modifiers returned.'
    more_results = int(page['totalNumEntries']) > offset


if __name__ == '__main__':
  # Initialize client object.
  adwords_client = adwords.AdWordsClient.LoadFromStorage()

  main(adwords_client)

Add a portfolio bidding strategy to a campaign

#!/usr/bin/env python
#
# Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Adds a Shared Bidding Strategy and uses it to construct a campaign.

The LoadFromStorage method is pulling credentials and properties from a
"googleads.yaml" file. By default, it looks for this file in your home
directory. For more information, see the "Caching authentication information"
section of our README.

"""


import uuid
from googleads import adwords


# Enter a shared budget ID to re-use an existing budget or leave as None to
# create a new one.
BUDGET_ID = None


def main(client, budget_id):
  bidding_strategy = CreateBiddingStrategy(client)

  if budget_id is None:
    budget = CreateSharedBudget(client)
    budget_id = budget['budgetId']

  CreateCampaignWithBiddingStrategy(client, bidding_strategy['id'], budget_id)


def CreateBiddingStrategy(client):
  """Creates a bidding strategy object.

  Args:
    client: AdWordsClient the client to run the example with.

  Returns:
    dict An object representing a bidding strategy.
  """
  # Initialize appropriate service.
  bidding_strategy_service = client.GetService(
      'BiddingStrategyService', version='v201809')

  # Create a shared bidding strategy.
  shared_bidding_strategy = {
      'name': 'Maximize Clicks %s' % uuid.uuid4(),
      'biddingScheme': {
          'xsi_type': 'TargetSpendBiddingScheme',
          # Optionally set additional bidding scheme parameters.
          'bidCeiling': {
              'microAmount': '2000000'
          }
      }
  }

  # Create operation.
  operation = {
      'operator': 'ADD',
      'operand': shared_bidding_strategy
  }

  response = bidding_strategy_service.mutate([operation])
  new_bidding_strategy = response['value'][0]

  print ('Shared bidding strategy with name "%s" and ID "%s" of type "%s"'
         'was created.' %
         (new_bidding_strategy['name'], new_bidding_strategy['id'],
          new_bidding_strategy['biddingScheme']['BiddingScheme.Type']))

  return new_bidding_strategy


def CreateSharedBudget(client):
  """Creates an explicit budget to be used only to create the Campaign.

  Args:
    client: AdWordsClient the client to run the example with.

  Returns:
    dict An object representing a shared budget.
  """
  # Initialize appropriate service.
  budget_service = client.GetService('BudgetService', version='v201809')

  # Create a shared budget
  budget = {
      'name': 'Shared Interplanetary Budget #%s' % uuid.uuid4(),
      'amount': {
          'microAmount': '2000000'
      },
      'deliveryMethod': 'STANDARD',
      'isExplicitlyShared': 'true'
  }

  # Create operation.
  operation = {
      'operator': 'ADD',
      'operand': budget
  }

  response = budget_service.mutate([operation])
  return response['value'][0]


def CreateCampaignWithBiddingStrategy(client, bidding_strategy_id, budget_id):
  """Create a Campaign with a Shared Bidding Strategy.

  Args:
    client: AdWordsClient the client to run the example with.
    bidding_strategy_id: string the bidding strategy ID to use.
    budget_id: string the shared budget ID to use.

  Returns:
    dict An object representing a campaign.
  """
  # Initialize appropriate service.
  campaign_service = client.GetService('CampaignService', version='v201809')

  # Create campaign.
  campaign = {
      'name': 'Interplanetary Cruise #%s' % uuid.uuid4(),
      'budget': {
          'budgetId': budget_id
      },
      'biddingStrategyConfiguration': {
          'biddingStrategyId': bidding_strategy_id
      },
      'advertisingChannelType': 'SEARCH',
      'networkSetting': {
          'targetGoogleSearch': 'true',
          'targetSearchNetwork': 'true',
          'targetContentNetwork': 'true'
      }
  }

  # Create operation.
  operation = {
      'operator': 'ADD',
      'operand': campaign
  }

  response = campaign_service.mutate([operation])
  new_campaign = response['value'][0]

  print ('Campaign with name "%s", ID "%s" and bidding scheme ID "%s" '
         'was created.' %
         (new_campaign['name'], new_campaign['id'],
          new_campaign['biddingStrategyConfiguration']['biddingStrategyId']))

  return new_campaign


if __name__ == '__main__':
  # Initialize client object.
  adwords_client = adwords.AdWordsClient.LoadFromStorage()
  main(adwords_client, BUDGET_ID)

Send feedback about...

AdWords API
AdWords API
Need help? Visit our support page.