Asset optimization experiments test different asset combinations within
Performance Max campaigns, which lets you compare how different sets of assets
perform against a base set.

This workflow is supported for
[`ExperimentType.OPTIMIZE_ASSETS`](https://developers.google.com/google-ads/api/reference/rpc/v26/ExperimentTypeEnum.ExperimentType#optimize_assets).

## Setup

To set up an asset optimization experiment:

- Create a new asset and an experiment with control and treatment arms.
- Link the new asset to the treatment arm's asset group within a single mutate request.

### Prerequisites

Before creating an asset optimization experiment, you must have an existing
Performance Max campaign and a base [`AssetGroup`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetGroup) resource
(`customers/{customer_id}/assetGroups/{asset_group_id}`) that serves as the
baseline for both experiment arms. For `ADD_ASSETS_TO_ASSETLESS_RETAIL`, ensure
the base `AssetGroup` already has at least one `final_urls` set before creating
the experiment (an active asset experiment freezes edits to the base
`AssetGroup`, and linking custom assets requires `final_urls`).

### Request operation order

Because these entities are interdependent, you must use [temporary resource
names](https://developers.google.com/google-ads/api/docs/mutating/best-practices#temporary-resource-names) to refer to resources created in earlier operations
within the same request.

The operations in your request must be in the following order:

1. Create one or more [`Asset`](https://developers.google.com/google-ads/api/reference/rpc/v26/Asset) resources with temporary resource names (such as `customers/CUSTOMER_ID/assets/-1`). Include your test assets, as well as any new `BUSINESS_NAME` and `LOGO` brand assets if brand guidelines are enabled on an assetless retail campaign without existing brand links (in which case, link those brand assets to the base `Campaign` with [`CampaignAsset`](https://developers.google.com/google-ads/api/reference/rpc/v26/CampaignAsset) operations immediately after step 1).
2. Create an [`Experiment`](https://developers.google.com/google-ads/api/reference/rpc/v26/Experiment) with a temporary resource name (for example, `customers/CUSTOMER_ID/experiments/-2`), `type` set to `OPTIMIZE_ASSETS`, `status` set to `ENABLED`, and `optimize_assets_experiment.optimize_assets_experiment_subtype` set to the selected [`OptimizeAssetsExperimentSubtype`](https://developers.google.com/google-ads/api/reference/rpc/v26/OptimizeAssetsExperimentSubtypeEnum.OptimizeAssetsExperimentSubtype) (for example, `COMPARE_ASSETS`).
3. Create two [`ExperimentArm`](https://developers.google.com/google-ads/api/reference/rpc/v26/ExperimentArm) resources linked to the
   temporary experiment resource name from step 2, setting `campaigns` (to the
   Performance Max campaign resource name), `traffic_split` (summing to `100`),
   and [`asset_groups`](https://developers.google.com/google-ads/api/reference/rpc/v26/ExperimentArm#asset_groups%5B%5D) (`ExperimentArm.AssetGroupInfo`) on
   each arm:

   > [!NOTE]
   > **Note:** Although [`asset_groups`](https://developers.google.com/google-ads/api/reference/rpc/v26/ExperimentArm#asset_groups%5B%5D) (`repeated` [`ExperimentArm.AssetGroupInfo`](https://developers.google.com/google-ads/api/reference/rpc/v26/ExperimentArm.AssetGroupInfo)) is a repeated field in the protocol buffer, `OPTIMIZE_ASSETS` experiments support only one asset group per experiment. Both the control arm and the treatment arm must specify the same base `AssetGroup` resource name in `asset_group`, and an `(asset, field_type)` pair in `asset_group_assets` cannot be duplicated across both arms.

   - A control arm (`control = true`) where `asset_groups` contains an [`AssetGroupInfo`](https://developers.google.com/google-ads/api/reference/rpc/v26/ExperimentArm.AssetGroupInfo) with `asset_group` set to the resource name of the base `AssetGroup` (`customers/CUSTOMER_ID/assetGroups/ASSET_GROUP_ID`). When testing newly added assets against the baseline asset group (or when using the `ADD_ASSETS_TO_ASSETLESS_RETAIL` or `ADD_VIDEO_ASSETS_TO_VIDEOLESS` subtypes), leave `asset_group_assets` unset on the control arm; when comparing two distinct asset sets under `COMPARE_ASSETS`, list the control arm's [`AssetGroupAssetInfo`](https://developers.google.com/google-ads/api/reference/rpc/v26/ExperimentArm.AssetGroupAssetInfo) entries (`asset` and `field_type`).
   - A treatment arm (`control = false`) where `asset_groups` contains an [`AssetGroupInfo`](https://developers.google.com/google-ads/api/reference/rpc/v26/ExperimentArm.AssetGroupInfo) with `asset_group` set to the same base `AssetGroup` resource name (`customers/CUSTOMER_ID/assetGroups/ASSET_GROUP_ID`) and `asset_group_assets` (`repeated` [`AssetGroupAssetInfo`](https://developers.google.com/google-ads/api/reference/rpc/v26/ExperimentArm.AssetGroupAssetInfo)) listing the `Asset` resources and `field_type`s for the treatment arm, including the newly created test `Asset` (`customers/CUSTOMER_ID/assets/-1`) from step 1. When using `ADD_ASSETS_TO_ASSETLESS_RETAIL`, `asset_group_assets` on the treatment arm must meet all [minimum asset group requirements](https://developers.google.com/google-ads/api/performance-max/asset-requirements) (don't list optional assets such as `YOUTUBE_VIDEO` alone), and required campaign-level `BUSINESS_NAME` and `LOGO` [`CampaignAsset`](https://developers.google.com/google-ads/api/reference/rpc/v26/CampaignAsset) links must be present or created in the same request when brand guidelines are enabled on the base campaign.
4. Create consecutive [`AssetGroupAsset`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetGroupAsset) resources linking
   the test assets from step 1 (`customers/CUSTOMER_ID/assets/-1`) to the base
   `AssetGroup` used in the experiment arms.


### Java

```
This example is not yet available in Java; you can take a look at the other languages.
    
```

### C#

```
This example is not yet available in C#; you can take a look at the other languages.
    
```

### PHP

```
This example is not yet available in PHP; you can take a look at the other languages.
    
```

### Python

```python
# 1. Create Assets with temporary resource names.
# We create a text asset and an image asset to showcase different types.
asset_operation_1 = create_text_asset_operation(
    client,
    customer_id,
    ASSET_1_TEMP_ID,
    "Fly to Mars!",
)
asset_operation_2 = create_image_asset_operation(
    client,
    customer_id,
    ASSET_2_TEMP_ID,
    "https://gaagl.page.link/Eit5",
    "Mars Landscape View",
)

# 2. Create an Experiment with a temporary resource name.
experiment_operation = client.get_type("MutateOperation")
experiment = experiment_operation.experiment_operation.create
experiment.resource_name = googleads_service.experiment_path(
    customer_id, EXPERIMENT_TEMP_ID
)
experiment.name = f"Interstellar Asset Experiment #{uuid4()}"
experiment.type_ = client.enums.ExperimentTypeEnum.OPTIMIZE_ASSETS
# Set the optimize assets experiment subtype to COMPARE_ASSETS.
experiment.optimize_assets_experiment.optimize_assets_experiment_subtype = (
    client.enums.OptimizeAssetsExperimentSubtypeEnum.COMPARE_ASSETS
)

# 3. Create two ExperimentArm resources.
treatment_assets = [
    (ASSET_1_TEMP_ID, client.enums.AssetFieldTypeEnum.HEADLINE),
    (ASSET_2_TEMP_ID, client.enums.AssetFieldTypeEnum.MARKETING_IMAGE),
]
arm_operations = create_arms_operations(
    client,
    customer_id,
    EXPERIMENT_TEMP_ID,
    campaign_resource_name,
    asset_group_id,
    treatment_assets,
)

# 4. Create AssetGroupAssets linking the assets to the asset group.
asset_group_asset_operation_1 = create_asset_group_asset_operation(
    client,
    customer_id,
    asset_group_id,
    ASSET_1_TEMP_ID,
    client.enums.AssetFieldTypeEnum.HEADLINE,
)
asset_group_asset_operation_2 = create_asset_group_asset_operation(
    client,
    customer_id,
    asset_group_id,
    ASSET_2_TEMP_ID,
    client.enums.AssetFieldTypeEnum.MARKETING_IMAGE,
)

# Send all operations in a single Mutate request.
# The operations must be in this specific order.
mutate_operations = [
    asset_operation_1,
    asset_operation_2,
    experiment_operation,
    *arm_operations,
    asset_group_asset_operation_1,
    asset_group_asset_operation_2,
]

response = googleads_service.mutate(
    customer_id=customer_id,
    mutate_operations=mutate_operations,
)
      
```

### Ruby

```ruby
# 1. Create Assets with temporary resource names.
# We create a text asset and an image asset to showcase different types.
asset_operation_1 = create_text_asset_operation(
  client,
  customer_id,
  asset_1_temp_id,
  "Fly to Mars!",
)
asset_operation_2 = create_image_asset_operation(
  client,
  customer_id,
  asset_2_temp_id,
  "https://gaagl.page.link/Eit5",
  "Mars Landscape View",
)

# 2. Create an Experiment with a temporary resource name.
experiment_operation = client.operation.mutate do |m|
  m.experiment_operation = client.operation.create_resource.experiment do |e|
    e.resource_name = client.path.experiment(customer_id, experiment_temp_id)
    e.name = "Interstellar Asset Experiment #{(Time.new.to_f * 1000).to_i}"
    e.type = :OPTIMIZE_ASSETS
    # Set the optimize assets experiment subtype to COMPARE_ASSETS.
    e.optimize_assets_experiment = client.resource.optimize_assets_experiment_info do |oae|
      oae.optimize_assets_experiment_subtype = :COMPARE_ASSETS
    end
  end
end

# 3. Create two ExperimentArm resources.
treatment_assets = [
  [asset_1_temp_id, :HEADLINE],
  [asset_2_temp_id, :MARKETING_IMAGE],
]
arm_operations = create_arms_operations(
  client,
  customer_id,
  experiment_temp_id,
  campaign_resource_name,
  asset_group_id,
  treatment_assets,
)

# 4. Create AssetGroupAssets linking the assets to the asset group.
asset_group_asset_operation_1 = create_asset_group_asset_operation(
  client,
  customer_id,
  asset_group_id,
  asset_1_temp_id,
  :HEADLINE,
)
asset_group_asset_operation_2 = create_asset_group_asset_operation(
  client,
  customer_id,
  asset_group_id,
  asset_2_temp_id,
  :MARKETING_IMAGE,
)

# Send all operations in a single Mutate request.
# The operations must be in this specific order.
mutate_operations = [
  asset_operation_1,
  asset_operation_2,
  experiment_operation,
  *arm_operations,
  asset_group_asset_operation_1,
  asset_group_asset_operation_2,
]

response = client.service.google_ads.mutate(
  customer_id: customer_id,
  mutate_operations: mutate_operations,
)
      
```

### Perl

```
This example is not yet available in Perl; you can take a look at the other languages.
    
```

### curl

> [!NOTE]
> **Note:** While a direct REST code sample for this step isn't provided here, you can achieve this using a manual REST request.   
>
> Refer to the Google Ads API REST interface documentation and the method-specific reference pages. You will need to construct the JSON payload based on the proto definitions.   
>
> Key Resources:
>
> - [Using REST](https://developers.google.com/google-ads/api/rest/overview)
> - [REST Interface Structure](https://developers.google.com/google-ads/api/rest/design/overview)
> - [JSON Field Mappings](https://developers.google.com/google-ads/api/rest/design/json-mappings)
> - Consult the [REST API Reference](https://developers.google.com/google-ads/api/reference/rpc/latest/overview) for the specific service and method.

<br />

## Report on the experiment

See the [Reporting guide](https://developers.google.com/google-ads/api/docs/experiments/reporting) to query the `experiment` resource and
compare metrics between the control and treatment asset groups.

## Graduate or end

After evaluating the results, you can either end or graduate the experiment
using [`ExperimentService`](https://developers.google.com/google-ads/api/reference/rpc/v26/ExperimentService).

- **End** : If you are not satisfied with the results from the treatment arm, use [`EndExperiment`](https://developers.google.com/google-ads/api/reference/rpc/v26/ExperimentService/EndExperiment). This is a synchronous operation.
- **Graduate** : If you prefer the performance of the treatment arm's asset group, use [`GraduateExperiment`](https://developers.google.com/google-ads/api/reference/rpc/v26/ExperimentService/GraduateExperiment). As part of this process, the original base campaign associated with the control arm is paused, and the treatment arm is converted to a new, independent campaign. This is a synchronous operation.