Extensions Samples

The code samples below provide examples of common extension functions using the AdWords API. Client Library.

Add Google My Business location extensions

#!/usr/bin/env ruby
# Encoding: utf-8
#
# Copyright:: Copyright 2014, Google Inc. All Rights Reserved.
#
# License:: 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 feed that syncs feed items from a Google My Business (GMB)
# account and associates the feed with a customer.

require 'adwords_api'
require 'date'

def add_gmb_location_extensions(gmb_email_address, gmb_access_token,
                                business_account_identifier)
  # AdwordsApi::Api will read a config file from ENV['HOME']/adwords_api.yml
  # when called without parameters.
  adwords = AdwordsApi::Api.new

  # To enable logging of SOAP requests, set the log_level value to 'DEBUG' in
  # the configuration file or provide your own logger:
  # adwords.logger = Logger.new('adwords_xml.log')

  feed_srv = adwords.service(:FeedService, API_VERSION)
  customer_feed_srv = adwords.service(:CustomerFeedService, API_VERSION)

  if gmb_access_token.nil?
    gmb_access_token = adwords.get_auth_handler.get_token(
        adwords.credential_handler.credentials)[:access_token]
  end

  # Create a feed that will sync to the Google My Business account specified
  # by gmb_email_address. Do not add FeedAttributes to this object, as AdWords
  # will add them automatically because this will be a system generated feed.
  gmb_feed = {
    :name => "GMB feed #%d" % (Time.new.to_f * 1000).to_i,
    :system_feed_generation_data => {
      :xsi_type => 'PlacesLocationFeedData',
      :o_auth_info => {
        :http_method => 'GET',
        :http_request_url => 'https://www.googleapis.com/auth/adwords',
        :http_authorization_header => "Bearer %s" % gmb_access_token
      },
      :email_address => gmb_email_address
    },
    # Since this feed's feed items will be managed by AdWords, you must set
    # its origin to ADWORDS.
    :origin => 'ADWORDS'
  }

  # Optional: specify labels to filter Google My Business listings. If
  # specified, only listings that have any of the labels set are synchronized
  # into FeedItems.
  gmb_feed[:system_feed_generation_data][:label_filters] =
      ['Stores in New York City']

  # Only include the business_account_identifier if it's specified.
  # A nil value will cause an invalid request.
  unless business_account_identifier.nil?
    gmb_feed[:system_feed_generation_data][:business_account_identifier] =
        business_account_identifier
  end

  gmb_operation = {
    :operator => 'ADD',
    :operand => gmb_feed
  }

  result = feed_srv.mutate([gmb_operation])
  added_feed = result[:value].first
  puts "Added GMB feed with ID %d" % added_feed[:id]

  # Add a CustomerFeed that associates the feed with this customer for the
  # LOCATION placeholder type.
  customer_feed = {
    :feed_id => added_feed[:id],
    :placeholder_types => [PLACEHOLDER_TYPE_LOCATION],
    :matching_function => {
      :operator => 'IDENTITY',
      :lhs_operand => {
        :xsi_type => 'ConstantOperand',
        :type => 'BOOLEAN',
        :boolean_value => true
      }
    }
  }

  customer_feed_operation = {
    :xsi_type => 'CustomerFeedOperation',
    :operator => 'ADD',
    :operand => customer_feed
  }

  added_customer_feed = nil
  number_of_attempts = 0
  while i < MAX_CUSTOMER_FEED_ADD_ATTEMPTS && !added_customer_feed
    number_of_attempts += 1
    begin
      result = customer_feed_srv.mutate([customer_feed_operation])
      added_customer_feed = result[:value].first
      puts "Attempt #%d to add the CustomerFeed was successful" %
          number_of_attempts
    rescue
      sleep_seconds = 5 * (2 ** number_of_attempts)
      puts ("Attempt #%d to add the CustomerFeed was not succeessful. " +
          "Waiting %d seconds before trying again.") %
          [number_of_attempts, sleep_seconds]
      sleep(sleep_seconds)
    end
  end

  unless added_customer_feed
    raise StandardError, ("Could not create the CustomerFeed after %d " +
        "attempts. Please retry the CustomerFeed ADD operation later.") %
        MAX_CUSTOMER_FEED_ADD_ATTEMPTS
  end

  puts "Added CustomerFeed for feed ID %d and placeholder type %d" %
      [added_customer_feed[:id], added_customer_feed[:placeholder_types].first]

  # OPTIONAL: Create a CampaignFeed to specify which FeedItems to use at the
  # Campaign level. This will be similar to the CampaignFeed in the
  # add_site_links example, except you can filter based on the business name
  # and category of each FeedItem by using a FeedAttributeOperand in your
  # matching function.

  # OPTIONAL: Create an AdGroupFeed for even more fine grained control over
  # which feed items are used at the AdGroup level.
