Performance Max campaigns have some unique characteristics regarding
[assets](https://support.google.com/google-ads/answer/7331111).

- Asset groups must meet [minimum asset requirements](https://developers.google.com/google-ads/api/performance-max/asset-requirements.md.txt) across asset types, with exceptions for [retail](https://developers.google.com/google-ads/api/performance-max/asset-groups.md.txt#link-asset-groups-to-assets-in-performance-max-retail-campaigns) and [Local Services](https://developers.google.com/google-ads/api/performance-max/asset-groups.md.txt#local-services-pmax) campaigns.
- [Assets](https://developers.google.com/google-ads/api/docs/assets/overview.md.txt) are grouped in an [`AssetGroup`](https://developers.google.com/google-ads/api/performance-max/asset-groups.md.txt), which is unique to Performance Max campaigns.
- Machine learning can generate additional assets automatically.

> [!TIP]
> **Tip:** If you are upgrading to Performance Max campaigns from other campaign types, you can reuse your existing assets in the Google Ads account. Refer to the [upgrade guide](https://developers.google.com/google-ads/api/performance-max/upgrade-enhancements.md.txt#add-additional-assets) for details on the additional assets to add.

## Brand guidelines: business name and logo linkage

While most assets in a Performance Max campaign are organized within asset
groups, key assets representing your brand's identity---specifically
**Business Name** and **Business Logo**---are handled differently if brand
guidelines are enabled for your campaign.

These brand guideline assets are linked directly at the campaign level, not at
the Asset Group level. This is done using the [`CampaignAsset`](https://developers.google.com/google-ads/api/reference/rpc/v26/CampaignAsset.md.txt) resource. You
link the asset to the campaign, specifying the appropriate
[`AssetFieldType`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetFieldTypeEnum.AssetFieldType.md.txt):

- `BUSINESS_NAME` for the Business Name asset (which is a Text Asset).
- `LOGO` for the Business Logo asset (which is an Image Asset).

This campaign-level linkage ensures consistent brand representation across all
asset groups within the Performance Max campaign.

## Code example

The following code snippet illustrates creating the necessary repeated assets in
a new request:


### Java

```java
/** Creates multiple text assets and returns the list of resource names. */
private List<String> createMultipleTextAssets(
    GoogleAdsClient googleAdsClient, long customerId, List<String> texts) {
  List<MutateOperation> mutateOperations = new ArrayList<>();
  for (String text : texts) {
    Asset asset = Asset.newBuilder().setTextAsset(TextAsset.newBuilder().setText(text)).build();
    AssetOperation assetOperation = AssetOperation.newBuilder().setCreate(asset).build();
    mutateOperations.add(MutateOperation.newBuilder().setAssetOperation(assetOperation).build());
  }

  List<String> assetResourceNames = new ArrayList<>();
  // Creates the service client.
  try (GoogleAdsServiceClient googleAdsServiceClient =
      googleAdsClient.getLatestVersion().createGoogleAdsServiceClient()) {
    // Sends the operations in a single Mutate request.
    MutateGoogleAdsResponse response =
        googleAdsServiceClient.mutate(Long.toString(customerId), mutateOperations);
    for (MutateOperationResponse result : response.getMutateOperationResponsesList()) {
      if (result.hasAssetResult()) {
        assetResourceNames.add(result.getAssetResult().getResourceName());
      }
    }
    printResponseDetails(response);
  }
  return assetResourceNames;
}

      
```

### C#

```c#
/// <summary>
/// Creates multiple text assets and returns the list of resource names.
/// </summary>
/// <param name="client">The Google Ads Client.</param>
/// <param name="customerId">The customer's ID.</param>
/// <param name="texts">The texts to add.</param>
/// <returns>A list of asset resource names.</returns>
private List<string> CreateMultipleTextAssets(
    GoogleAdsClient client,
    long customerId,
    string[] texts)
{
    // Get the GoogleAdsService.
    GoogleAdsServiceClient googleAdsServiceClient =
        client.GetService(Services.V26.GoogleAdsService);

    MutateGoogleAdsRequest request = new MutateGoogleAdsRequest()
    {
        CustomerId = customerId.ToString()
    };

    foreach (string text in texts)
    {
        request.MutateOperations.Add(
            new MutateOperation()
            {
                AssetOperation = new AssetOperation()
                {
                    Create = new Asset()
                    {
                        TextAsset = new TextAsset()
                        {
                            Text = text
                        }
                    }
                }
            }
        );
    }

    // Send the operations in a single Mutate request.
    MutateGoogleAdsResponse response = googleAdsServiceClient.Mutate(request);

    List<string> assetResourceNames = new List<string>();

    foreach (MutateOperationResponse operationResponse in response.MutateOperationResponses)
    {
        MutateAssetResult assetResult = operationResponse.AssetResult;
        assetResourceNames.Add(assetResult.ResourceName);
    }

    PrintResponseDetails(response);

    return assetResourceNames;
}

      
```

### PHP

```php
    private static function createMultipleTextAssets(
        GoogleAdsClient $googleAdsClient,
        int $customerId,
        array $texts
    ): array {
        // Here again, we use the GoogleAdService to create multiple text assets in a single
        // request.
        $operations = [];
        foreach ($texts as $text) {
            // Creates a mutate operation for a text asset.
            $operations[] = new MutateOperation(
                [
                'asset_operation' => new AssetOperation(
                    [
                    'create' => new Asset(['text_asset' => new TextAsset(['text' => $text])])
                    ]
                )
                ]
            );
        }

        // Issues a mutate request to add all assets.
        $googleAdsService = $googleAdsClient->getGoogleAdsServiceClient();
        /**
 * @var MutateGoogleAdsResponse $mutateGoogleAdsResponse
*/
        $mutateGoogleAdsResponse =
            $googleAdsService->mutate(MutateGoogleAdsRequest::build($customerId, $operations));

        $assetResourceNames = [];
        foreach ($mutateGoogleAdsResponse->getMutateOperationResponses() as $response) {
            /**
 * @var MutateOperationResponse $response
*/
            $assetResourceNames[] = $response->getAssetResult()->getResourceName();
        }
        self::printResponseDetails($mutateGoogleAdsResponse);

        return $assetResourceNames;
    }
      
```

### Python

```python
def create_multiple_text_assets(
    client: GoogleAdsClient, customer_id: str, texts: List[str]
) -> List[str]:
    """Creates multiple text assets and returns the list of resource names.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID.
        texts: a list of strings, each of which will be used to create a text
          asset.

    Returns:
        asset_resource_names: a list of asset resource names.
    """
    # Here again we use the GoogleAdService to create multiple text
    # assets in a single request.
    googleads_service: GoogleAdsServiceClient = client.get_service(
        "GoogleAdsService"
    )

    operations: List[MutateOperation] = []
    for text in texts:
        mutate_operation: MutateOperation = client.get_type("MutateOperation")
        asset: Asset = mutate_operation.asset_operation.create
        asset.text_asset.text = text
        operations.append(mutate_operation)

    # Send the operations in a single Mutate request.
    response: MutateGoogleAdsResponse = googleads_service.mutate(
        customer_id=customer_id,
        mutate_operations=operations,
    )
    asset_resource_names: List[str] = []
    for result in response.mutate_operation_responses:
        if result._pb.HasField("asset_result"):
            asset_resource_names.append(result.asset_result.resource_name)
    print_response_details(response)
    return asset_resource_names
      
```

### Ruby

```ruby
# Creates multiple text assets and returns the list of resource names.
def create_multiple_text_assets(client, customer_id, texts)
  operations = texts.map do |text|
    client.operation.mutate do |m|
      m.asset_operation = client.operation.create_resource.asset do |asset|
        asset.text_asset = client.resource.text_asset do |text_asset|
          text_asset.text = text
        end
      end
    end
  end

  # Send the operations in a single Mutate request.
  response = client.service.google_ads.mutate(
    customer_id: customer_id,
    mutate_operations: operations,
  )

  asset_resource_names = []
  response.mutate_operation_responses.each do |result|
    if result.asset_result
      asset_resource_names.append(result.asset_result.resource_name)
    end
  end
  print_response_details(response)
  asset_resource_names
end
      
```

### Perl

```perl
sub create_multiple_text_assets {
  my ($api_client, $customer_id, $texts) = @_;

  # Here again we use the GoogleAdService to create multiple text assets in a
  # single request.
  my $operations = [];
  foreach my $text (@$texts) {
    # Create a mutate operation for a text asset.
    push @$operations,
      Google::Ads::GoogleAds::V26::Services::GoogleAdsService::MutateOperation
      ->new({
        assetOperation =>
          Google::Ads::GoogleAds::V26::Services::AssetService::AssetOperation->
          new({
            create => Google::Ads::GoogleAds::V26::Resources::Asset->new({
                textAsset =>
                  Google::Ads::GoogleAds::V26::Common::TextAsset->new({
                    text => $text
                  })})})});
  }

  # Issue a mutate request to add all assets.
  my $mutate_google_ads_response = $api_client->GoogleAdsService()->mutate({
    customerId       => $customer_id,
    mutateOperations => $operations
  });

  my $asset_resource_names = [];
  foreach
    my $response (@{$mutate_google_ads_response->{mutateOperationResponses}})
  {
    push @$asset_resource_names, $response->{assetResult}{resourceName};
  }
  print_response_details($mutate_google_ads_response);

  return $asset_resource_names;
}
      
```

### 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.md.txt)
> - [REST Interface Structure](https://developers.google.com/google-ads/api/rest/design/overview.md.txt)
> - [JSON Field Mappings](https://developers.google.com/google-ads/api/rest/design/json-mappings.md.txt)
> - Consult the [REST API Reference](https://developers.google.com/google-ads/api/reference/rpc/latest/overview) for the specific service and method.

<br />

## Asset automation

Google automation using machine learning generates additional assets as needed
to cover all relevant channels. Assets are automatically mixed and matched based
on which Google Ad channel (such as YouTube, Gmail, or Search) your ad is being
served on. For more details on managing these settings, see the
[asset automation settings guide](https://developers.google.com/google-ads/api/docs/assets/asset-automation-settings.md.txt).

### Text customization

Text customization allows Google's AI to automatically construct and tailor text
assets for your ads. You can augment this feature by associating URL inclusions
(page feeds) in your account with a Performance Max campaign to
[generate text assets](https://support.google.com/google-ads/answer/10724897#automatically_created_assets).

To link URL inclusions with a campaign, use the same process as used for Dynamic
Search Ads:

1. [Create assets for each page of your website](https://developers.google.com/google-ads/api/docs/dynamic-search-ads/dsa-page-feeds.md.txt#create-assets-for-each-page-on-your-website)
2. [Package page URL inclusions into an AssetSet](https://developers.google.com/google-ads/api/docs/dynamic-search-ads/dsa-page-feeds.md.txt#package-feed-assets-into-assetset)
3. [Associate the AssetSet with a campaign](https://developers.google.com/google-ads/api/docs/dynamic-search-ads/dsa-page-feeds.md.txt#associate-assetset-with-campaign)

After you've associated URL inclusions (a page feed), make sure the
[`AssetAutomationSetting`](https://developers.google.com/google-ads/api/reference/rpc/v26/Campaign.AssetAutomationSetting.md.txt) of type [`TEXT_ASSET_AUTOMATION`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetAutomationTypeEnum.AssetAutomationType.md.txt) is set to
`OPTED_IN`.

This is the default setting if you didn't set the `AssetAutomationSetting` when
creating the campaign.

Using this setting means your campaign can use content from your landing page,
domain, and provided assets to customize ads when predicted to improve
performance. We recommend leaving this as `OPTED_IN`.

> [!IMPORTANT]
> **Key Point:** Both the `CampaignAssetSet` for `AssetSet` of type `PAGE_FEED` and `TEXT_ASSET_AUTOMATION` set to `OPTED_IN` (or no `AssetAutomationSetting` set for `TEXT_ASSET_AUTOMATION`) must be present together for this feature to work. If you want to set `TEXT_ASSET_AUTOMATION` to `OPTED_OUT`, you must first remove the `CampaignAssetSet` before changing the `AssetAutomationSetting`. The same is true the other way around: you must opt-in to `TEXT_ASSET_AUTOMATION` before creating a `CampaignAssetSet`. Attempting to set one of these without the other results in an [`OPERATION_NOT_PERMITTED_FOR_CONTEXT`](https://developers.google.com/google-ads/api/reference/rpc/v26/ContextErrorEnum.ContextError.md.txt#operation_not_permitted_for_context) error.

### Text guidelines

Text guidelines allow you to refine brand messages for automatically generated
text assets by specifying term exclusions and messaging restrictions.

To use text guidelines, populate the [`text_guidelines`](https://developers.google.com/google-ads/api/reference/rpc/v26/Campaign.md.txt#text_guidelines) field of the
[`Campaign`](https://developers.google.com/google-ads/api/reference/rpc/v26/Campaign.md.txt) resource:

- **Term exclusions**: Provide a list of exact words or phrases to be excluded from generated text assets. Each exclusion can be up to 30 characters, with a maximum of 25 exclusions.
- **Messaging restrictions** : Provide freeform instructions (up to 300 characters each) to guide AI text generation. You can provide up to 40 restrictions. Only [`RESTRICTION_BASED_EXCLUSION`](https://developers.google.com/google-ads/api/reference/rpc/v26/MessagingRestrictionTypeEnum.MessagingRestrictionType.md.txt#restriction_based_exclusion) is supported for the restriction type.

### Video assets

If you don't add a video to your Performance Max asset group, then one or more
video assets might be generated from the assets in your asset group. If you no
longer want auto-generated videos to serve in your Performance Max campaign,
then you can upload your own custom video, and the auto-generated videos will
stop serving.

> [!CAUTION]
> **Caution:** In a Performance Max retail campaign whose asset group has no custom assets, don't link a custom `YOUTUBE_VIDEO` asset without also linking all [minimum required text, image, and brand assets](https://developers.google.com/google-ads/api/performance-max/asset-groups.md.txt#link-asset-groups-to-assets-in-performance-max-retail-campaigns) in the same request. Linking only optional custom assets leaves the asset group in an unsupported state that blocks edits in the Google Ads UI.

Smart automation may [enhance your YouTube video assets](https://support.google.com/google-ads/answer/13652431) by adjusting video
orientation and intelligently shortening them to highlight key moments. If you
prefer to maintain your original video assets, set the
[`AssetAutomationSetting`](https://developers.google.com/google-ads/api/reference/rpc/v26/Campaign.AssetAutomationSetting.md.txt) of type [`GENERATE_ENHANCED_YOUTUBE_VIDEOS`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetAutomationTypeEnum.AssetAutomationType.md.txt)
to `OPTED_OUT`.

Google can also find and use relevant videos from approved sources such as
your landing page, YouTube channel, and organic social channels linked on your
landing page ([sourced videos](https://support.google.com/google-ads/answer/17016118)). This optional feature is
disabled by default. To opt in, set the [`AssetAutomationSetting`](https://developers.google.com/google-ads/api/reference/rpc/v26/Campaign.AssetAutomationSetting.md.txt) of type
[`AUTOMATED_VIDEO_CRAWL`](https://developers.google.com/google-ads/api/reference/rpc/v26/AssetAutomationTypeEnum.AssetAutomationType.md.txt#automated_video_crawl) to `OPTED_IN` and configure the
[`automated_video_crawl_setting`](https://developers.google.com/google-ads/api/reference/rpc/v26/Campaign.AssetAutomationSetting.md.txt#automated_video_crawl_setting) with your
approved source URLs and platforms. See the
[asset automation settings guide](https://developers.google.com/google-ads/api/docs/assets/asset-automation-settings.md.txt) for details.