The code samples below provide examples of common remarketing functions using the AdWords API. Client Library.
Create a remarketing user list (audience)
#!/usr/bin/env ruby # Encoding: utf-8 # # Copyright:: Copyright 2011, 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 illustrates how to create a user list (a.k.a. Audience) and shows # its associated conversion tracker code snippet. require 'adwords_api' def add_audience() # 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') user_list_srv = adwords.service(:AdwordsUserListService, API_VERSION) conv_tracker_srv = adwords.service(:ConversionTrackerService, API_VERSION) # Prepare for adding remarketing user list. name = "Mars cruise customers #%d" % (Time.new.to_f * 1000).to_i operation = { :operator => 'ADD', :operand => { # The 'xsi_type' field allows you to specify the xsi:type of the object # being created. It's only necessary when you must provide an explicit # type that the client library can't infer. :xsi_type => 'BasicUserList', :name => name, :description => 'A list of mars cruise customers in the last year', :membership_life_span => 365, :conversion_types => [{:name => name}], # Optional field. :status => 'OPEN' } } # Add user list. response = user_list_srv.mutate([operation]) if response and response[:value] user_list = response[:value].first # Get conversion snippets. conversion_trackers = {} if user_list and user_list[:conversion_types] conversion_ids = user_list[:conversion_types][:id] selector = { :fields => ['Id', 'GoogleGlobalSiteTag', 'GoogleEventSnippet'], :predicates => [ {:field => 'Id', :operator => 'IN', :values => [conversion_ids]} ] } conv_tracker_response = conv_tracker_srv.get(selector) if conv_tracker_response and conv_tracker_response[:entries] conv_tracker_response[:entries].each do |conversion_tracker| conversion_trackers[conversion_tracker[:id]] = conversion_tracker end end end puts "User list with name '%s' and ID %d was added." % [user_list[:name], user_list[:id]] # Display the list of associated conversion code snippets. user_list_conversion_type = user_list[:conversion_types] conversion_tracker = conversion_trackers[user_list_conversion_type[:id].to_i] puts "Google global site tag:\n%s\n" % conversion_tracker[:google_global_site_tag] puts "Google event snippet:\n%s\n" % conversion_tracker[:google_event_snippet] else puts 'No user lists were added.' end end if __FILE__ == $0 API_VERSION = :v201809 begin add_audience() # 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
Create an AdWords conversion tracker and add to it upload conversions
#!/usr/bin/env ruby # Encoding: utf-8 # # Copyright:: Copyright 2011, 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 illustrates how to add an AdWords conversion tracker and an # upload conversion tracker. require 'adwords_api' def add_conversion_trackers() # 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') conv_tracker_srv = adwords.service(:ConversionTrackerService, API_VERSION) # Prepare for adding AdWords conversion tracker. operation1 = { :operator => 'ADD', :operand => { # The 'xsi_type' field allows you to specify the xsi:type of the object # being created. It's only necessary when you must provide an explicit # type that the client library can't infer. :xsi_type => 'AdWordsConversionTracker', :name => "Earth to Mars Cruises Conversion #%d" % (Time.new.to_f * 1000).to_i, :category => 'DEFAULT', # Optional fields: :status => 'ENABLED', :viewthrough_lookback_window => 15, :default_revenue_value => 23.41, :always_use_default_revenue_value => true } } # Prepare for adding upload conversion tracker. operation2 = { :operator => 'ADD', :operand => { # The 'xsi_type' field allows you to specify the xsi:type of the object # being created. It's only necessary when you must provide an explicit # type that the client library can't infer. :xsi_type => 'UploadConversion', # Set an appropriate category. This field is optional, and will be set to # DEFAULT if not mentioned. :category => 'LEAD', :name => "Upload Conversion #%d" % (Time.new.to_f * 1000).to_i, :viewthrough_lookback_window => 30, :ctc_lookback_window => 90, # Optional: Set the default currency code to use for conversions that do # not specify a conversion currency. This must be an ISO 4217 3-character # currency code such as "EUR" or "USD". # If this field is not set on this UploadConversion, AdWords will use the # account currency. :default_revenue_currency_code => 'EUR', # Optional: Set the default revenue value to use for conversions that do # not specify a conversion value. # Note: that this value should NOT be in micros. :default_revenue_value => 2.50, # Optional: To upload fractional conversion credits, mark the upload # conversion as externally attributed. See # https://developers.google.com/adwords/api/docs/guides/conversion-tracking#importing_externally_attributed_conversions # to learn more about importing externally attributed conversions. #:is_externally_attributed => true } } # Add conversion trackers. response = conv_tracker_srv.mutate([operation1, operation2]) if response and response[:value] response[:value].each do |tracker| puts ("\nConversion tracker with ID %d, name '%s', status '%s' and " + "category '%s' was added.") % [tracker[:id], tracker[:name], tracker[:status], tracker[:category]] if tracker[:xsi_type] == 'AdWordsConversionTracker' puts "Google global site tag:\n%s\n" % tracker[:google_global_site_tag] puts "Google event snippet:\n%s\n" % tracker[:google_event_snippet] end end else puts 'No conversion trackers were added.' end end if __FILE__ == $0 API_VERSION = :v201809 begin add_conversion_trackers() # 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
Create and populate a user list
#!/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 user list (a.k.a. audience) and uploads members to # populate the list. # # Note: It may take several hours for the list to be populated with members. # Email addresses and other member information must be associated with a Google # account. For privacy purposes, the user list size will show as zero until the # list has at least 1000 members. After that, the size will be rounded to the # two most significant digits. require 'adwords_api' require 'digest' def add_crm_based_user_list() # 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') user_list_srv = adwords.service(:AdwordsUserListService, API_VERSION) user_list = { :xsi_type => 'CrmBasedUserList', :name => 'Customer relationship management list #%d' % Time.new.usec, :description => 'A list of customers that originated from email addresses', # CRM-based user lists can use a membershipLifeSpan of 10000 to indicate # unlimited; otherwise normal values apply. :membership_life_span => 30, :upload_key_type => 'CONTACT_INFO' } operation = { :operand => user_list, :operator => 'ADD' } result = user_list_srv.mutate([operation]) user_list_id = result[:value].first[:id] emails = ['customer1@example.com', 'customer2@example.com', ' Customer3@example.com '] sha_digest = Digest::SHA256.new members = emails.map do |email| # Remove leading and trailing whitespace and convert all characters to # lowercase before generating the hashed version. { :hashed_email => sha_digest.hexdigest(normalize_text(email)) } end first_name = 'John' last_name = 'Doe' country_code = 'US' zip_code = '10001' members << { :address_info => { # First and last name must be normalized and hashed. :hashed_first_name => sha_digest.hexdigest(normalize_text(first_name)), :hashed_last_name => sha_digest.hexdigest(normalize_text(last_name)), # Country code and zip code are sent in plaintext. :country_code => country_code, :zip_code => zip_code } } mutate_members_operation = { :operand => { :user_list_id => user_list_id, :members_list => members }, :operator => 'ADD' } mutate_members_result = user_list_srv.mutate_members([mutate_members_operation]) mutate_members_result[:user_lists].each do |user_list| puts "User list with name '%s' and ID '%d' was added." % [user_list[:name], user_list[:id]] end end def normalize_text(text) text.strip.downcase end if __FILE__ == $0 API_VERSION = :v201809 begin add_crm_based_user_list() # 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
Create rule-based user lists
#!/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 two rule-based remarketing user lists: one with no site # visit data restrictions, and another that will only include users who visit # your site in the next six months. require 'adwords_api' def add_rule_based_user_lists() # 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') user_list_srv = adwords.service(:AdwordsUserListService, API_VERSION) # First rule item group - users who visited the checkout page and had more # than one item in their shopping cart. cart_rule_item = { :xsi_type => 'StringRuleItem', :key => { :name => 'ecomm_pagetype' }, :op => 'EQUALS', :value => 'checkout' } cart_size_rule_item = { :xsi_type => 'NumberRuleItem', :key => { :name => 'cartsize' }, :op => 'GREATER_THAN', :value => 1.0 } # Combine the two rule items into a RuleItemGroup so AdWords will AND # their rules together. checkout_multiple_item_group = { :items => [cart_rule_item, cart_size_rule_item] } # Second rule item group - users who checked out after October 31st # and before January 1st. start_date_rule_item = { :xsi_type => 'DateRuleItem', :key => { :name => 'checkoutdate' }, :op => 'AFTER', :value => '20141031' } end_date_rule_item = { :xsi_type => 'DateRuleItem', :key => { :name => 'checkoutdate' }, :op => 'BEFORE', :value => '20150101' } # Combine the date rule items into a RuleItemGroup. checked_out_nov_dec_item_group = { :items => [start_date_rule_item, end_date_rule_item] } # Combine the rule item groups into a Rule so AdWords knows how to apply the # rules. rule = { :groups => [checkout_multiple_item_group, checked_out_nov_dec_item_group], # ExpressionRuleUserLists can use either CNF or DNF for matching. CNF means # 'at least one item in each rule item group must match', and DNF means 'at # least one entire rule item group must match'. # DateSpecificRuleUserList only supports DNF. You can also omit the rule # type altogether to default to DNF. :rule_type => 'DNF' } # Third and fourth rule item groups. # Visitors of a page who visited another page. sites = ['example.com/example1', 'example.com/example2'] # Create two rules to show that a visitor browsed two sites. user_visited_site_rules = sites.map do |site| { :groups => [ :items => [ { :xsi_type => 'StringRuleItem', :key => {:name => 'url__'}, :op => 'EQUALS', :value => site } ]]} end # Create the user list with no restrictions on site visit date. expression_user_list = { :xsi_type => 'ExpressionRuleUserList', :name => 'Users who checked out in November or December OR ' + 'visited the checkout page with more than one item in their cart', :description => 'Expression based user list', :rule => rule, # Optional: Set the prepopulationStatus to REQUESTED to include past users # in the user list. :prepopulation_status => 'REQUESTED' } # Create the user list restricted to users who visit your site within the # specified timeframe. date_user_list = { :xsi_type => 'DateSpecificRuleUserList', :name => 'Date rule user list created at ' + Time.now.to_s, :description => 'Users who visited the site between 20141031 and ' + '20150331 and checked out in November or December OR visited the ' + 'checkout page with more than one item in their cart', # We re-use the rule here. To avoid side effects, we need a deep copy. :rule => Marshal.load(Marshal.dump(rule)), # Set the start and end dates of the user list. :start_date => '20141031', :end_date => '20150331' } # Create the user list where "Visitors of a page who did visit another page". # To create a user list where "Visitors of a page who did not visit another # page", change the ruleOperator from AND to AND_NOT. combined_rule_user_list = { :xsi_type => 'CombinedRuleUserList', :name => 'Combined rule user list "Visitors of a page who did visit another page"', :description => 'Users who visited two sites.', :left_operand => user_visited_site_rules[0], :right_operand => user_visited_site_rules[1], :rule_operator => 'AND' } # Create operations to add the user lists. all_lists = [expression_user_list, date_user_list, combined_rule_user_list] operations = all_lists.map do |user_list| { :operand => user_list, :operator => 'ADD' } end # Submit the operations. response = user_list_srv.mutate(operations) # Display the results. response[:value].each do |user_list| puts ("User list added with ID %d, name '%s', status '%s', " + "list type '%s', accountUserListStatus '%s', description '%s'.") % [user_list[:id], user_list[:name], user_list[:status], user_list[:list_type], user_list[:account_user_list_status], user_list[:description]] end end if __FILE__ == $0 API_VERSION = :v201809 begin add_rule_based_user_lists() # 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
Import conversion adjustments for existing conversions
#!/usr/bin/env ruby # Encoding: utf-8 # # 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 code example imports conversion adjustments for conversions that already # exist. To set up a conversion tracker, run the add_conversion_tracker.pl # example. require 'adwords_api' def upload_conversion_adjustments(conversion_name, gclid, adjustment_type, conversion_time, adjustment_time, adjusted_value) # 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') adjustment_srv = adwords.service(:OfflineConversionAdjustmentFeedService, API_VERSION) # This example demonstrates adjusting one conversion, but you can add more # than one operation to adjust more in a single mutate request. operations = [] # Associate conversion adjustments with the existing named conversion tracker. # The GCLID should have been uploaded before with a conversion. feed = { :xsi_type => 'GclidOfflineConversionAdjustmentFeed', :conversion_name => conversion_name, :google_click_id => gclid, :conversion_time => conversion_time, :adjustment_type => adjustment_type, :adjustment_time => adjustment_time, :adjusted_value => adjusted_value } operations << { :operator => 'ADD', :operand => feed } response = adjustment_srv.mutate(operations) new_feed = response[:value].first puts ('Uploaded offline conversion adjustment value of "%s" for Google ' + 'Click ID "%s"') % [new_feed[:conversion_name], new_feed[:google_click_id]] end if __FILE__ == $0 API_VERSION = :v201809 begin conversion_name = 'INSERT_CONVERSION_NAME_HERE' gclid = 'INSERT_GCLID_HERE' adjustment_type = 'INSERT_ADJUSTMENT_TYPE_HERE' conversion_time = 'INSERT_CONVERSION_TIME_HERE' adjustment_time = 'INSERT_ADJUSTMENT_TIME_HERE' adjusted_value = 'INSERT_ADJUSTED_VALUE_HERE'.to_f upload_conversion_adjustments(conversion_name, gclid, adjustment_type, conversion_time, adjustment_time, adjusted_value) # 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
Import offline call conversions
#!/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 code example imports offline conversion values for calls related to ads # in your account. # # To set up a conversion tracker, run the add_conversion_trackers.rb example. require 'adwords_api' def upload_offline_call_conversions(caller_id, call_start_time, conversion_name, conversion_time, conversion_value) # 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') occ_feed_srv = adwords.service(:OfflineCallConversionFeedService, API_VERSION) # Associate offline conversions with the existing named conversion tracker. If # this tracker was newly created, it may be a few hours before it can accept # conversions. feed = { :caller_id => caller_id, :call_start_time => call_start_time, :conversion_name => conversion_name, :conversion_time => conversion_time, :conversion_value => conversion_value } occ_operations = [{ :operator => 'ADD', :operand => feed }] occ_response = occ_feed_srv.mutate(occ_operations) if occ_response[:value] occ_response[:value].each do |occ_feed| puts 'Uploaded offline call conversion value "%s" for caller ID "%s"' % [occ_feed[:conversion_name], occ_feed[:caller_id]] end end end if __FILE__ == $0 API_VERSION = :v201809 begin caller_id = 'INSERT_CALLER_ID_HERE' # For times, use the format yyyyMMdd HHmmss tz. For more details on # formats, see: # https://developers.google.com/adwords/api/docs/appendix/codes-formats#date-and-time-formats # For time zones, see: # https://developers.google.com/adwords/api/docs/appendix/codes-formats#timezone-ids call_start_time = 'INSERT_CALL_START_TIME_HERE' conversion_name = 'INSERT_CONVERSION_NAME_HERE' conversion_time = 'INSERT_CONVERSION_TIME_HERE' conversion_value = 'INSERT_CONVERSION_VALUE_HERE' upload_offline_call_conversions( caller_id, call_start_time, conversion_name, conversion_time, conversion_value ) # 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
Import offline click conversions
#!/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 code example imports offline conversion values for specific clicks to # your account. To get Google Click ID for a click, run # CLICK_PERFORMANCE_REPORT. To set up a conversion tracker, run the # add_conversion_trackers.rb example. require 'adwords_api' require 'date' def upload_offline_conversions(conversion_name, google_click_id, conversion_time, conversion_value) # 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') conversion_feed_srv = adwords.service(:OfflineConversionFeedService, API_VERSION) # Associate offline conversions with the existing named conversion tracker. If # this tracker was newly created, it may be a few hours before it can accept # conversions. feed = { :conversion_name => conversion_name, :google_click_id => google_click_id, :conversion_time => conversion_time, :conversion_value => conversion_value } # Optional: To upload fractional conversion credits, set the external # attribution model and credit. To use this feature, your conversion tracker # should be marked as externally attributed. See # https://developers.google.com/adwords/api/docs/guides/conversion-tracking#importing_externally_attributed_conversions # to learn more about importing externally attributed conversions. # # feed[:external_attribution_model] = "Linear" # feed[:external_attribution_credit] = 0.3 return_feeds = conversion_feed_srv.mutate([ {:operator => 'ADD', :operand => feed}]) return_feeds[:value].each do |return_feed| puts ("Uploaded offline conversion value %.2f for Google Click ID '%s', " + 'to %s') % [return_feed[:conversion_value], return_feed[:google_click_id], return_feed[:conversion_name]] end end if __FILE__ == $0 API_VERSION = :v201809 begin # Name of the conversion tracker to upload to. conversion_name = 'INSERT_CONVERSION_NAME_HERE' # Google Click ID of the click for which offline conversions are uploaded. google_click_id = 'INSERT_GOOGLE_CLICK_ID_HERE' # Conversion time in 'yyyymmdd hhmmss' format. conversion_time = Time.new.strftime("%Y%m%d %H%M%S") # Conversion value to be uploaded. conversion_value = 'INSERT_CONVERSION_VALUE_HERE'.to_f upload_offline_conversions(conversion_name, google_click_id, conversion_time, conversion_value) # 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
Upload offline data for store sales transactions
#!/usr/bin/env ruby # Encoding: utf-8 # # Copyright:: Copyright 2017, 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 code example shows how to upload offline data for store sales # transactions. require 'adwords_api' require 'digest' require 'date' def upload_offline_data(conversion_name, external_upload_id, store_sales_upload_common_metadata_type, email_addresses, advertiser_upload_time, bridge_map_version_id, partner_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') unless email_addresses.size == 2 raise ArgumentError, ('%d email addresses specified. Please specify ' + 'exactly 2 email addresses.') % email_addresses.size end # Set partial failure to true since this example demonstrates how to handle # partial failure errors. adwords.partial_failure = true offline_data_upload_srv = adwords.service( :OfflineDataUploadService, API_VERSION) offline_data_list = [] # Create the first offline data for upload. # This transaction occurred 7 days ago with amount of 200 USD. transaction_time_1 = DateTime.parse((Date.today - 7).to_s) transaction_amount_1 = 200_000_000 user_identifiers_1 = [ create_user_identifier('HASHED_EMAIL', email_addresses[0]), create_user_identifier('STATE', 'New York') ] offline_data_list << create_offline_data(transaction_time_1, transaction_amount_1, 'USD', conversion_name, user_identifiers_1) # Create the second offline data for upload. # This transaction occurred 14 days ago with amount of 450 EUR. transaction_time_2 = DateTime.parse((Date.today - 14).to_s) transaction_amount_2 = 450_000_000 user_identifiers_2 = [ create_user_identifier('HASHED_EMAIL', email_addresses[1]), create_user_identifier('STATE', 'California') ] offline_data_list << create_offline_data(transaction_time_2, transaction_amount_2, 'EUR', conversion_name, user_identifiers_2) # Set the type and metadata of this upload. upload_metadata = { :xsi_type => store_sales_upload_common_metadata_type, :loyalty_rate => 1.0, :transaction_upload_rate => 1.0 } upload_type = 'STORE_SALES_UPLOAD_FIRST_PARTY' if store_sales_upload_common_metadata_type == METADATA_TYPE_3P upload_type = 'STORE_SALES_UPLOAD_THIRD_PARTY' upload_metadata[:advertiser_upload_time] = advertiser_upload_time upload_metadata[:valid_transaction_rate] = 1.0 upload_metadata[:partner_match_rate] = 1.0 upload_metadata[:partner_upload_rate] = 1.0 upload_metadata[:bridge_map_version_id] = bridge_map_version_id upload_metadata[:partner_id] = partner_id end # Create offline data upload object. offline_data_upload = { :external_upload_id => external_upload_id, :offline_data_list => offline_data_list, :upload_type => upload_type, :upload_metadata => upload_metadata } # Create an offline data upload operation. data_upload_operation = { :operator => 'ADD', :operand => offline_data_upload } # Upload offline data on the server and print some information. operations = [data_upload_operation] return_value = offline_data_upload_srv.mutate(operations) offline_data_upload = return_value[:value].first puts ('Uploaded offline data with external upload ID %d, and upload ' + 'status %s') % [offline_data_upload[:external_upload_id], offline_data_upload[:upload_status]] # Print any partial data errors from the response. unless return_value[:partial_failure_errors].nil? return_value[:partial_failure_errors].each do |api_error| # Get the index of the failed operation from the error's field path # elements. operation_index = get_field_path_element_index(api_error, 'operations') unless operation_index.nil? failed_offline_data_upload = operations[operation_index][:operand] # Get the index of the entry in the offline data list from the error's # field path elements. offline_data_list_index = get_field_path_element_index(api_error, 'offlineDataList') puts ("Offline data list entry %d in operation %d with external " + "upload ID %d and type '%s' has triggered failure for the " + " following reason: '%s'") % [offline_data_list_index, operation_index, failed_offline_data_upload[:external_upload_id], failed_offline_data_upload[:upload_type], api_error[:error_string]] else puts "A failure has occurred for the following reason: '%s'" % apiError[:error_string] end end end end def get_field_path_element_index(api_error, field) field_path_elements = api_error[:field_path_elements] return nil if field_path_elements.nil? field_path_elements.each_with_index do |field_path_element, i| if field == field_path_element[:field] return field_path_element[:index] end end return nil end def create_offline_data(transaction_time, transaction_micro_amount, transaction_currency, conversion_name, user_identifiers) store_sales_transaction = { :xsi_type => 'StoreSalesTransaction', # For times, use the format yyyyMMdd HHmmss [tz]. # For details, see # https://developers.google.com/adwords/api/docs/appendix/codes-formats#date-and-time-formats :transaction_time => transaction_time.strftime('%Y%m%d %H%M%S'), :conversion_name => conversion_name, :user_identifiers => user_identifiers, :transaction_amount => { :money => { :micro_amount => transaction_micro_amount }, :currency_code => transaction_currency } } return store_sales_transaction end def create_user_identifier(identifier_type, value) # If the user identifier type is a hashed type, also call the hash function # on the value. if HASHED_IDENTIFIER_TYPES.include?(identifier_type) value = hash_string(value) end user_identifier = { :user_identifier_type => identifier_type, :value => value } return user_identifier end def hash_string(text) sha_digest = Digest::SHA256.new sha_digest.hexdigest(normalize_text(text)) end def normalize_text(text) text.strip.downcase end if __FILE__ == $0 API_VERSION = :v201809 HASHED_IDENTIFIER_TYPES = [ 'HASHED_EMAIL', 'HASHED_FIRST_NAME', 'HASHED_LAST_NAME', 'HASHED_PHONE' ] # Store sales upload common metadata types METADATA_TYPE_1P = 'FirstPartyUploadMetadata' METADATA_TYPE_3P = 'ThirdPartyUploadMetadata' begin conversion_name = 'INSERT_CONVERSION_NAME_HERE' external_upload_id = 'INSERT_EXTERNAL_UPLOAD_ID_HERE'.to_i email_addresses = ['INSERT_EMAIL_ADDRESS_HERE', 'INSERT_EMAIL_ADDRESS_HERE'] # Set the below constant to METADATA_TYPE_3P if uploading third-party data. store_sales_upload_common_metadata_type = METADATA_TYPE_1P # The three constants below are needed when uploading third-party data. They # are not used when uploading first-party data. # Advertiser upload time to partner. # For times, use the format yyyyMMdd HHmmss tz. For more details on formats, # see: # https://developers.google.com/adwords/api/docs/appendix/codes-formats#timezone-ids advertiser_upload_time = 'INSERT_ADVERTISER_UPLOAD_TIME_HERE' bridge_map_version_id = 'INSERT_BRIDGE_MAP_VERSION_ID_HERE' partner_id = 'INSERT_PARTNER_ID_HERE'.to_i upload_offline_data(conversion_name, external_upload_id, store_sales_upload_common_metadata_type, email_addresses, advertiser_upload_time, bridge_map_version_id, partner_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