end

if __FILE__ == $0
  API_VERSION = :v201708
  PLACEHOLDER_TYPE_LOCATION = 7
  MAX_CUSTOMER_FEED_ADD_ATTEMPTS = 10

  begin
    # The email address of either an owner or a manager of the GMB account.
    gmb_email_address = 'INSERT_GMB_EMAIL_ADDRESS_HERE'

    # If the gmbEmailAddress above is the same as you used to generate your
    # AdWords API refresh token, leave the value below as nil.
    # Otherwise, to obtain an access token for your GMB account, generate a
    # refresh token as you did for AdWords, but make sure you are logged in as
    # the same user as gmb_email_address above when you follow the link, then
    # capture the generated access token
    gmb_access_token = nil

    # If the gmb_email_address above is for a GMB manager instead of
    # the GMB account owner, then set business_account_identifier to the
    # +Page ID of a location for which the manager has access. See the
    # location extensions guide at
    # https://developers.google.com/adwords/api/docs/guides/feed-services-locations
    # for details.
    business_account_identifier = nil

    add_gmb_location_extensions(gmb_email_address, gmb_access_token,
                                business_account_identifier)

  # Authorization error.
  rescue AdsCommon::Errors::OAuth2VerificationRequired => e
    puts "Authorization credentials are not valid. Edit adwords_api.yml for " +
        "OAuth2 client ID and secret and run misc/setup_oauth2.rb example " +
        "to retrieve and store OAuth2 tokens."
    puts "See this wiki page for more details:\n\n  " +
        'https://github.com/googleads/google-api-ads-ruby/wiki/OAuth2'

  # HTTP errors.
  rescue AdsCommon::Errors::HttpError => e
    puts "HTTP Error: %s" % e

  # API errors.
  rescue AdwordsApi::Errors::ApiException => e
    puts "Message: %s" % e.message
    puts 'Errors:'
    e.errors.each_with_index do |error, index|
      puts "\tError [%d]:" % (index + 1)
      error.each do |field, value|
        puts "\t\t%s: %s" % [field, value]
      end
    end
  end
end

Add prices

#!/usr/bin/env ruby
# Encoding: utf-8
#
# Copyright:: Copyright 2016, Google Inc. All Rights Reserved.
#
# License:: 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 price extension and associates it with an account.
# Campaign targeting is also set using the specified campaign ID. To get
# campaigns, run basic_operations/get_campaigns.rb.

require 'adwords_api'

