Usage flow Stay organized with collections Save and categorize content based on your preferences.
The steps for using batch processing are as follows:
Create a new batch job
To create aBatchJob
resource, callMutateBatchJob
.
Java
privateStringcreateBatchJob(BatchJobServiceClientbatchJobServiceClient,longcustomerId){BatchJobOperationoperation=BatchJobOperation.newBuilder().setCreate(BatchJob.newBuilder().build()).build();StringbatchJobResourceName=batchJobServiceClient.mutateBatchJob(Long.toString(customerId),operation).getResult().getResourceName();System.out.printf("Created a mutate job with resource name: '%s'.%n",batchJobResourceName);returnbatchJobResourceName;}
C#
privatestaticstringCreateBatchJob(BatchJobServiceClientbatchJobService,longcustomerId){BatchJobOperationoperation=newBatchJobOperation(){Create=newBatchJob(){}};stringbatchJobResourceName=batchJobService.MutateBatchJob(customerId.ToString(),operation).Result.ResourceName;Console.WriteLine($"Created a batch job with resource name: "+$"'{batchJobResourceName}'.");returnbatchJobResourceName;}
PHP
private static function createBatchJob( BatchJobServiceClient $batchJobServiceClient, int $customerId): string { // Creates a batch job operation to create a new batch job. $batchJobOperation = new BatchJobOperation(); $batchJobOperation->setCreate(new BatchJob()); // Issues a request to the API and get the batch job's resource name. $batchJobResourceName = $batchJobServiceClient->mutateBatchJob( MutateBatchJobRequest::build($customerId, $batchJobOperation) )->getResult()->getResourceName(); printf( "Created a batch job with resource name: '%s'.%s", $batchJobResourceName, PHP_EOL ); return $batchJobResourceName;}
Python
defcreate_batch_job(batch_job_service,customer_id,batch_job_operation):"""Creates a batch job for the specified customer ID. Args: batch_job_service: an instance of the BatchJobService message class. customer_id: a str of a customer ID. batch_job_operation: a BatchJobOperation instance set to "create" Returns: a str of a resource name for a batch job. """try:response=batch_job_service.mutate_batch_job(customer_id=customer_id,operation=batch_job_operation)resource_name=response.result.resource_nameprint(f'Created a batch job with resource name "{resource_name}"')returnresource_nameexceptGoogleAdsExceptionasexception:handle_googleads_exception(exception)
Ruby
defcreate_batch_job(client,batch_job_service,customer_id)# Creates a batch job operation to create a new batch job.operation=client.operation.create_resource.batch_job# Issues a request to the API and get the batch job's resource name.response=batch_job_service.mutate_batch_job(customer_id:customer_id,operation:operation)batch_job_resource_name=response.result.resource_nameputs"Created a batch job with resource name: '#{batch_job_resource_name}'"batch_job_resource_nameend
Perl
subcreate_batch_job{my($batch_job_service,$customer_id)=@_;# Create a batch job operation.my$batch_job_operation=Google::Ads::GoogleAds::V20::Services::BatchJobService::BatchJobOperation->new({create=>Google::Ads::GoogleAds::V20::Resources::BatchJob->new({})});my$batch_job_resource_name=$batch_job_service->mutate({customerId=>$customer_id,operation=>$batch_job_operation})->{result}{resourceName};printf"Created a batch job with resource name: '%s'.\n",$batch_job_resource_name;return$batch_job_resource_name;}
curl
#Createsabatchjob.##Variables:#API_VERSION,#CUSTOMER_ID,#DEVELOPER_TOKEN,#MANAGER_CUSTOMER_ID,#OAUTH2_ACCESS_TOKEN:#Seehttps://developers.google.com/google-ads/api/rest/auth#request_headers#fordetails.curl -f --request POST \"https://googleads.googleapis.com/v${API_VERSION}/customers/${CUSTOMER_ID}/batchJobs:mutate" \--header "Content-Type: application/json" \--header "developer-token: ${DEVELOPER_TOKEN}" \--header "login-customer-id: ${MANAGER_CUSTOMER_ID}" \--header "Authorization: Bearer ${OAUTH2_ACCESS_TOKEN}" \--data @- <<EOF{ "operation": { "create": {} }}EOF
At this point in the process, thestatus
ofthe job isPENDING
.
Add one or more mutate operations to the batch job
Add one or moreMutateOperation
to the batchjob created in the previous step by callingAddBatchJobOperations
.Theresponse then contains thefollowing:
- Total number of operations added so far for this job
- Sequence token to be used when calling this method to add more operations
When you callAddBatchJobOperations
again to add more operations, ensure you specify the previously obtainedsequence token in thesequence_token
field of arequest. If you callthe method using any sequence token other than the previously obtained one, itresults in an error.
sequence_token
is also available asnext_add_sequence_token
ofBatchJob
, which you canretrieve later.
If you're creating dependent objects such as a complete campaign consisting ofa new campaign and corresponding ad groups, ads, and keywords, you canusetemporary IDs to specify aresource name.
Java
privatevoidaddAllBatchJobOperations(BatchJobServiceClientbatchJobServiceClient,longcustomerId,StringbatchJobResourceName){AddBatchJobOperationsResponseresponse=batchJobServiceClient.addBatchJobOperations(AddBatchJobOperationsRequest.newBuilder().setResourceName(batchJobResourceName).addAllMutateOperations(buildAllOperations(customerId)).build());System.out.printf("%d mutate operations have been added so far.%n",response.getTotalOperations());// You can use this next sequence token for calling addBatchJobOperations() next time.System.out.printf("Next sequence token for adding next operations is '%s'.%n",response.getNextSequenceToken());}
C#
privatestaticvoidAddAllBatchJobOperations(BatchJobServiceClientbatchJobService,longcustomerId,stringbatchJobResourceName){AddBatchJobOperationsResponseresponse=batchJobService.AddBatchJobOperations(newAddBatchJobOperationsRequest(){ResourceName=batchJobResourceName,MutateOperations={BuildAllOperations(customerId)}});Console.WriteLine($"{response.TotalOperations} mutate operations have been added"+$" so far.");// You can use this next sequence token for calling AddBatchJobOperations() next time.Console.WriteLine($"Next sequence token for adding next operations is "+$"'{response.NextSequenceToken}'.");}
PHP
private static function addAllBatchJobOperations( BatchJobServiceClient $batchJobServiceClient, int $customerId, string $batchJobResourceName): void { $response = $batchJobServiceClient->addBatchJobOperations( AddBatchJobOperationsRequest::build( $batchJobResourceName, '', self::buildAllOperations($customerId) ) ); printf( "%d mutate operations have been added so far.%s", $response->getTotalOperations(), PHP_EOL ); // You can use this next sequence token for calling addBatchJobOperations() next time. printf( "Next sequence token for adding next operations is '%s'.%s", $response->getNextSequenceToken(), PHP_EOL );}
Python
defadd_all_batch_job_operations(batch_job_service,operations,resource_name):"""Adds all mutate operations to the batch job. As this is the first time for this batch job, we pass null as a sequence token. The response will contain the next sequence token that we can use to upload more operations in the future. Args: batch_job_service: an instance of the BatchJobService message class. operations: a list of a mutate operations. resource_name: a str of a resource name for a batch job. """try:response=batch_job_service.add_batch_job_operations(resource_name=resource_name,sequence_token=None,mutate_operations=operations,)print(f"{response.total_operations} mutate operations have been ""added so far.")# You can use this next sequence token for calling# add_batch_job_operations() next time.print("Next sequence token for adding next operations is "f"{response.next_sequence_token}")exceptGoogleAdsExceptionasexception:handle_googleads_exception(exception)
Ruby
defadd_all_batch_job_operations(client,batch_job_service,customer_id,batch_job_resource_name)response=batch_job_service.add_batch_job_operations(resource_name:batch_job_resource_name,mutate_operations:build_all_operations(client,customer_id),)puts"#{response.total_operations} mutate operations have been added so far."# You can use this next sequence token for calling# add_all_batch_job_operations() next timeputs"Next sequence token for adding next operations is "\"'#{response.next_sequence_token}'"end
Perl
subadd_all_batch_job_operations{my($batch_job_service,$customer_id,$batch_job_resource_name)=@_;my$add_batch_job_operations_response=$batch_job_service->add_operations({resourceName=>$batch_job_resource_name,sequenceToken=>undef,mutateOperations=>build_all_operations($customer_id)});printf"%d batch operations have been added so far.\n",$add_batch_job_operations_response->{totalOperations};# You can use this next sequence token for calling add_operations() next time.printf"Next sequence token for adding next operations is '%s'.\n",$add_batch_job_operations_response->{nextSequenceToken};}
curl
#Addsoperationstoabatchjob.##Variables:#API_VERSION,#CUSTOMER_ID,#DEVELOPER_TOKEN,#MANAGER_CUSTOMER_ID,#OAUTH2_ACCESS_TOKEN:#Seehttps://developers.google.com/google-ads/api/rest/auth#request_headers#fordetails.#BATCH_JOB_RESOURCE_NAME:#Theresourcenameofthebatchjobtowhichtheoperationsshouldbeadded#asreturnedbythepreviousstep.curl -f --request POST \"https://googleads.googleapis.com/v${API_VERSION}/${BATCH_JOB_RESOURCE_NAME}:addOperations" \--header "Content-Type: application/json" \--header "developer-token: ${DEVELOPER_TOKEN}" \--header "login-customer-id: ${MANAGER_CUSTOMER_ID}" \--header "Authorization: Bearer ${OAUTH2_ACCESS_TOKEN}" \--data @- <<EOF{ "mutateOperations": [ { "campaignBudgetOperation": { "create": { "resourceName": "customers/${CUSTOMER_ID}/campaignBudgets/-1", "name": "batch job budget #${RANDOM}", "deliveryMethod": "STANDARD", "amountMicros": 5000000 } } }, { "campaignOperation": { "create": { "advertisingChannelType": "SEARCH", "status": "PAUSED", "name": "batch job campaign #${RANDOM}", "campaignBudget": "customers/${CUSTOMER_ID}/campaignBudgets/-1", "resourceName": "customers/${CUSTOMER_ID}/campaigns/-2", "manualCpc": { } } }, } ]}EOF
Click to see the content of the build operations function in GitHub for yourclient library:
Java
buildAllOperations()
C#
BuildAllOperations()
PHP
buildAllOperations()
Python
build_all_operations()
Ruby
build_all_operations()
Perl
build_all_operations
Run the batch job
After adding all your operations, you can request the Google Ads API to run the batchjob by callingRunBatchJob
on theuploaded operations.
Java
privateOperationFuturerunBatchJob(BatchJobServiceClientbatchJobServiceClient,StringbatchJobResourceName){OperationFutureoperationResponse=batchJobServiceClient.runBatchJobAsync(batchJobResourceName);// BEWARE! The above call returns an OperationFuture. The execution of that future depends on// the thread pool which is owned by batchJobServiceClient. If you use this future, you *must*// keep the service client in scope too.// See https://developers.google.com/google-ads/api/docs/client-libs/java/lro for more detail.System.out.printf("Mutate job with resource name '%s' has been executed.%n",batchJobResourceName);returnoperationResponse;}
C#
privateOperation<Empty,BatchJobMetadata>RunBatchJob(BatchJobServiceClientbatchJobService,stringbatchJobResourceName){Operation<Empty,BatchJobMetadata>operationResponse=batchJobService.RunBatchJob(batchJobResourceName);Console.WriteLine($"Batch job with resource name '{batchJobResourceName}' has been "+$"executed.");returnoperationResponse;}
PHP
private static function runBatchJob( BatchJobServiceClient $batchJobServiceClient, string $batchJobResourceName): OperationResponse { $operationResponse = $batchJobServiceClient->runBatchJob(RunBatchJobRequest::build($batchJobResourceName)); printf( "Batch job with resource name '%s' has been executed.%s", $batchJobResourceName, PHP_EOL ); return $operationResponse;}
Python
defrun_batch_job(batch_job_service,resource_name):"""Runs the batch job for executing all uploaded mutate operations. Args: batch_job_service: an instance of the BatchJobService message class. resource_name: a str of a resource name for a batch job. Returns: a google.api_core.operation.Operation instance. """try:response=batch_job_service.run_batch_job(resource_name=resource_name)print(f'Batch job with resource name "{resource_name}" has been '"executed.")returnresponseexceptGoogleAdsExceptionasexception:handle_googleads_exception(exception)
Ruby
defrun_batch_job(batch_job_service,batch_job_resource_name)operation_response=batch_job_service.run_batch_job(resource_name:batch_job_resource_name,)puts"Batch job with resource name '#{batch_job_resource_name}' "\"has been executed."operation_responseend
Perl
subrun_batch_job{my($batch_job_service,$batch_job_resource_name)=@_;my$batch_job_lro=$batch_job_service->run({resourceName=>$batch_job_resource_name});printf"Batch job with resource name '%s' has been executed.\n",$batch_job_resource_name;return$batch_job_lro;}
curl
#Runsabatchjob.##Variables:#API_VERSION,#CUSTOMER_ID,#DEVELOPER_TOKEN,#MANAGER_CUSTOMER_ID,#OAUTH2_ACCESS_TOKEN:#Seehttps://developers.google.com/google-ads/api/rest/auth#request_headers#fordetails.#BATCH_JOB_RESOURCE_NAME:#Theresourcenameofthebatchjobtorunasreturnedbythepreviousstep.curl -f --request POST \"https://googleads.googleapis.com/v19/${BATCH_JOB_RESOURCE_NAME}:run" \--header "Content-Type: application/json" \--header "developer-token: ${DEVELOPER_TOKEN}" \--header "login-customer-id: ${MANAGER_CUSTOMER_ID}" \--header "Authorization: Bearer ${OAUTH2_ACCESS_TOKEN}" \--data @- <<EOF{}EOF
The returned response is an object of along-runningOperation
(LRO). The LRO contains the metadata of your batchjob along with the information about the job status.
Poll the status of the batch job until it's done
The next step is to poll the status of the batch job using the LRO'sGetOperation
until the LRO'sdone
value istrue
.
Java
privatevoidpollBatchJob(OperationFutureoperationResponse){try{operationResponse.get(MAX_TOTAL_POLL_INTERVAL_SECONDS,TimeUnit.SECONDS);}catch(InterruptedException|ExecutionException|TimeoutExceptione){System.err.printf("Failed polling the mutate job. Exception: %s%n",e);System.exit(1);}}
C#
privatestaticvoidPollBatchJob(Operation<Empty,BatchJobMetadata>operationResponse){PollSettingspollSettings=newPollSettings(Expiration.FromTimeout(TimeSpan.FromSeconds(MAX_TOTAL_POLL_INTERVAL_SECONDS)),TimeSpan.FromSeconds(1));operationResponse.PollUntilCompleted(pollSettings);}
PHP
private static function pollBatchJob(OperationResponse $operationResponse): void{ $operationResponse->pollUntilComplete([ 'initialPollDelayMillis' => self::POLL_FREQUENCY_SECONDS * 1000, 'totalPollTimeoutMillis' => self::MAX_TOTAL_POLL_INTERVAL_SECONDS * 1000 ]);}
Python
defpoll_batch_job(operations_response,event):"""Polls the server until the batch job execution finishes. Sets the initial poll delay time and the total time to wait before time-out. Args: operations_response: a google.api_core.operation.Operation instance. event: an instance of asyncio.Event to invoke once the operations have completed, alerting the awaiting calling code that it can proceed. """loop=asyncio.get_event_loop()defdone_callback(future):# The operations_response object will call callbacks from a daemon# thread so we must use a threadsafe method of setting the event here# otherwise it will not trigger the awaiting code.loop.call_soon_threadsafe(event.set)# operations_response represents a Long-Running Operation or LRO. The class# provides an interface for polling the API to check when the operation is# complete. Below we use the asynchronous interface, but there's also a# synchronous interface that uses the Operation.result method.# See: https://googleapis.dev/python/google-api-core/latest/operation.htmloperations_response.add_done_callback(done_callback)
Ruby
defpoll_batch_job(operation_response)operation_response.wait_until_done!end
Perl
subpoll_batch_job{my($operation_service,$batch_job_lro)=@_;$operation_service->poll_until_done({name=>$batch_job_lro->{name},pollFrequencySeconds=>POLL_FREQUENCY_SECONDS,pollTimeoutSeconds=>POLL_TIMEOUT_SECONDS});}
curl
#Getsthestatusofabatchjob.##Variables:#API_VERSION,#CUSTOMER_ID,#DEVELOPER_TOKEN,#MANAGER_CUSTOMER_ID,#OAUTH2_ACCESS_TOKEN:#Seehttps://developers.google.com/google-ads/api/rest/auth#request_headers#fordetails.#BATCH_JOB_OPERATION_NAME:#Theoperationnameoftherunningbatchjobasreturnedbytheprevious#step.curl -f --request GET \"https://googleads.googleapis.com/v${API_VERSION}/${BATCH_JOB_OPERATION_NAME}" \--header "Content-Type: application/json" \--header "developer-token: ${DEVELOPER_TOKEN}" \--header "login-customer-id: ${MANAGER_CUSTOMER_ID}" \--header "Authorization: Bearer ${OAUTH2_ACCESS_TOKEN}" \
List all batch job results
When all of your batch jobs finish, useListBatchJobResults
tolist their results, and print their statuses and responses:
Java
privatevoidfetchAndPrintResults(BatchJobServiceClientbatchJobServiceClient,StringbatchJobResourceName){System.out.printf("Mutate job with resource name '%s' has finished. Now, printing its results...%n",batchJobResourceName);// Gets all the results from running mutate job and prints their information.ListBatchJobResultsPagedResponsebatchJobResults=batchJobServiceClient.listBatchJobResults(ListBatchJobResultsRequest.newBuilder().setResourceName(batchJobResourceName).setPageSize(PAGE_SIZE).build());for(BatchJobResultbatchJobResult:batchJobResults.iterateAll()){System.out.printf("Mutate job #%d has a status '%s' and response of type '%s'.%n",batchJobResult.getOperationIndex(),batchJobResult.getStatus().getMessage().isEmpty()?"N/A":batchJobResult.getStatus().getMessage(),batchJobResult.getMutateOperationResponse().getResponseCase().equals(ResponseCase.RESPONSE_NOT_SET)?"N/A":batchJobResult.getMutateOperationResponse().getResponseCase());}}
C#
privatestaticvoidFetchAndPrintResults(BatchJobServiceClientbatchJobService,stringbatchJobResourceName){Console.WriteLine($"batch job with resource name '{batchJobResourceName}' has "+$"finished. Now, printing its results...");ListBatchJobResultsRequestrequest=newListBatchJobResultsRequest(){ResourceName=batchJobResourceName,PageSize=PAGE_SIZE,};ListBatchJobResultsResponseresp=newListBatchJobResultsResponse();// Gets all the results from running batch job and prints their information.foreach(BatchJobResultbatchJobResultinbatchJobService.ListBatchJobResults(request)){if(!batchJobResult.IsFailed){Console.WriteLine($"batch job result #{batchJobResult.OperationIndex} is "+$"successful and response is of type "+$"'{batchJobResult.MutateOperationResponse.ResponseCase}'.");}else{Console.WriteLine($"batch job result #{batchJobResult.OperationIndex} "+$"failed with error message {batchJobResult.Status.Message}.");foreach(GoogleAdsErrorerrorinbatchJobResult.Failure.Errors){Console.WriteLine($"Error found: {error}.");}}}}
PHP
private static function fetchAndPrintResults( BatchJobServiceClient $batchJobServiceClient, string $batchJobResourceName): void { printf( "Batch job with resource name '%s' has finished. Now, printing its results...%s", $batchJobResourceName, PHP_EOL ); // Gets all the results from running batch job and print their information. $batchJobResults = $batchJobServiceClient->listBatchJobResults( ListBatchJobResultsRequest::build($batchJobResourceName)->setPageSize(self::PAGE_SIZE) ); foreach ($batchJobResults->iterateAllElements() as $batchJobResult) { /** @var BatchJobResult $batchJobResult */ printf( "Batch job #%d has a status '%s' and response of type '%s'.%s", $batchJobResult->getOperationIndex(), $batchJobResult->getStatus() ? $batchJobResult->getStatus()->getMessage() : 'N/A', $batchJobResult->getMutateOperationResponse() ? $batchJobResult->getMutateOperationResponse()->getResponse() : 'N/A', PHP_EOL ); }}
Python
deffetch_and_print_results(client,batch_job_service,resource_name):"""Prints all the results from running the batch job. Args: client: an initialized GoogleAdsClient instance. batch_job_service: an instance of the BatchJobService message class. resource_name: a str of a resource name for a batch job. """print(f'Batch job with resource name "{resource_name}" has finished. '"Now, printing its results...")list_results_request=client.get_type("ListBatchJobResultsRequest")list_results_request.resource_name=resource_namelist_results_request.page_size=1000# Gets all the results from running batch job and prints their information.batch_job_results=batch_job_service.list_batch_job_results(request=list_results_request)forbatch_job_resultinbatch_job_results:status=batch_job_result.status.messagestatus=statusifstatuselse"N/A"result=batch_job_result.mutate_operation_responseresult=resultor"N/A"print(f"Batch job #{batch_job_result.operation_index} "f'has a status "{status}" and response type "{result}"')
Ruby
deffetch_and_print_results(batch_job_service,batch_job_resource_name)puts"Batch job with resource name '#{batch_job_resource_name}' has "\"finished. Now, printing its results..."\# Gets all the results from running batch job and print their information.batch_job_results=batch_job_service.list_batch_job_results(resource_name:batch_job_resource_name,page_size:PAGE_SIZE,)batch_job_results.eachdo|result|puts"Batch job ##{result.operation_index} has a status "\"#{result.status?result.status.message:'N/A'} and response of type "\"#{result.mutate_operation_response?result.mutate_operation_response.response:'N/A'}"endend
Perl
subfetch_and_print_results{my($batch_job_service,$batch_job_resource_name)=@_;printf"Batch job with resource name '%s' has finished. "."Now, printing its results...\n",$batch_job_resource_name;# Get all the results from running batch job and print their information.my$list_batch_job_results_response=$batch_job_service->list_results({resourceName=>$batch_job_resource_name,pageSize=>PAGE_SIZE});foreachmy$batch_job_result(@{$list_batch_job_results_response->{results}}){printf"Batch job #%d has a status '%s' and response of type '%s'.\n",$batch_job_result->{operationIndex},$batch_job_result->{status}?$batch_job_result->{status}{message}:"N/A",$batch_job_result->{mutateOperationResponse}?[keys%{$batch_job_result->{mutateOperationResponse}}]->[0]:"N/A";}}
curl
#Getstheresultsofabatchjob.##Variables:#API_VERSION,#CUSTOMER_ID,#DEVELOPER_TOKEN,#MANAGER_CUSTOMER_ID,#OAUTH2_ACCESS_TOKEN:#Seehttps://developers.google.com/google-ads/api/rest/auth#request_headers#fordetails.#BATCH_JOB_RESOURCE_NAME:#Theoperationnameoftherunningbatchjobasreturnedbytheprevious#step.curl -f --request GET \"https://googleads.googleapis.com/v${API_VERSION}/${BATCH_JOB_RESOURCE_NAME}:listResults?pageSize=1000" \--header "Content-Type: application/json" \--header "developer-token: ${DEVELOPER_TOKEN}" \--header "login-customer-id: ${MANAGER_CUSTOMER_ID}" \--header "Authorization: Bearer ${OAUTH2_ACCESS_TOKEN}"
If the corresponding operation was successful, theresponse
of themutate_operation_response
contains the result with itsresource_name
. In addition, the resource of theresult contains the modified resource with all of its mutable fields populatedifresponse_content_type
is set toMUTABLE_RESOURCE
.
If the corresponding operation produced errors and can't be completed, themutate_operation_response
field isnull
.
Thestatus
field ofBatchJobResult
contains error details foreach failed operation.
ListBatchJobResults
before callingRunBatchJob
,an error is returned since no operations would have been processed.Cancel a batch job
If necessary, you can attempt to cancel a batch job. Seecustomers.operations.cancel
.
Error handling
BatchJobService
automatically retries operations that fail due to transienterrors. However, not all failure scenarios can be avoided. Operations thatfailed due to validation errors can be fixed and resubmitted in a newbatch job. Operations that were cancelled can be retried by adding them to a newbatch job.
Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2025-07-17 UTC.