You can use the Google Ads API to upload offline call conversions into Google Ads, mapping to the Uploads conversion source in the Google Ads UI, followed by choosing Conversions from calls. It gives you more flexibility in associating calls with conversions.
A mobile click-to-call click cannot be uploaded as a conversion if there is no Google forwarding number attached to the call. Without a Google forwarding number, there is no way Google can be sure that the click led to a call and then to a conversion. If a click is uploaded like this, it will be ignored by the conversion action.
Code example
You need to associate your offline call conversions with a conversion action by
passing the caller ID, conversion date time, conversion action resource name and
optionally the conversion value and currency to
ConversionUploadService
:
Java
private void runExample( GoogleAdsClient googleAdsClient, long customerId, String conversionActionId, String callerId, String callStartDateTime, double conversionValue) { // Create a call conversion by specifying currency as USD. CallConversion conversion = CallConversion.newBuilder() .setConversionAction(conversionActionId) .setCallerId(callerId) .setCallStartDateTime(callStartDateTime) .setConversionValue(conversionValue) .setCurrencyCode("USD") .build(); // Uploads the call conversion to the API. try (ConversionUploadServiceClient conversionUploadServiceClient = googleAdsClient.getLatestVersion().createConversionUploadServiceClient()) { // Partial failure MUST be enabled for this request. UploadCallConversionsResponse response = conversionUploadServiceClient.uploadCallConversions( UploadCallConversionsRequest.newBuilder() .setCustomerId(String.valueOf(customerId)) .setCustomerId(Long.toString(customerId)) .addConversions(conversion) .setPartialFailure(true) .build()); // Prints any partial failure errors returned. if (response.hasPartialFailureError()) { throw new RuntimeException( "Partial failure occurred " + response.getPartialFailureError().getMessage()); } // Prints the result if valid. CallConversionResult result = response.getResults(0); System.out.printf( "Uploaded call conversion that occurred at '%' for caller ID '%' to the conversion" + " action with resource name '%'.%n", result.getCallStartDateTime(), result.getCallerId(), result.getConversionAction()); } }
C#
public void Run(GoogleAdsClient client, long customerId, string callerId, string callStartTime, string conversionTime, double conversionValue) { // Get the ConversionUploadService. ConversionUploadServiceClient conversionUploadService = client.GetService(Services.V6.ConversionUploadService); // Create a call conversion by specifying currency as USD. CallConversion callConversion = new CallConversion() { CallerId = callerId, CallStartDateTime = callStartTime, ConversionDateTime = conversionTime, ConversionValue = conversionValue, CurrencyCode = "USD" }; UploadCallConversionsRequest request = new UploadCallConversionsRequest() { CustomerId = customerId.ToString(), Conversions = { callConversion }, PartialFailure = true }; try { // Issues a request to upload the call conversion. The partialFailure parameter // is set to true, and validateOnly parameter to false as required by this method // call. UploadCallConversionsResponse response = conversionUploadService.UploadCallConversions(request); // Prints the result. CallConversionResult uploadedCallConversion = response.Results[0]; Console.WriteLine($"Uploaded call conversion that occurred at " + $"'{uploadedCallConversion.CallStartDateTime}' for caller ID " + $"'{uploadedCallConversion.CallerId}' to the conversion action with " + $"resource name '{uploadedCallConversion.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 $callerId, string $callStartDateTime, string $conversionDateTime, float $conversionValue ) { // Creates a call conversion by specifying currency as USD. $callConversion = new CallConversion([ 'conversion_action' => ResourceNames::forConversionAction($customerId, $conversionActionId), 'caller_id' => $callerId, 'call_start_date_time' => $callStartDateTime, 'conversion_date_time' => $conversionDateTime, 'conversion_value' => $conversionValue, 'currency_code' => 'USD', ]); // Issues a request to upload the call conversion. $conversionUploadServiceClient = $googleAdsClient->getConversionUploadServiceClient(); $response = $conversionUploadServiceClient->uploadCallConversions( $customerId, [$callConversion], 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 CallConversionResult $uploadedCallConversion */ $uploadedCallConversion = $response->getResults()[0]; printf( "Uploaded call conversion that occurred at '%s' for caller ID '%s' to the " . "conversion action with resource name '%s'.%s", $uploadedCallConversion->getCallStartDateTime(), $uploadedCallConversion->getCallerId(), $uploadedCallConversion->getConversionAction(), PHP_EOL ); } }
Python
def main( client, customer_id, conversion_action_id, caller_id, call_start_date_time, conversion_date_time, conversion_value, ): """Imports offline call conversion values for calls related to your ads. Args: client: An initialized GoogleAdsClient instance. customer_id: The client customer ID string. conversion_action_id: The ID of the conversion action to upload to. caller_id: The caller ID from which this call was placed. Caller ID is expected to be in E.164 format with preceding '+' sign, e.g. '+16502531234'. call_start_date_time: The date and time at which the call occurred. The format is 'yyyy-mm-dd hh:mm:ss+|-hh:mm', e.g. '2019-01-01 12:32:45-08:00'. conversion_date_time: The the date and time of the conversion (should be after the click time). The format is 'yyyy-mm-dd hh:mm:ss+|-hh:mm', e.g. '2019-01-01 12:32:45-08:00'. conversion_value: The conversion value in the desired currency. """ # Get the ConversionUploadService client. conversion_upload_service = client.get_service( "ConversionUploadService", version="v6" ) # Create a call conversion in USD currency. call_conversion = client.get_type("CallConversion", version="v6") call_conversion.conversion_action = client.get_service( "ConversionActionService", version="v6" ).conversion_action_path(customer_id, conversion_action_id) call_conversion.caller_id = caller_id call_conversion.call_start_date_time = call_start_date_time call_conversion.conversion_date_time = conversion_date_time call_conversion.conversion_value = conversion_value call_conversion.currency_code = "USD" try: # Issue a request to upload the call conversion. upload_call_conversions_response = conversion_upload_service.upload_call_conversions( customer_id, [call_conversion], partial_failure=True ) # Print any partial errors returned. if upload_call_conversions_response.partial_failure_error: print( "Partial error ocurred: " f"'{upload_call_conversions_response.partial_failure_error.message}'" ) # Print the result if valid. uploaded_call_conversion = upload_call_conversions_response.results[0] if uploaded_call_conversion.call_start_date_time: print( "Uploaded call conversion that occurred at " f"'{uploaded_call_conversion.call_start_date_time}' " f"for caller ID '{uploaded_call_conversion.caller_id}' " "to the conversion action with resource name " f"'{uploaded_call_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_call_conversion(customer_id, conversion_action_id, caller_id, call_start_date_time, 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 # Create a call conversion by specifying currency as USD. call_conversion = client.resource.call_conversion do |c| c.conversion_action = client.path.conversion_action( customer_id, conversion_action_id) c.caller_id = caller_id c.call_start_date_time = call_start_date_time c.conversion_date_time = conversion_date_time c.conversion_value = conversion_value c.currency_code = "USD" end # Issues a request to upload the call conversion. response = client.service.conversion_upload.upload_call_conversions( customer_id: customer_id, conversions: [call_conversion], partial_failure: true ) # Prints errors if any partial failure error is returned. if response.partial_failure_error failures = client.decode_partial_failure_error(response.partial_failure_error) failures.each do |failure| failure.errors.each do |error| human_readable_error_path = error .location .field_path_elements .map { |location_info| if location_info.index "#{location_info.field_name}[#{location_info.index}]" else "#{location_info.field_name}" end }.join(" > ") errmsg = "error occured while adding operations " \ "#{human_readable_error_path}" \ " with value: #{error.trigger.string_value}" \ " because #{error.message.downcase}" puts errmsg end end else # Print the result if valid. uploaded_call_conversion = response.results.first puts "Uploaded call conversion that occurred at " \ "#{uploaded_call_conversion.call_start_date_time} " \ "for caller ID " \ "#{uploaded_call_conversion.caller_id} " \ "to the conversion action with resource name " \ "#{uploaded_call_conversion.conversion_action}" end end
Perl
sub upload_call_conversion { my ($api_client, $customer_id, $conversion_action_id, $caller_id, $call_start_date_time, $conversion_date_time, $conversion_value) = @_; # Create a call conversion by specifying currency as USD. my $call_conversion = Google::Ads::GoogleAds::V6::Services::ConversionUploadService::CallConversion ->new({ conversionAction => Google::Ads::GoogleAds::V6::Utils::ResourceNames::conversion_action( $customer_id, $conversion_action_id ), callerId => $caller_id, callStartDateTime => $call_start_date_time, conversionDateTime => $conversion_date_time, conversionValue => $conversion_value, currencyCode => "USD" }); # Issue a request to upload the call conversion. my $upload_call_conversions_response = $api_client->ConversionUploadService()->upload_call_conversions({ customerId => $customer_id, conversions => [$call_conversion], partialFailure => "true" }); # Print any partial errors returned. if ($upload_call_conversions_response->{partialFailureError}) { printf "Partial error encountered: '%s'.\n", $upload_call_conversions_response->{partialFailureError}{message}; } # Print the result if valid. my $uploaded_call_conversion = $upload_call_conversions_response->{results}[0]; if (%$uploaded_call_conversion) { printf "Uploaded call conversion that occurred at '%s' " . "for caller ID '%s' to the conversion action with resource name '%s'.\n", $uploaded_call_conversion->{callStartDateTime}, $uploaded_call_conversion->{callerId}, $uploaded_call_conversion->{conversionAction}; } return 1; }
Uploading CallConversion
There are several requirements that must be met when uploading a
CallConversion
.
To avoid a ConversionUploadError.INVALID_CONVERSION_ACTION
error, the
conversion_action
attribute
must refer to a ConversionAction
where:
- The
ConversionActionType
isUPLOAD_CALLS
. - The
status
of theConversionAction
isENABLED
. - The
ConversionAction
exists in the effective conversion account of the click's Google Ads account. - At the time of the call, conversion tracking was enabled in the effective conversion account of the call's Google Ads account.
In addition, the following conditions must be met:
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 CallConversion
A few things to keep in mind when creating a CallConversion
:
The
partial_failure
attribute of theUploadCallConversionsRequest
should always be set totrue
. Follow the partial failures guidelines when handling valid and failed operations simultaneously.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.
Although duplicate uploads of a conversion (same caller ID, name, and time) are permitted, only the first instance is recorded.