def add_prices(campaign_id)
  # AdwordsApi::Api will read a config file from ENV['HOME']/adwords_api.yml
  # when called without parameters.
  adwords = AdwordsApi::Api.new

  # To enable logging of SOAP requests, set the log_level value to 'DEBUG' in
  # the configuration file or provide your own logger:
  # adwords.logger = Logger.new('adwords_xml.log')

  customer_extension_setting_srv =
      adwords.service(:CustomerExtensionSettingService, API_VERSION)

  price_feed_item = {
    :xsi_type => 'PriceFeedItem',
    :price_extension_type => 'SERVICES',
    # Price qualifier is optional.
    :price_qualifier => 'FROM',
    :tracking_url_template => 'http://tracker.example.com/?u={lpurl}',
    :language => 'en',
    :campaign_targeting => {
      :targeting_campaign_id => campaign_id
    },
    :scheduling => {
      :feed_item_schedules => [
        {
          :day_of_week => 'SUNDAY',
          :start_hour => 10,
          :start_minute => 'ZERO',
          :end_hour => 18,
          :end_minute => 'ZERO'
        },
        {
          :day_of_week => 'SATURDAY',
          :start_hour => 10,
          :start_minute => 'ZERO',
          :end_hour => 22,
          :end_minute => 'ZERO'
        }
      ]
    },
    # To create a price extension, at least three table rows are needed.
    :table_rows => [
      create_price_table_row(
          'Scrubs',
          'Body Scrub, Salt Scrub',
          'http://www.example.com/scrubs',
          'http://m.example.com/scrubs',
          60000000,
          'USD',
          'PER_HOUR'
      ),
      create_price_table_row(
          'Hair Cuts',
          'Once a month',
          'http://www.example.com/haircuts',
          'http://m.example.com/haircuts',
          75000000,
          'USD',
          'PER_MONTH'
      ),
      create_price_table_row(
          'Skin Care Package',
          'Four times a month',
          'http://www.example.com/skincarepackage',
          nil,
          250000000,
          'USD',
          'PER_MONTH'
      )
    ]
  }

  customer_extension_setting = {
    :extension_type => 'PRICE',
    :extension_setting => {
      :extensions => [price_feed_item]
    }
  }

  operation = {
    :operator => 'ADD',
    :operand => customer_extension_setting
  }

  result = customer_extension_setting_srv.mutate([operation])

  new_extension_setting = result[:value].first
  puts "Extension setting with type '%s' was added to your account.\n" %
      new_extension_setting[:extension_type]
end

def create_price_table_row(header, description, final_url, final_mobile_url,
    price_in_micros, currency_code, price_unit)
  ret_val = {
    :header => header,
    :description => description,
    :final_urls => {
      :urls => [final_url]
    },
    :price => {
      :money => {
        :micro_amount => price_in_micros
      },
      :currency_code => currency_code
    },
    :price_unit => price_unit
  }

  # Optional: Set the mobile final URLs.
  unless final_mobile_url.nil? or final_mobile_url.empty?
    ret_val[:final_mobile_urls] = {:urls => [final_mobile_url]}
  end
end

if __FILE__ == $0
  API_VERSION = :v201708

  begin
    # Campaign ID to add site link to.
    campaign_id = 'INSERT_CAMPAIGN_ID_HERE'.to_i
    add_prices(campaign_id)

  # Authorization error.
  rescue AdsCommon::Errors::OAuth2VerificationRequired => e
    puts "Authorization credentials are not valid. Edit adwords_api.yml for " +
        "OAuth2 client ID and secret and run misc/setup_oauth2.rb example " +
        "to retrieve and store OAuth2 tokens."
    puts "See this wiki page for more details:\n\n  " +
        'https://github.com/googleads/google-api-ads-ruby/wiki/OAuth2'

  # HTTP errors.
  rescue AdsCommon::Errors::HttpError => e
    puts "HTTP Error: %s" % e

  # API errors.
  rescue AdwordsApi::Errors::ApiException => e
    puts "Message: %s" % e.message
    puts 'Errors:'
    e.errors.each_with_index do |error, index|
      puts "\tError [%d]:" % (index + 1)
      error.each do |field, value|
        puts "\t\t%s: %s" % [field, value]
      end
    end
  end
end

Add sitelinks to a campaign

#!/usr/bin/env ruby
# Encoding: utf-8
#
# Copyright:: Copyright 2015, Google Inc. All Rights Reserved.
#
# License:: 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 sitelinks feed and associates it with a campaign.

require 'adwords_api'
require 'date'

