Consider these guidelines when you use [`BatchJobService`](https://developers.google.com/google-ads/api/reference/rpc/v26/BatchJobService.md.txt).

## 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](https://developers.google.com/google-ads/api/docs/batch-processing/best-practices.md.txt#atomicity-in-batch-splitting)). 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](https://developers.google.com/google-ads/api/reference/rpc/v26/CampaignOperation.md.txt) are first, followed by all of the
  [ad group operations](https://developers.google.com/google-ads/api/reference/rpc/v26/AdGroupOperation.md.txt), and finally all
  [ad group criterion operations](https://developers.google.com/google-ads/api/reference/rpc/v26/AdGroupCriterionOperation.md.txt).

- Within operations of the same type, it can improve performance to group them
  by parent resource. For example, if you have a series of
  [`AdGroupCriterionOperation`](https://developers.google.com/google-ads/api/reference/rpc/v26/AdGroupCriterionOperation.md.txt) objects, 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 [`AdGroupCriterionOperation`](https://developers.google.com/google-ads/api/reference/rpc/v26/AdGroupCriterionOperation.md.txt) operations (`create`, `update`, and `remove`) for [`LISTING_GROUP`](https://developers.google.com/google-ads/api/reference/rpc/v26/CriterionTypeEnum.CriterionType.md.txt#listing_group) criteria ([`AdGroupCriterion.listing_group`](https://developers.google.com/google-ads/api/reference/rpc/v26/AdGroupCriterion.md.txt#listing_group)) targeting the same [`AdGroup`](https://developers.google.com/google-ads/api/reference/rpc/v26/AdGroup.md.txt) (fails with [`CriterionError.LISTING_GROUP_ERROR_IN_ANOTHER_OPERATION`](https://developers.google.com/google-ads/api/reference/rpc/v26/CriterionErrorEnum.CriterionError.md.txt#listing_group_error_in_another_operation) if any operation in the group fails).
- Consecutive [`AssetGroupListingGroupFilterOperation`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetGroupListingGroupFilterOperation.md.txt) operations (`create`, `update`, and `remove`) targeting the same [`AssetGroup`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetGroup.md.txt) (fails with [`BatchJobError.ASSET_GROUP_LISTING_GROUP_FILTER_TRANSACTION_FAILURE`](https://developers.google.com/google-ads/api/reference/rpc/v26/BatchJobErrorEnum.BatchJobError.md.txt#asset_group_listing_group_filter_transaction_failure) if any operation in the group fails).
- An [`AssetGroupOperation`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetGroupOperation.md.txt) (`create`) immediately followed by up to 999 [`AssetGroupAssetOperation`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetGroupAssetOperation.md.txt) (`create`) operations targeting the same [`AssetGroup`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetGroup.md.txt) (fails with [`BatchJobError.ASSET_GROUP_AND_ASSET_GROUP_ASSET_TRANSACTION_FAILURE`](https://developers.google.com/google-ads/api/reference/rpc/v26/BatchJobErrorEnum.BatchJobError.md.txt#asset_group_and_asset_group_asset_transaction_failure) if any operation in the group fails). Each [`AssetGroupOperation`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetGroupOperation.md.txt) (`update` or `remove`) executes in its own standalone single-operation sub-batch.
- A Performance Max [`CampaignOperation`](https://developers.google.com/google-ads/api/reference/rpc/v26/CampaignOperation.md.txt) (`create`) with brand guidelines enabled ([`brand_guidelines_enabled`](https://developers.google.com/google-ads/api/reference/rpc/v26/Campaign.md.txt#brand_guidelines_enabled) set to `true` or left unset, since it defaults to `true` unless you explicitly set it to `false` or create a Performance Max for travel goals campaign) immediately followed by up to 999 [`CampaignAssetOperation`](https://developers.google.com/google-ads/api/reference/rpc/v26/CampaignAssetOperation.md.txt) (`create`) operations targeting the same [`Campaign`](https://developers.google.com/google-ads/api/reference/rpc/v26/Campaign.md.txt) (fails with [`BatchJobError.CAMPAIGN_AND_CAMPAIGN_ASSET_TRANSACTION_FAILURE`](https://developers.google.com/google-ads/api/reference/rpc/v26/BatchJobErrorEnum.BatchJobError.md.txt#campaign_and_campaign_asset_transaction_failure) if any operation in the group fails). [Local Services Performance Max](https://developers.google.com/google-ads/api/performance-max/asset-groups.md.txt#local-services-pmax) campaigns don't support brand guidelines and omit brand [`CampaignAsset`](https://developers.google.com/google-ads/api/reference/rpc/v26/CampaignAsset.md.txt) resources (set [`brand_guidelines_enabled`](https://developers.google.com/google-ads/api/reference/rpc/v26/Campaign.md.txt#brand_guidelines_enabled) to `false` when creating the campaign). Retail Performance Max campaigns (with a Merchant Center feed) can omit brand [`CampaignAsset`](https://developers.google.com/google-ads/api/reference/rpc/v26/CampaignAsset.md.txt) resources in the same atomic sub-batch only when you create an assetless campaign without custom [`AssetGroupAsset`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetGroupAsset.md.txt) resources (other than HTML5 `MEDIA_BUNDLE` assets) or when [`brand_guidelines_enabled`](https://developers.google.com/google-ads/api/reference/rpc/v26/Campaign.md.txt#brand_guidelines_enabled) is set to `false`.

For both [`AssetGroup`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetGroup.md.txt) and Performance Max
[`Campaign`](https://developers.google.com/google-ads/api/reference/rpc/v26/Campaign.md.txt) 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 `create` operation (`resource_name` on [`AssetGroup`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetGroup.md.txt) or [`Campaign`](https://developers.google.com/google-ads/api/reference/rpc/v26/Campaign.md.txt)) and its consecutive child `create` operations (`asset_group` on [`AssetGroupAsset`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetGroupAsset.md.txt) or `campaign` on [`CampaignAsset`](https://developers.google.com/google-ads/api/reference/rpc/v26/CampaignAsset.md.txt)) must specify the same negative [temporary ID](https://developers.google.com/google-ads/api/docs/batch-processing/temporary-ids.md.txt).
- Place any prerequisite [`AssetOperation`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetOperation.md.txt) (`create`) operations for new [`Asset`](https://developers.google.com/google-ads/api/reference/rpc/v26/Asset.md.txt) resources **before** the parent [`AssetGroupOperation`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetGroupOperation.md.txt) or [`CampaignOperation`](https://developers.google.com/google-ads/api/reference/rpc/v26/CampaignOperation.md.txt) (`create`), never between the parent `create` and its child link `create` operations (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`](https://developers.google.com/google-ads/api/reference/rpc/v26/BatchJobResult.md.txt#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`](https://developers.google.com/google-ads/api/reference/rpc/v26/BatchJobResult.md.txt) entries sharing the same
[`AdGroup`](https://developers.google.com/google-ads/api/reference/rpc/v26/AdGroup.md.txt), [`AssetGroup`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetGroup.md.txt), or [`Campaign`](https://developers.google.com/google-ads/api/reference/rpc/v26/Campaign.md.txt) 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](https://developers.google.com/google-ads/api/docs/batch-processing/listing-groups.md.txt) and
[Performance Max batch processing](https://developers.google.com/google-ads/api/performance-max/batch-processing.md.txt) for details.

### Logical grouping

When you modify a product targeting hierarchy
([`AssetGroupListingGroupFilterOperation`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetGroupListingGroupFilterOperation.md.txt) in Performance
Max campaigns or [`AdGroupCriterionOperation`](https://developers.google.com/google-ads/api/reference/rpc/v26/AdGroupCriterionOperation.md.txt) in
Shopping campaigns) or create a new [`AssetGroup`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetGroup.md.txt) or
Performance Max [`Campaign`](https://developers.google.com/google-ads/api/reference/rpc/v26/Campaign.md.txt), group all operations targeting the same
parent resource ([`AssetGroup`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetGroup.md.txt), [`AdGroup`](https://developers.google.com/google-ads/api/reference/rpc/v26/AdGroup.md.txt), or
[`Campaign`](https://developers.google.com/google-ads/api/reference/rpc/v26/Campaign.md.txt)) 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 you submit 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
  [`RUNNING`](https://developers.google.com/google-ads/api/reference/rpc/v26/BatchJobStatusEnum.BatchJobStatus.md.txt#running) that 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_size`](https://developers.google.com/google-ads/api/reference/rpc/v26/ListBatchJobResultsRequest.md.txt#page_size) unset (or set it to the maximum of `1000`)
  when you call [`ListBatchJobResults`](https://developers.google.com/google-ads/api/reference/rpc/v26/BatchJobService/ListBatchJobResults.md.txt) to minimize
  pagination round trips, and only set
  [`response_content_type`](https://developers.google.com/google-ads/api/reference/rpc/v26/ListBatchJobResultsRequest.md.txt#response_content_type) to
  [`MUTABLE_RESOURCE`](https://developers.google.com/google-ads/api/reference/rpc/v26/ResponseContentTypeEnum.ResponseContentType.md.txt#mutable_resource) if your application inspects the
  returned resource fields beyond `resource_name`.

- The results order is the same as the upload order.

## Additional usage guidance

- You can set an approximate upper bound for how long a batch job is allowed
  to run before being canceled. When you create a new batch job, set the
  [`metadata.execution_limit_seconds`](https://developers.google.com/google-ads/api/reference/rpc/v26/BatchJob.BatchJobMetadata.md.txt#execution_limit_seconds) field to a
  positive integer for your preferred time limit, in seconds. There is no
  default time limit if `metadata.execution_limit_seconds` is not set.

- Although the protocol limit is 10,000 operations per request, we recommend
  adding no more than 1,000 operations per
  [`AddBatchJobOperationsRequest`](https://developers.google.com/google-ads/api/reference/rpc/v26/AddBatchJobOperationsRequest.md.txt) and using the
  [`sequence_token`](https://developers.google.com/google-ads/api/reference/rpc/v26/AddBatchJobOperationsRequest.md.txt#sequence_token) to upload the rest of the operations to
  the same job. Depending on the size of the operations, sending too many
  operations in a single
  [`AddBatchJobOperationsRequest`](https://developers.google.com/google-ads/api/reference/rpc/v26/AddBatchJobOperationsRequest.md.txt) can cause a
  [`BatchJobError.REQUEST_TOO_LARGE`](https://developers.google.com/google-ads/api/reference/rpc/v26/BatchJobErrorEnum.BatchJobError.md.txt#request_too_large) error. You can handle
  this error by reducing the number of operations and retrying the
  [`AddBatchJobOperationsRequest`](https://developers.google.com/google-ads/api/reference/rpc/v26/AddBatchJobOperationsRequest.md.txt).

## Limitations

- Each [`BatchJob`](https://developers.google.com/google-ads/api/reference/rpc/v26/BatchJob.md.txt) supports up to one million operations.
  Exceeding this limit when you call
  [`AddBatchJobOperations`](https://developers.google.com/google-ads/api/reference/rpc/v26/BatchJobService/AddBatchJobOperations.md.txt) returns a
  [`ResourceCountLimitExceededError.RESOURCE_LIMIT`](https://developers.google.com/google-ads/api/reference/rpc/v26/ResourceCountLimitExceededErrorEnum.ResourceCountLimitExceededError.md.txt#resource_limit) error
  (with [`ResourceLimitType.BATCH_JOB_OPERATIONS_PER_JOB`](https://developers.google.com/google-ads/api/reference/rpc/v26/ResourceLimitTypeEnum.ResourceLimitType.md.txt#batch_job_operations_per_job) in
  [`ErrorDetails.resource_count_details`](https://developers.google.com/google-ads/api/reference/rpc/v26/ErrorDetails.md.txt#resource_count_details)).

- Each account can have up to 100 active or pending jobs at the same time.
  Exceeding this limit when you create a batch job with
  [`MutateBatchJob`](https://developers.google.com/google-ads/api/reference/rpc/v26/BatchJobService/MutateBatchJob.md.txt) returns a
  [`ResourceCountLimitExceededError.RESOURCE_LIMIT`](https://developers.google.com/google-ads/api/reference/rpc/v26/ResourceCountLimitExceededErrorEnum.ResourceCountLimitExceededError.md.txt#resource_limit) error
  (with [`ResourceLimitType.BATCH_JOBS_PER_CUSTOMER`](https://developers.google.com/google-ads/api/reference/rpc/v26/ResourceLimitTypeEnum.ResourceLimitType.md.txt#batch_jobs_per_customer)
  in [`ErrorDetails.resource_count_details`](https://developers.google.com/google-ads/api/reference/rpc/v26/ErrorDetails.md.txt#resource_count_details)).

- Pending jobs older than 7 days are automatically removed.

- Each [`AddBatchJobOperationsRequest`](https://developers.google.com/google-ads/api/reference/rpc/v26/AddBatchJobOperationsRequest.md.txt) has a
  hard limit of 10,000 mutate operations per request. Exceeding 10,000
  operations in a single request returns a
  [`BatchJobError.REQUEST_TOO_LARGE`](https://developers.google.com/google-ads/api/reference/rpc/v26/BatchJobErrorEnum.BatchJobError.md.txt#request_too_large) error.

- For the [`page_size`](https://developers.google.com/google-ads/api/reference/rpc/v26/ListBatchJobResultsRequest.md.txt#page_size) field in
  [`ListBatchJobResultsRequest`](https://developers.google.com/google-ads/api/reference/rpc/v26/ListBatchJobResultsRequest.md.txt):

  - If [`page_size`](https://developers.google.com/google-ads/api/reference/rpc/v26/ListBatchJobResultsRequest.md.txt#page_size) is not set or is `0`, it defaults to the maximum of `1000`.
  - If [`page_size`](https://developers.google.com/google-ads/api/reference/rpc/v26/ListBatchJobResultsRequest.md.txt#page_size) exceeds `1000`, or is less than `0`, the API returns a [`BatchJobError.INVALID_PAGE_SIZE`](https://developers.google.com/google-ads/api/reference/rpc/v26/BatchJobErrorEnum.BatchJobError.md.txt#invalid_page_size) error.
- Each [`AddBatchJobOperationsRequest`](https://developers.google.com/google-ads/api/reference/rpc/v26/AddBatchJobOperationsRequest.md.txt) has a
  maximum size of 41,937,920 bytes. If you exceed this limit, you receive a
  [`BatchJobError.REQUEST_TOO_LARGE`](https://developers.google.com/google-ads/api/reference/rpc/v26/BatchJobErrorEnum.BatchJobError.md.txt#request_too_large) error (or an
  [`INTERNAL_ERROR`](https://developers.google.com/google-ads/api/reference/rpc/v26/InternalErrorEnum.InternalError.md.txt#internal_error) if 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

  ```java

  static final int MAX_REQUEST_BYTES = 41_937_920;

  // ... (code to get the AddBatchJobOperationsRequest object)

  int sizeInBytes = request.getSerializedSize();
  ```

  ### C#

  ```c#

  const int MAX_REQUEST_BYTES = 41_937_920;

  // ... (code to get the AddBatchJobOperationsRequest object)

  int sizeInBytes = request.CalculateSize();
  ```

  ### PHP

  ```php

  const MAX_REQUEST_BYTES = 41937920;

  // ... (code to get the AddBatchJobOperationsRequest object)

  $size_in_bytes = $request->byteSize();
  ```

  ### Python

  ```python

  MAX_REQUEST_BYTES = 41_937_920

  # ... (code to get the AddBatchJobOperationsRequest object)

  # Supports both proto-plus (use_proto_plus=True) and native protobuf
  # (use_proto_plus=False) messages.
  pb = type(request).pb(request) if hasattr(type(request), "pb") else request
  size_in_bytes = pb.ByteSize()
  ```

  ### Ruby

  ```ruby

  MAX_REQUEST_BYTES = 41_937_920

  # ... (code to get the AddBatchJobOperationsRequest object)

  size_in_bytes = request.to_proto.bytesize
  ```

  ### Perl

  ```perl

  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`](https://developers.google.com/google-ads/api/reference/rpc/v26/MutateOperation.md.txt) 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`](https://developers.google.com/google-ads/api/reference/rpc/v26/BatchJobErrorEnum.BatchJobError.md.txt#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.