Page Summary
-
Optimize throughput by using fewer larger jobs and ordering operations by type and parent resource.
-
Avoid concurrency issues by minimizing operations on the same objects across concurrent jobs and within a single job.
-
Retrieve results efficiently by avoiding frequent polling and limiting results per page to 1,000.
-
Batch jobs support up to one million operations, with a limit of 100 active or pending jobs per account, and requests for adding operations have size and operation count limits.
Consider these guidelines when using BatchJobService.
Improve throughput
Fewer larger jobs are preferred over many smaller jobs.
Order uploaded operations by operation type (except for interdependent operations that must be grouped consecutively in atomic sub-batches). For example, if your job contains operations to add standard campaigns, ad groups, and ad group criteria, order the operations in your upload so that all of the campaign operations are first, followed by all of the ad group operations, and finally all ad group criterion operations.
Within operations of the same type, it can improve performance to group them by parent resource. For example, if you have a series of
AdGroupCriterionOperationobjects, it is more efficient to group operations by ad group rather than intermixing operations that affect ad group criteria in different ad groups.
Atomicity in batch splitting
The Google Ads API splits the operations in a submitted batch job into smaller sub-batches for processing. While standard sub-batches execute with partial failure enabled, sub-batches for certain interdependent operations are processed atomically as a single transaction:
- Consecutive
AdGroupCriterionOperationoperations (create,update, andremove) forLISTING_GROUPcriteria (AdGroupCriterion.listing_group) targeting the sameAdGroup(fails withCriterionError.LISTING_GROUP_ERROR_IN_ANOTHER_OPERATIONif any operation in the group fails). - Consecutive
AssetGroupListingGroupFilterOperationoperations (create,update, andremove) targeting the sameAssetGroup(fails withBatchJobError.ASSET_GROUP_LISTING_GROUP_FILTER_TRANSACTION_FAILUREif any operation in the group fails). - An
AssetGroupOperation(create) immediately followed by up to 999AssetGroupAssetOperation(create) operations targeting the sameAssetGroup(fails withBatchJobError.ASSET_GROUP_AND_ASSET_GROUP_ASSET_TRANSACTION_FAILUREif any operation in the group fails). EachAssetGroupOperation(updateorremove) executes in its own standalone single-operation sub-batch. - A Performance Max
CampaignOperation(create) with Brand Guidelines enabled (brand_guidelines_enabledset totrueor left unset, since it defaults totrueunless explicitly set tofalseor creating a Performance Max for travel goals campaign) immediately followed by up to 999CampaignAssetOperation(create) operations targeting the sameCampaign(fails withBatchJobError.CAMPAIGN_AND_CAMPAIGN_ASSET_TRANSACTION_FAILUREif any operation in the group fails). Retail Performance Max campaigns (with a Merchant Center feed) can be created without linking brandCampaignAssetresources in the same atomic sub-batch.
For both AssetGroup and Performance Max
Campaign creation sub-batches (up to 1,000 operations total per
sub-batch; any child create operations beyond 999 spill into the next
non-atomic sub-batch):
- The parent
createoperation (resource_nameonAssetGrouporCampaign) and its consecutive childcreateoperations (asset_grouponAssetGroupAssetorcampaignonCampaignAsset) must specify the same negative temporary ID. - Place any prerequisite
AssetOperation(create) operations for newAssetresources before the parentAssetGroupOperationorCampaignOperation(create), never between the parentcreateand its child linkcreateoperations (which would immediately close the atomic sub-batch and split the parent resource creation from its linked assets).
When an atomic sub-batch fails, the offending operation's
BatchJobResult.status contains the underlying
validation error, while the remaining operations in that sub-batch are rolled
back with the corresponding transaction error for that sub-batch. Inspect the
adjacent BatchJobResult entries sharing the same
AdGroup, AssetGroup, or Campaign ID
to identify the root-cause error.
If related operations in any of these groups are not added consecutively, the Google Ads API splits them across separate sub-batches, causing the modification to fail minimum asset requirements or leaving listing group trees incomplete. See Use listing group filters in batch jobs and Performance Max batch processing for details.
Logical grouping
When modifying a product targeting hierarchy
(AssetGroupListingGroupFilterOperation in Performance
Max campaigns or AdGroupCriterionOperation in
Shopping campaigns) or creating a new AssetGroup or
Performance Max Campaign, group all operations targeting the same
parent resource (AssetGroup, AdGroup, or
Campaign) consecutively. This reduces backend lock contention and
keeps interdependent trees together.
Data consistency
Because listing group filter trees and Performance Max asset requirements are validated at the end of each atomic sub-batch transaction, avoid splitting updates to the same parent resource across discontinuous ranges in a job or across concurrent jobs.
Avoid concurrency issues
When submitting multiple concurrent jobs for the same account, reduce the likelihood of jobs operating on the same objects at the same time while maintaining large job sizes. Many unfinished jobs with the status of
RUNNINGthat try to mutate the same set of objects can lead to deadlock-like conditions, resulting in severe slow-down and even job failures.Don't submit multiple operations that mutate the same object in the same job, as the result can be unpredictable.
Retrieve results optimally
Don't poll the job status too frequently or you risk hitting rate limit errors.
Leave
page_sizeunset (or set it to the maximum of1000) when callingListBatchJobResultsto minimize pagination round trips, and only setresponse_content_typetoMUTABLE_RESOURCEif your application inspects the returned resource fields beyondresource_name.The results order is the same as the upload order.
Additional usage guidance
You can set an upper bound for how long a batch job is allowed to run before being canceled. When creating a new batch job, set the
metadata.execution_limit_secondsfield to your preferred time limit, in seconds. There is no default time limit ifmetadata.execution_limit_secondsis not set.Although the protocol limit is 10,000 operations per request, we recommend adding no more than 1,000 operations per
AddBatchJobOperationsRequestand using thesequence_tokento upload the rest of the operations to the same job. Depending on the size of the operations, sending too many operations in a singleAddBatchJobOperationsRequestcan cause aBatchJobError.REQUEST_TOO_LARGEerror. You can handle this error by reducing the number of operations and retrying theAddBatchJobOperationsRequest.
Limitations
Each
BatchJobsupports up to one million operations. Exceeding this limit when callingAddBatchJobOperationsreturns aResourceCountLimitExceededError.RESOURCE_LIMITerror (withResourceLimitType.BATCH_JOB_OPERATIONS_PER_JOBinErrorDetails.resource_count_details).Each account can have up to 100 active or pending jobs at the same time. Exceeding this limit when creating a batch job with
MutateBatchJobreturns aResourceCountLimitExceededError.RESOURCE_LIMITerror (withResourceLimitType.BATCH_JOBS_PER_CUSTOMERinErrorDetails.resource_count_details).Pending jobs older than 7 days are automatically removed.
Each
AddBatchJobOperationsRequesthas a hard limit of 10,000 mutate operations per request. Exceeding 10,000 operations in a single request returns aBatchJobError.REQUEST_TOO_LARGEerror.For the
page_sizefield inListBatchJobResultsRequest:- If
page_sizeis not set or is0, it defaults to the maximum of1000. - If
page_sizeexceeds1000, or is less than0, the API returns aBatchJobError.INVALID_PAGE_SIZEerror.
- If
Each
AddBatchJobOperationsRequesthas a maximum size of 41,937,920 bytes. If you exceed this limit, you receive aBatchJobError.REQUEST_TOO_LARGEerror (or anINTERNAL_ERRORif rejected at the transport layer). You can determine the serialized size of the request before submitting and take appropriate action if it is too large:Java
static final int MAX_REQUEST_BYTES = 41_937_920; // ... (code to get the AddBatchJobOperationsRequest object) int sizeInBytes = request.getSerializedSize();C#
const int MAX_REQUEST_BYTES = 41_937_920; // ... (code to get the AddBatchJobOperationsRequest object) int sizeInBytes = request.CalculateSize();PHP
const MAX_REQUEST_BYTES = 41937920; // ... (code to get the AddBatchJobOperationsRequest object) $size_in_bytes = $request->byteSize();Python
MAX_REQUEST_BYTES = 41_937_920 # ... (code to get the AddBatchJobOperationsRequest object) size_in_bytes = type(request).pb(request).ByteSize()Ruby
MAX_REQUEST_BYTES = 41_937_920 # ... (code to get the AddBatchJobOperationsRequest object) size_in_bytes = request.to_proto.bytesizePerl
use JSON::XS; use constant MAX_REQUEST_BYTES => 41937920; # ... (code to get the AddBatchJobOperationsRequest object) # The Perl client library uses REST/JSON; UTF-8 JSON byte length provides a # conservative upper-bound estimate of the serialized request size. my $json_encoder = JSON::XS->new->utf8->convert_blessed; my $size_in_bytes = length($json_encoder->encode($request));
Single mutate operation size
While the overall request can be up to 41,937,920 bytes, the serialized size of
a single MutateOperation within the batch is capped at
10,484,504 bytes (10 MiB minus 1,256 bytes). Exceeding this limit returns a
BatchJobError.REQUEST_TOO_LARGE error. Note that while
the reference documentation for BatchJobError.REQUEST_TOO_LARGE cites the
10,484,504-byte threshold, AddBatchJobOperations returns this same error code
when any of the three request thresholds (41,937,920 total request bytes,
10,484,504 single-operation bytes, or 10,000 operations per call) is exceeded,
with the error's message field specifying which limit was violated.