def add_site_links(campaign_id)
  # AdwordsApi::Api will read a config file from ENV['HOME']/adwords_api.yml
  # when called without parameters.
  adwords = AdwordsApi::Api.new

  # To enable logging of SOAP requests, set the log_level value to 'DEBUG' in
  # the configuration file or provide your own logger:
  # adwords.logger = Logger.new('adwords_xml.log')

  customer_srv = adwords.service(:CustomerService, API_VERSION)

  # Find the matching customer and its time zone. The get_customers method will
  # return a single customer corresponding to the configured client_customer_id.
  customer = customer_srv.get_customers().first
  customer_time_zone = customer[:date_time_zone]
  puts 'Found customer ID %d with time zone "%s"' %
      [customer[:customer_id], customer_time_zone]

  if customer_time_zone.nil?
    raise StandardError, 'Customer not found for customer ID: ' + customer_id
  end

  campaign_extension_setting_srv =
      adwords.service(:CampaignExtensionSettingService, API_VERSION)

  sitelink_1 = {
    :xsi_type => "SitelinkFeedItem",
    :sitelink_text => "Store Hours",
    :sitelink_final_urls => {
      :urls => ["http://www.example.com/storehours"]
    }
  }

  sitelink_2 = {
    :xsi_type => "SitelinkFeedItem",
    :sitelink_text => "Thanksgiving Specials",
    :sitelink_final_urls => {
      :urls => ["http://www.example.com/thanksgiving"]
    },
    :start_time => DateTime.new(Date.today.year, 11, 20, 0, 0, 0).
        strftime("%Y%m%d %H%M%S ") + customer_time_zone,
    :end_time => DateTime.new(Date.today.year, 11, 27, 23, 59, 59).
        strftime("%Y%m%d %H%M%S ") + customer_time_zone,
    # Target this sitelink for United States only. See
    # https://developers.google.com/adwords/api/docs/appendix/geotargeting
    # for valid geolocation codes.
    :geo_targeting => {
      :id => 2840
    },
    # Restrict targeting only to people physically within the United States.
    # Otherwise, this could also show to people interested in the United States
    # but not physically located there.
    :geo_targeting_restriction => {
      :geo_restriction => 'LOCATION_OF_PRESENCE'
    }
  }

  sitelink_3 = {
    :xsi_type => "SitelinkFeedItem",
    :sitelink_text => "Wifi available",
    :sitelink_final_urls => {
      :urls => ["http://www.example.com/mobile/wifi"]
    },
    :device_preference => {:device_preference => 30001},
    # Target this sitelink only when the ad is triggered by the keyword
    # "free wifi".
    :keyword_targeting => {
      :text => "free wifi",
      :match_type => 'BROAD'
    }
  }

  sitelink_4 = {
    :xsi_type => "SitelinkFeedItem",
    :sitelink_text => "Happy hours",
    :sitelink_final_urls => {
      :urls => ["http://www.example.com/happyhours"]
    },
    :scheduling => {
      :feed_item_schedules => [
        {
          :day_of_week => 'MONDAY',
          :start_hour => 18,
          :start_minute => 'ZERO',
          :end_hour => 21,
          :end_minute => 'ZERO'
        },
        {
          :day_of_week => 'TUESDAY',
          :start_hour => 18,
          :start_minute => 'ZERO',
          :end_hour => 21,
          :end_minute => 'ZERO'
        },
        {
          :day_of_week => 'WEDNESDAY',
          :start_hour => 18,
          :start_minute => 'ZERO',
          :end_hour => 21,
          :end_minute => 'ZERO'
        },
        {
          :day_of_week => 'THURSDAY',
          :start_hour => 18,
          :start_minute => 'ZERO',
          :end_hour => 21,
          :end_minute => 'ZERO'
        },
        {
          :day_of_week => 'FRIDAY',
          :start_hour => 18,
          :start_minute => 'ZERO',
          :end_hour => 21,
          :end_minute => 'ZERO'
        }
      ]
    }
  }

  campaign_extension_setting = {
    :campaign_id => campaign_id,
    :extension_type => 'SITELINK',
    :extension_setting => {
      :extensions => [sitelink_1, sitelink_2, sitelink_3, sitelink_4]
    }
  }

  operation = {
    :operand => campaign_extension_setting,
    :operator => 'ADD'
  }

  response = campaign_extension_setting_srv.mutate([operation])
  if response and response[:value]
    new_extension_setting = response[:value].first
    puts "Extension setting with type = %s was added to campaign ID %d" % [
      new_extension_setting[:extension_type],
      new_extension_setting[:campaign_id]
    ]
  elsif
    puts "No extension settings were created."
  end
