You can use the Google Ads API to upload offline click conversions into Google Ads, mapping to the Uploads conversion source in the Google Ads UI, followed by Conversions from clicks. It gives you more flexibility in associating clicks with conversions. You can track ads that led to sales in the offline world, such as over the phone or through a sales rep.
You must enable your website and lead-tracking system to capture and store the
GCLID
, the unique ID that Google Ads provides for every impression of a Google ad.
If the click conversions are uploaded in the Google Ads UI,
auto-tagging is automatically
enabled so your website will start receiving the GCLID
as a URL parameter. But
this does not occur when using the Google Ads API, and you should enable auto-tagging
by updating the auto_tagging_enabled
attribute of
Customer
.
Code example
You need to associate your offline click conversions with a conversion action by
passing the GCLID
, conversion date time, conversion action resource name and
optionally the conversion value and currency to
ConversionUploadService
:
Java
private void runExample( GoogleAdsClient googleAdsClient, long customerId, long conversionActionId, String gclid, String conversionDateTime, Double conversionValue) { // Gets the conversion action resource name. String conversionActionResourceName = ResourceNames.conversionAction(customerId, conversionActionId); // Creates the click conversion. ClickConversion clickConversion = ClickConversion.newBuilder() .setConversionAction(conversionActionResourceName) .setConversionDateTime(conversionDateTime) .setConversionValue(conversionValue) .setCurrencyCode("USD") .setGclid(gclid) .build(); // Creates the conversion upload service client. try (ConversionUploadServiceClient conversionUploadServiceClient = googleAdsClient.getLatestVersion().createConversionUploadServiceClient()) { // Uploads the click conversion. Partial failure should always be set to true. UploadClickConversionsResponse response = conversionUploadServiceClient.uploadClickConversions( UploadClickConversionsRequest.newBuilder() .setCustomerId(Long.toString(customerId)) .addConversions(clickConversion) // Enables partial failure (must be true). .setPartialFailure(true) .build()); // Prints any partial errors returned. if (response.hasPartialFailureError()) { System.out.printf( "Partial error encountered: '%s'.%n", response.getPartialFailureError().getMessage()); } // Prints the result. ClickConversionResult result = response.getResults(0); // Only prints valid results. if (result.hasGclid()) { System.out.printf( "Uploaded conversion that occurred at '%s' from Google Click ID '%s' to '%s'.%n", result.getConversionDateTime(), result.getGclid(), result.getConversionAction()); } } }
C#
public void Run(GoogleAdsClient client, long customerId, long conversionActionId, string gclid, string conversionTime, double conversionValue) { // Get the ConversionActionService. ConversionUploadServiceClient conversionUploadService = client.GetService(Services.V6.ConversionUploadService); // Creates a click conversion by specifying currency as USD. ClickConversion clickConversion = new ClickConversion() { ConversionAction = ResourceNames.ConversionAction(customerId, conversionActionId), Gclid = gclid, ConversionValue = conversionValue, ConversionDateTime = conversionTime, CurrencyCode = "USD" }; try { // Issues a request to upload the click conversion. UploadClickConversionsResponse response = conversionUploadService.UploadClickConversions( new UploadClickConversionsRequest() { CustomerId = customerId.ToString(), Conversions = { clickConversion }, PartialFailure = true, ValidateOnly = false }); // Prints the result. ClickConversionResult uploadedClickConversion = response.Results[0]; Console.WriteLine($"Uploaded conversion that occurred at " + $"'{uploadedClickConversion.ConversionDateTime}' from Google " + $"Click ID '{uploadedClickConversion.Gclid}' to " + $"'{uploadedClickConversion.ConversionAction}'."); } catch (GoogleAdsException e) { Console.WriteLine("Failure:"); Console.WriteLine($"Message: {e.Message}"); Console.WriteLine($"Failure: {e.Failure}"); Console.WriteLine($"Request ID: {e.RequestId}"); throw; } }
PHP
public static function runExample( GoogleAdsClient $googleAdsClient, int $customerId, int $conversionActionId, string $gclid, string $conversionDateTime, float $conversionValue ) { // Creates a click conversion by specifying currency as USD. $clickConversion = new ClickConversion([ 'conversion_action' => ResourceNames::forConversionAction($customerId, $conversionActionId), 'gclid' => $gclid, 'conversion_value' => $conversionValue, 'conversion_date_time' => $conversionDateTime, 'currency_code' => 'USD', ]); // Issues a request to upload the click conversion. $conversionUploadServiceClient = $googleAdsClient->getConversionUploadServiceClient(); /** @var UploadClickConversionsResponse $response */ $response = $conversionUploadServiceClient->uploadClickConversions( $customerId, [$clickConversion], true ); // Prints the status message if any partial failure error is returned. // Note: The details of each partial failure error are not printed here, you can refer to // the example HandlePartialFailure.php to learn more. if (!is_null($response->getPartialFailureError())) { printf( "Partial failures occurred: '%s'.%s", $response->getPartialFailureError()->getMessage(), PHP_EOL ); } else { // Prints the result if exists. /** @var ClickConversionResult $uploadedClickConversion */ $uploadedClickConversion = $response->getResults()[0]; printf( "Uploaded click conversion that occurred at '%s' from Google Click ID '%s' " . "to '%s'.%s", $uploadedClickConversion->getConversionDateTime(), $uploadedClickConversion->getGclid(), $uploadedClickConversion->getConversionAction(), PHP_EOL ); } }
Python
def main( client, customer_id, conversion_action_id, gclid, conversion_date_time, conversion_value, ): """Creates a click conversion with a default currency of USD.""" click_conversion = client.get_type("ClickConversion", version="v6") conversion_action_service = client.get_service( "ConversionActionService", version="v6" ) click_conversion.conversion_action = conversion_action_service.conversion_action_path( customer_id, conversion_action_id ) click_conversion.gclid = gclid click_conversion.conversion_value = float(conversion_value) click_conversion.conversion_date_time = conversion_date_time click_conversion.currency_code = "USD" conversion_upload_service = client.get_service( "ConversionUploadService", version="v6" ) try: conversion_upload_response = conversion_upload_service.upload_click_conversions( customer_id, [click_conversion], partial_failure=True ) uploaded_click_conversion = conversion_upload_response.results[0] print( f"Uploaded conversion that occurred at " f'"{uploaded_click_conversion.conversion_date_time}" from ' f'Google Click ID "{uploaded_click_conversion.gclid}" ' f'to "{uploaded_click_conversion.conversion_action}"' ) except GoogleAdsException as ex: print( f'Request with ID "{ex.request_id}" failed with status ' f'"{ex.error.code().name}" and includes the following errors:' ) for error in ex.failure.errors: print(f'\tError with message "{error.message}".') if error.location: for field_path_element in error.location.field_path_elements: print(f"\t\tOn field: {field_path_element.field_name}") sys.exit(1)
Ruby
def upload_offline_conversion(customer_id, conversion_action_id, gclid, conversion_date_time, conversion_value) # GoogleAdsClient will read a config file from # ENV['HOME']/google_ads_config.rb when called without parameters client = Google::Ads::GoogleAds::GoogleAdsClient.new click_conversion = client.resource.click_conversion do |cc| cc.conversion_action = client.path.conversion_action(customer_id, conversion_action_id) cc.gclid = gclid cc.conversion_value = conversion_value.to_f cc.conversion_date_time = conversion_date_time cc.currency_code = 'USD' end response = client.service.conversion_upload.upload_click_conversions( customer_id: customer_id, conversions: [click_conversion], partial_failure: true, ) if response.partial_failure_error.nil? result = response.results.first puts "Uploaded conversion that occurred at #{result.conversion_date_time} " \ "from Google Click ID #{result.gclid} to #{result.conversion_action}." else failures = client.decode_partial_failure_error(response.partial_failure_error) puts "Request failed. Failure details:" failures.each do |failure| failure.errors.each do |error| puts "\t#{error.error_code.error_code}: #{error.message}" end end end end
Perl
sub upload_offline_conversion { my ($api_client, $customer_id, $conversion_action_id, $gclid, $conversion_date_time, $conversion_value) = @_; # Create a click conversion by specifying currency as USD. my $click_conversion = Google::Ads::GoogleAds::V6::Services::ConversionUploadService::ClickConversion ->new({ conversionAction => Google::Ads::GoogleAds::V6::Utils::ResourceNames::conversion_action( $customer_id, $conversion_action_id ), gclid => $gclid, conversionDateTime => $conversion_date_time, conversionValue => $conversion_value, currencyCode => "USD" }); # Issue a request to upload the click conversion. my $upload_click_conversions_response = $api_client->ConversionUploadService()->upload_click_conversions({ customerId => $customer_id, conversions => [$click_conversion], partialFailure => "true" }); # Print any partial errors returned. if ($upload_click_conversions_response->{partialFailureError}) { printf "Partial error encountered: '%s'.\n", $upload_click_conversions_response->{partialFailureError}{message}; } # Print the result if valid. my $uploaded_click_conversion = $upload_click_conversions_response->{results}[0]; if (%$uploaded_click_conversion) { printf "Uploaded conversion that occurred at '%s' from Google Click ID '%s' " . "to the conversion action with resource name '%s'.\n", $uploaded_click_conversion->{conversionDateTime}, $uploaded_click_conversion->{gclid}, $uploaded_click_conversion->{conversionAction}; } return 1; }
Import externally attributed conversions
If you use third-party tools or homegrown solutions to track conversions, then
you may want to give Google Ads only part of the credit for the conversion.
Sometimes, you may also want to distribute a conversion's credit across multiple
clicks. Externally attributed conversion
imports allow you to upload
conversions with fractional credit assigned to each GCLID
.
To upload fractional credits, you need to follow the
upload_offline_conversion code example, then specify the
external_attribution_model
and external_attribution_credit
attributes for
the ExternalAttributionData
when
creating the ClickConversion
.
Uploading ClickConversion
There are several requirements that must be met when uploading a
ClickConversion
.
To avoid a ConversionUploadError.INVALID_CONVERSION_ACTION
error, the
conversion_action
attribute must refer to a ConversionAction
where:
The
ConversionActionType
isUPLOAD_CLICKS
.The
ConversionAction
had astatus
ofENABLED
at the time of the impression.The
ConversionAction
existed in the effective conversion account of the click's Google Ads account at the time of the impression. If the account was not using cross-account conversion tracking at the time of the impression, Google Ads will look for theConversionAction
in the account used to upload conversions. You can find your account's effective conversion tracking account under TOOLS & SETTINGS > Conversions in the Google Ads UI, or theconversion_tracking_setting
attribute ofCustomer
in the Google Ads API, but keep in mind that this will show you the current effective conversion tracking account, which may differ from the effective conversion tracking account in place at the time of the impression.
In addition, the following conditions must be met:
The
conversion_date_time
must be after the impression happened, to avoid aConversionUploadError.CONVERSION_PRECEDES_GCLID
error.The
conversion_date_time
must be before theclick_through_lookback_window_days
you specified for theConversionAction
, to avoid aConversionUploadError.EXPIRED_GCLID
error.The
conversion_value
must be greater than or equal to zero.The
conversion_date_time
must have a timezone specified, and the format is asyyyy-mm-dd hh:mm:ss+|-hh:mm
, for example,2019-01-01 12:32:45-08:00
. The timezone can be for any valid value: it does not have to match the account's timezone.
Creating ClickConversion
A few things to keep in mind when creating a ClickConversion
:
The
partial_failure
attribute of theUploadClickConversionsRequest
should always be set totrue
. Follow the partial failures guidelines when handlling valid and failed operations simultaneously.Although duplicate uploads of a conversion (same GCLID, name and time) are permitted, only the first instance is recorded.
Uploaded conversions will be reflected in reports for the impression date of the original click, not the date of the upload request or the date of the
conversion_date_time
of theClickConversion
.We recommend you wait 6 hours after creating the
ConversionAction
before uploading.It takes up to 3 hours for imported conversion statistics to appear in your Google Ads account for last-click attribution. For other search attribution models, it can take longer than 3 hours.
When uploading click conversions for multiple accounts, you can specify the
customer_id
of a common manager account and include conversions with GCLIDs from across multiple accounts. A conversion is attributed to the proper account based on the origin of its GCLID.When uploading click conversions with cross-account conversion tracking enabled, the conversion action must be in the manager account, rather than in the account associated with the GCLID.