end

if __FILE__ == $0
  API_VERSION = :v201708

  begin
    # Campaign ID to add site link to.
    campaign_id = 'INSERT_CAMPAIGN_ID_HERE'.to_i
    add_site_links(campaign_id)

  # Authorization error.
  rescue AdsCommon::Errors::OAuth2VerificationRequired => e
    puts "Authorization credentials are not valid. Edit adwords_api.yml for " +
        "OAuth2 client ID and secret and run misc/setup_oauth2.rb example " +
        "to retrieve and store OAuth2 tokens."
    puts "See this wiki page for more details:\n\n  " +
        'https://github.com/googleads/google-api-ads-ruby/wiki/OAuth2'

  # HTTP errors.
  rescue AdsCommon::Errors::HttpError => e
    puts "HTTP Error: %s" % e

  # API errors.
  rescue AdwordsApi::Errors::ApiException => e
    puts "Message: %s" % e.message
    puts 'Errors:'
    e.errors.each_with_index do |error, index|
      puts "\tError [%d]:" % (index + 1)
      error.each do |field, value|
        puts "\t\t%s: %s" % [field, value]
      end
    end
  end
end

Add sitelinks to a campaign using feeds

#!/usr/bin/env ruby
# Encoding: utf-8
#
# Copyright:: Copyright 2013, Google Inc. All Rights Reserved.
#
# License:: 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 sitelinks feed and associates it with a campaign.

require 'adwords_api'

def add_site_links(campaign_id)
  # AdwordsApi::Api will read a config file from ENV['HOME']/adwords_api.yml
  # when called without parameters.
  adwords = AdwordsApi::Api.new

  # To enable logging of SOAP requests, set the log_level value to 'DEBUG' in
  # the configuration file or provide your own logger:
  # adwords.logger = Logger.new('adwords_xml.log')

  feed_srv = adwords.service(:FeedService, API_VERSION)
  feed_item_srv = adwords.service(:FeedItemService, API_VERSION)
  feed_mapping_srv = adwords.service(:FeedMappingService, API_VERSION)
  campaign_feed_srv = adwords.service(:CampaignFeedService, API_VERSION)

  sitelinks_data = {}

  # Create site links feed first.
  site_links_feed = {
    :name => 'Feed For Site Links',
    :attributes => [
      {:type => 'STRING', :name => 'Link Text'},
      {:type => 'URL_LIST', :name => 'Final URLs'},
      {:type => 'STRING', :name => 'Line 2 Description'},
      {:type => 'STRING', :name => 'Line 3 Description'}
    ]
  }

  response = feed_srv.mutate([
      {:operator => 'ADD', :operand => site_links_feed}
  ])
  if response and response[:value]
    feed = response[:value].first
    # Attribute of type STRING.
    link_text_feed_attribute_id = feed[:attributes][0][:id]
    # Attribute of type URL_LIST.
    final_url_feed_attribute_id = feed[:attributes][1][:id]
    # Attribute of type STRING.
    line_2_feed_attribute_id = feed[:attributes][2][:id]
    #Attribute of type STRING.
    line_3_feed_attribute_id = feed[:attributes][3][:id]
    puts "Feed with name '%s' and ID %d was added with" %
        [feed[:name], feed[:id]]
    puts "\tText attribute ID %d and Final URLs attribute ID %d " +
        "and Line 2 attribute ID %d and Line 3 attribute ID %d." % [
          link_text_feed_attribute_id,
          final_url_feed_attribute_id,
          line_2_feed_attribute_id,
          line_3_feed_attribute_id
        ]

    sitelinks_data[:feed_id] = feed[:id]
    sitelinks_data[:link_text_feed_id] = link_text_feed_attribute_id
    sitelinks_data[:final_url_feed_id] = final_url_feed_attribute_id
    sitelinks_data[:line_2_feed_id] = line_2_feed_attribute_id
    sitelinks_data[:line_3_feed_id] = line_3_feed_attribute_id
  else
    raise new StandardError, 'No feeds were added.'
  end

  # Create site links feed items.
  items_data = [
    {
      :text => 'Home',
      :final_urls => ['http://www.example.com'],
      :line_2 => 'Home line 2',
      :line_3 => 'Home line 3'
    },
    {
      :text => 'Stores',
      :final_urls => ['http://www.example.com/stores'],
      :line_2 => 'Stores line 2',
      :line_3 => 'Stores line 3'
     },
    {
      :text => 'On Sale',
      :final_urls => ['http://www.example.com/sale'],
      :line_2 => 'On Sale line 2',
      :line_3 => 'On Sale line 3'
    },
    {
      :text => 'Support',
      :final_urls => ['http://www.example.com/support'],
      :line_2 => 'Support line 2',
      :line_3 => 'Support line 3'
    },
    {
      :text => 'Products',
      :final_urls => ['http://www.example.com/products'],
      :line_2 => 'Products line 2',
      :line_3 => 'Products line 3'
    },
    {
      :text => 'About Us',
      :final_urls => ['http://www.example.com/about'],
      :line_2 => 'About line 2',
      :line_3 => 'About line 3',
      :location_id => '21137'
    }
  ]

  feed_items = items_data.map do |item|
    feed_item = {
      :feed_id => sitelinks_data[:feed_id],
      :attribute_values => [
        {
          :feed_attribute_id => sitelinks_data[:link_text_feed_id],
          :string_value => item[:text]
        },
        {
          :feed_attribute_id => sitelinks_data[:final_url_feed_id],
          :string_values => item[:final_urls]
        },
        {
          :feed_attribute_id => sitelinks_data[:line_2_feed_id],
          :string_value => item[:line_2]
        },
        {
          :feed_attribute_id => sitelinks_data[:line_3_feed_id],
          :string_value => item[:line_3]
        }
      ]
    }
    # OPTIONAL: Use geographical targeting on a feed.
    # The IDs can be found in the documentation or retrieved with the
    # LocationCriterionService.
    unless item[:location_id].nil?
      feed_item[:geo_targeting] = {
        :id => item[:location_id]
      }
      # OPTIONAL: Restrict targeting only to people physically within the
      # location.
      feed_item[:geo_targeting_restriction] = {
        :geo_restriction => 'LOCATION_OF_PRESENCE'
      }
    end
    next feed_item
  end

  feed_items_operations = feed_items.map do |item|
    {:operator => 'ADD', :operand => item}
  end

  response = feed_item_srv.mutate(feed_items_operations)
  if response and response[:value]
    sitelinks_data[:feed_item_ids] = []
    response[:value].each do |feed_item|
      puts 'Feed item with ID %d was added.' % feed_item[:feed_item_id]
      sitelinks_data[:feed_item_ids] << feed_item[:feed_item_id]
    end
  else
    raise new StandardError, 'No feed items were added.'
  end

  # Create site links feed mapping.
  feed_mapping = {
    :placeholder_type => PLACEHOLDER_SITELINKS,
    :feed_id => sitelinks_data[:feed_id],
    :attribute_field_mappings => [
      {
        :feed_attribute_id => sitelinks_data[:link_text_feed_id],
        :field_id => PLACEHOLDER_FIELD_SITELINK_LINK_TEXT
      },
      {
        :feed_attribute_id => sitelinks_data[:final_url_feed_id],
        :field_id => PLACEHOLDER_FIELD_SITELINK_FINAL_URLS
      },
      {
        :feed_attribute_id => sitelinks_data[:line_2_feed_id],
        :field_id => PLACEHOLDER_FIELD_SITELINK_LINE_2_TEXT
      },
      {
        :feed_attribute_id => sitelinks_data[:line_3_feed_id],
        :field_id => PLACEHOLDER_FIELD_SITELINK_LINE_3_TEXT
      }
    ]
  }

  response = feed_mapping_srv.mutate([
      {:operator => 'ADD', :operand => feed_mapping}
  ])
  if response and response[:value]
    feed_mapping = response[:value].first
    puts ('Feed mapping with ID %d and placeholder type %d was saved for feed' +
        ' with ID %d.') % [
          feed_mapping[:feed_mapping_id],
          feed_mapping[:placeholder_type],
          feed_mapping[:feed_id]
        ]
  else
    raise new StandardError, 'No feed mappings were added.'
  end

  # Construct a matching function that associates the sitelink feeditems to the
  # campaign, and set the device preference to Mobile. See the matching function
  # guide at:
  # https://developers.google.com/adwords/api/docs/guides/feed-matching-functions
  # for more details.
  matching_function_string =
      "AND(IN(FEED_ITEM_ID, {%s}), EQUALS(CONTEXT.DEVICE, 'Mobile'))" %
      sitelinks_data[:feed_item_ids].join(',')

  # Create site links campaign feed.
  campaign_feed = {
    :feed_id => sitelinks_data[:feed_id],
    :campaign_id => campaign_id,
    :matching_function => {:function_string => matching_function_string},
    # Specifying placeholder types on the CampaignFeed allows the same feed
    # to be used for different placeholders in different Campaigns.
    :placeholder_types => [PLACEHOLDER_SITELINKS]
  }

  response = campaign_feed_srv.mutate([
      {:operator => 'ADD', :operand => campaign_feed}
  ])
  if response and response[:value]
    campaign_feed = response[:value].first
    puts 'Campaign with ID %d was associated with feed with ID %d.' %
      [campaign_feed[:campaign_id], campaign_feed[:feed_id]]
  else
    raise new StandardError, 'No campaign feeds were added.'
  end
end

if __FILE__ == $0
  API_VERSION = :v201708

  # See the Placeholder reference page for a list of all the placeholder types
  # and fields, see:
  #     https://developers.google.com/adwords/api/docs/appendix/placeholders
  PLACEHOLDER_SITELINKS = 1
  PLACEHOLDER_FIELD_SITELINK_LINK_TEXT = 1
  PLACEHOLDER_FIELD_SITELINK_FINAL_URLS = 5
  PLACEHOLDER_FIELD_SITELINK_LINE_2_TEXT = 3
  PLACEHOLDER_FIELD_SITELINK_LINE_3_TEXT = 4

  begin
    # Campaign ID to add site link to.
    campaign_id = 'INSERT_CAMPAIGN_ID_HERE'.to_i
    add_site_links(campaign_id)

  # Authorization error.
  rescue AdsCommon::Errors::OAuth2VerificationRequired => e
    puts "Authorization credentials are not valid. Edit adwords_api.yml for " +
        "OAuth2 client ID and secret and run misc/setup_oauth2.rb example " +
        "to retrieve and store OAuth2 tokens."
    puts "See this wiki page for more details:\n\n  " +
        'https://github.com/googleads/google-api-ads-ruby/wiki/OAuth2'

  # HTTP errors.
  rescue AdsCommon::Errors::HttpError => e
    puts "HTTP Error: %s" % e

  # API errors.
  rescue AdwordsApi::Errors::ApiException => e
    puts "Message: %s" % e.message
    puts 'Errors:'
    e.errors.each_with_index do |error, index|
      puts "\tError [%d]:" % (index + 1)
      error.each do |field, value|
        puts "\t\t%s: %s" % [field, value]
      end
    end
  end
end

Send feedback about...

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