To set up Dynamic Search Ads (DSAs) with the Google Ads API, follow these steps:

1. Create a campaign and specify its domain and language code.
2. Create an ad group for features related to DSAs.
3. Create one or more DSAs.
4. Specify one or more criteria for showing the DSAs in the campaign.

## Create the campaign

To configure DSAs on your campaign, create a
[`Campaign`](https://developers.google.com/google-ads/api/reference/rpc/v26/Campaign.md.txt) with
[`advertising_channel_type`](https://developers.google.com/google-ads/api/reference/rpc/v26/Campaign.md.txt#advertising_channel_type) set to
[`AdvertisingChannelType.SEARCH`](https://developers.google.com/google-ads/api/reference/rpc/v26/AdvertisingChannelTypeEnum.AdvertisingChannelType.md.txt#search). In addition, specify the website
domain (`domain_name`, without `http://` or `https://`) and language
(`language_code`) on which the DSAs operate by setting the
[`dynamic_search_ads_setting`](https://developers.google.com/google-ads/api/reference/rpc/v26/Campaign.md.txt#dynamic_search_ads_setting) field of the `Campaign` using a
[`DynamicSearchAdsSetting`](https://developers.google.com/google-ads/api/reference/rpc/v26/Campaign.DynamicSearchAdsSetting.md.txt). Both `domain_name` and
`language_code` are required. You can also set
[`use_supplied_urls_only`](https://developers.google.com/google-ads/api/reference/rpc/v26/Campaign.DynamicSearchAdsSetting.md.txt#use_supplied_urls_only) on `DynamicSearchAdsSetting`
(`true` restricts targeting to [DSA page feed URLs](https://developers.google.com/google-ads/api/docs/dynamic-search-ads/dsa-page-feeds.md.txt) only;
`false` uses both Google's index of your domain and any page feed URLs).

The following example creates a DSA campaign:


### Java

```java
private static String addCampaign(
    GoogleAdsClient googleAdsClient, long customerId, String budgetResourceName) {
  // Creates the campaign.
  Campaign campaign =
      Campaign.newBuilder()
          .setName("Interplanetary Cruise #" + getPrintableDateTime())
          .setAdvertisingChannelType(AdvertisingChannelType.SEARCH)
          .setStatus(CampaignStatus.PAUSED)
          .setManualCpc(ManualCpc.newBuilder().build())
          .setCampaignBudget(budgetResourceName)
          // Enables the campaign for DSAs.
          .setDynamicSearchAdsSetting(
              DynamicSearchAdsSetting.newBuilder()
                  .setDomainName("example.com")
                  .setLanguageCode("en")
                  .build())
          // Declares whether this campaign serves political ads targeting the EU.
          .setContainsEuPoliticalAdvertising(DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING)
          .setStartDateTime(new DateTime().plusDays(1).toString("yyyy-MM-dd 00:00:00"))
          .setEndDateTime(new DateTime().plusDays(30).toString("yyyy-MM-dd 23:59:59"))
          .build();

  // Creates the operation.
  CampaignOperation operation = CampaignOperation.newBuilder().setCreate(campaign).build();

  // Creates the campaign service client.
  try (CampaignServiceClient campaignServiceClient =
      googleAdsClient.getLatestVersion().createCampaignServiceClient()) {
    // Adds the campaign.
    MutateCampaignsResponse response =
        campaignServiceClient.mutateCampaigns(
            Long.toString(customerId), ImmutableList.of(operation));

    String campaignResourceName = response.getResults(0).getResourceName();
    // Displays the results.
    System.out.printf("Added campaign with resource name '%s'.%n", campaignResourceName);
    return campaignResourceName;
  }
}
      
```

### C#

```c#
private static string AddCampaign(GoogleAdsClient client, long customerId,
    string budgetResourceName)
{
    // Get the CampaignService.
    CampaignServiceClient campaignService = client.GetService(Services.V26.CampaignService);

    // Create the campaign.
    Campaign campaign = new Campaign()
    {
        Name = "Interplanetary Cruise #" + ExampleUtilities.GetRandomString(),
        AdvertisingChannelType = AdvertisingChannelType.Search,
        Status = CampaignStatus.Paused,
        ManualCpc = new ManualCpc(),
        CampaignBudget = budgetResourceName,

        // Enable the campaign for DSAs.
        DynamicSearchAdsSetting = new DynamicSearchAdsSetting()
        {
            DomainName = "example.com",
            LanguageCode = "en"
        },

        // Declare whether or not this campaign contains political ads targeting the EU.
        ContainsEuPoliticalAdvertising = EuPoliticalAdvertisingStatus.DoesNotContainEuPoliticalAdvertising,

        StartDateTime = DateTime.Now.AddDays(1).ToString("yyyyMMdd 00:00:00"),
        EndDateTime = DateTime.Now.AddDays(30).ToString("yyyyMMdd 23:59:59")
    };

    // Create the operation.
    CampaignOperation operation = new CampaignOperation()
    {
        Create = campaign
    };

    // Add the campaign.
    MutateCampaignsResponse response =
        campaignService.MutateCampaigns(customerId.ToString(),
            new CampaignOperation[] { operation });

    // Displays the result.
    string campaignResourceName = response.Results[0].ResourceName;
    Console.WriteLine($"Added campaign with resource name '{campaignResourceName}'.");
    return campaignResourceName;
}
      
```

### PHP

```php
    private static function createCampaign(
        GoogleAdsClient $googleAdsClient,
        int $customerId,
        string $campaignBudgetResourceName
    ) {
        $campaign = new Campaign(
            [
            'name' => 'Interplanetary Cruise #' . Helper::getPrintableDatetime(),
            'advertising_channel_type' => AdvertisingChannelType::SEARCH,
            'status' => CampaignStatus::PAUSED,
            'manual_cpc' => new ManualCpc(),
            'campaign_budget' => $campaignBudgetResourceName,
            // Enables the campaign for DSAs.
            'dynamic_search_ads_setting' => new DynamicSearchAdsSetting(
                [
                'domain_name' => 'example.com',
                'language_code' => 'en'
                ]
            ),
            // Declare whether or not this campaign serves political ads targeting the EU.
            'contains_eu_political_advertising' =>
                EuPoliticalAdvertisingStatus::DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING,
            // Optional: Sets the start and end dates for the campaign, beginning one day from
            // now and ending a month from now.
            'start_date_time' => date('Y-m-d 00:00:00', strtotime('+1 day')),
            'end_date_time' => date('Y-m-d 23:59:59', strtotime('+1 month'))
            ]
        );

        // Creates a campaign operation.
        $campaignOperation = new CampaignOperation();
        $campaignOperation->setCreate($campaign);

        // Issues a mutate request to add campaigns.
        $campaignServiceClient = $googleAdsClient->getCampaignServiceClient();
        /**
 * @var MutateCampaignsResponse $campaignResponse
*/
        $campaignResponse = $campaignServiceClient->mutateCampaigns(
            MutateCampaignsRequest::build($customerId, [$campaignOperation])
        );

        $campaignResourceName = $campaignResponse->getResults()[0]->getResourceName();
        printf("Added campaign named '%s'.%s", $campaignResourceName, PHP_EOL);

        return $campaignResourceName;
    }
      
```

### Python

```python
def create_campaign(
    client: GoogleAdsClient, customer_id: str, budget_resource_name: str
) -> str:
    """Creates a Dynamic Search Ad Campaign under the given customer ID.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID str.
        budget_resource_name: a resource_name str for a Budget

    Returns:
        A resource_name str for the newly created Campaign.
    """
    # Retrieve a new campaign operation object.
    campaign_operation: CampaignOperation = client.get_type("CampaignOperation")
    campaign: Campaign = campaign_operation.create
    campaign.name = f"Interplanetary Cruise #{uuid4()}"
    campaign.advertising_channel_type = (
        client.enums.AdvertisingChannelTypeEnum.SEARCH
    )
    # Recommendation: Set the campaign to PAUSED when creating it to prevent the
    # ads from immediately serving. Set to ENABLED once you've added targeting
    # and the ads are ready to serve.
    campaign.status = client.enums.CampaignStatusEnum.PAUSED
    campaign.manual_cpc.enhanced_cpc_enabled = True
    campaign.campaign_budget = budget_resource_name
    # Required: Enable the campaign for DSAs by setting the campaign's dynamic
    # search ads setting domain name and language.
    campaign.dynamic_search_ads_setting.domain_name = "example.com"
    campaign.dynamic_search_ads_setting.language_code = "en"

    # Declare whether or not this campaign serves political ads targeting the
    # EU. Valid values are:
    #   CONTAINS_EU_POLITICAL_ADVERTISING
    #   DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING
    campaign.contains_eu_political_advertising = (
        client.enums.EuPoliticalAdvertisingStatusEnum.DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING
    )

    # Optional: Sets the start and end dates for the campaign, beginning one day
    # from now and ending a month from now.
    campaign.start_date_time = (datetime.now() + timedelta(days=1)).strftime(
        "%Y%m%d 00:00:00"
    )
    campaign.end_date_time = (datetime.now() + timedelta(days=30)).strftime(
        "%Y%m%d 23:59:59"
    )

    # Retrieve the campaign service.
    campaign_service: CampaignServiceClient = client.get_service(
        "CampaignService"
    )

    # Issues a mutate request to add campaign.
    response: MutateCampaignsResponse = campaign_service.mutate_campaigns(
        customer_id=customer_id, operations=[campaign_operation]
    )
    resource_name: str = response.results[0].resource_name

    print(f'Created campaign with resource_name: "{resource_name}"')
      
```

### Ruby

```ruby
def create_campaign(client, customer_id, budget_resource_name)
  campaign = client.resource.campaign do |c|
    c.name = "Interplanetary Cruise #{(Time.now.to_f * 1000).to_i}"

    c.advertising_channel_type = :SEARCH
    c.status = :PAUSED
    c.manual_cpc = client.resource.manual_cpc
    c.campaign_budget = budget_resource_name

    c.dynamic_search_ads_setting = client.resource.dynamic_search_ads_setting do |s|
      s.domain_name =  "example.com"
      s.language_code =  "en"
    end

    # Declare whether or not this campaign serves political ads targeting the EU.
    # Valid values are CONTAINS_EU_POLITICAL_ADVERTISING and
    # DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING.
    c.contains_eu_political_advertising = :DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING

    c.start_date_time = DateTime.parse((Date.today + 1).to_s).strftime('%Y%m%d %H:%M:%S')
    c.end_date_time = DateTime.parse(Date.today.next_year.to_s).strftime('%Y%m%d %H:%M:%S')
  end

  operation = client.operation.create_resource.campaign(campaign)

  response = client.service.campaign.mutate_campaigns(
    customer_id: customer_id,
    operations: [operation],
  )
  puts("Created campaign with ID: #{response.results.first.resource_name}")
  response.results.first.resource_name
end
      
```

### Perl

```perl
sub create_campaign {
  my ($api_client, $customer_id, $campaign_budget_resource_name) = @_;

  # Create a campaign.
  my $campaign = Google::Ads::GoogleAds::V26::Resources::Campaign->new({
      name                   => "Interplanetary Cruise #" . uniqid(),
      advertisingChannelType => SEARCH,
      status => Google::Ads::GoogleAds::V26::Enums::CampaignStatusEnum::PAUSED,
      manualCpc      => Google::Ads::GoogleAds::V26::Common::ManualCpc->new(),
      campaignBudget => $campaign_budget_resource_name,
      # Enable the campaign for DSAs.
      dynamicSearchAdsSetting =>
        Google::Ads::GoogleAds::V26::Resources::DynamicSearchAdsSetting->new({
          domainName   => "example.com",
          languageCode => "en"
        }
        ),
      # Optional: Set the start and end datetimes for the campaign, beginning one day from
      # now and ending a month from now.
      startDateTime =>
        strftime("%Y%m%d 00:00:00", localtime(time + 60 * 60 * 24)),
      endDateTime =>
        strftime("%Y%m%d 23:59:59", localtime(time + 60 * 60 * 24 * 30)),
      # Declare whether or not this campaign serves political ads targeting the EU.
      # Valid values are CONTAINS_EU_POLITICAL_ADVERTISING and
      # DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING.
      containsEuPoliticalAdvertising =>
        DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING
    });

  # Create a campaign operation.
  my $campaign_operation =
    Google::Ads::GoogleAds::V26::Services::CampaignService::CampaignOperation->
    new({create => $campaign});

  # Add the campaign.
  my $campaigns_response = $api_client->CampaignService()->mutate({
      customerId => $customer_id,
      operations => [$campaign_operation]});

  my $campaign_resource_name = $campaigns_response->{results}[0]{resourceName};

  printf "Created campaign '%s'.\n", $campaign_resource_name;

  return $campaign_resource_name;
}
      
```

### 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 />

## Create the ad group

To use DSA features, create an [`AdGroup`](https://developers.google.com/google-ads/api/reference/rpc/v26/AdGroup.md.txt) with the [`type`](https://developers.google.com/google-ads/api/reference/rpc/v26/AdGroup.md.txt#type)
field set to [`SEARCH_DYNAMIC_ADS`](https://developers.google.com/google-ads/api/reference/rpc/v26/AdGroupTypeEnum.AdGroupType.md.txt#search_dynamic_ads).
This ad group type enforces the following restrictions:

- This ad group type can be added only to Search campaigns.
- A valid `DynamicSearchAdsSetting` must be set at the campaign level before the ad group is added. Otherwise, the API returns an `AdGroupError` with [`CANNOT_ADD_ADGROUP_OF_TYPE_DSA_TO_CAMPAIGN_WITHOUT_DSA_SETTING`](https://developers.google.com/google-ads/api/reference/rpc/v26/AdGroupErrorEnum.AdGroupError.md.txt#cannot_add_adgroup_of_type_dsa_to_campaign_without_dsa_setting).
- Positive keywords aren't allowed in this ad group type. Audience targets, dynamic ad targets (`webpage`), and negative keywords are allowed.
- As with all ad groups, the `type` field cannot be changed after creation.
- Only ad formats related to DSAs are allowed in this ad group.

The following code example shows how to create a `SEARCH_DYNAMIC_ADS` ad group:


### Java

```java
private static String addAdGroup(
    GoogleAdsClient googleAdsClient, long customerId, String campaignResourceName) {
  // Creates the ad group.
  AdGroup adGroup =
      AdGroup.newBuilder()
          .setName("Earth to Mars Cruises #" + getPrintableDateTime())
          .setCampaign(campaignResourceName)
          .setType(AdGroupType.SEARCH_DYNAMIC_ADS)
          .setStatus(AdGroupStatus.PAUSED)
          .setTrackingUrlTemplate("http://tracker.examples.com/traveltracker/{escapedlpurl}")
          .setCpcBidMicros(50_000)
          .build();

  // Creates the operation.
  AdGroupOperation operation = AdGroupOperation.newBuilder().setCreate(adGroup).build();

  // Creates the ad group service client.
  try (AdGroupServiceClient adGroupServiceClient =
      googleAdsClient.getLatestVersion().createAdGroupServiceClient()) {
    MutateAdGroupsResponse response =
        adGroupServiceClient.mutateAdGroups(
            Long.toString(customerId), ImmutableList.of(operation));
    String adGroupResourceName = response.getResults(0).getResourceName();
    // Displays the results.
    System.out.printf("Added ad group with resource name '%s'.%n", adGroupResourceName);
    return adGroupResourceName;
  }
}
      
```

### C#

```c#
private static string AddAdGroup(GoogleAdsClient client, long customerId,
    string campaignResourceName)
{
    // Get the AdGroupService.
    AdGroupServiceClient adGroupService = client.GetService(Services.V26.AdGroupService);

    // Create the ad group.
    AdGroup adGroup = new AdGroup()
    {
        Name = "Earth to Mars Cruises #" + ExampleUtilities.GetRandomString(),
        Campaign = campaignResourceName,
        Type = AdGroupType.SearchDynamicAds,
        Status = AdGroupStatus.Paused,
        TrackingUrlTemplate = "http://tracker.examples.com/traveltracker/{escapedlpurl}",
        CpcBidMicros = 50_000
    };

    // Create the operation.
    AdGroupOperation operation = new AdGroupOperation()
    {
        Create = adGroup
    };

    // Add the ad group.
    MutateAdGroupsResponse response =
        adGroupService.MutateAdGroups(customerId.ToString(),
            new AdGroupOperation[] { operation });

    // Display the results.
    string adGroupResourceName = response.Results[0].ResourceName;
    Console.WriteLine($"Added ad group with resource name '{adGroupResourceName}'.");

    return adGroupResourceName;
}
      
```

### PHP

```php
    private static function createAdGroup(
        GoogleAdsClient $googleAdsClient,
        int $customerId,
        string $campaignResourceName
    ) {
        // Constructs an ad group and sets an optional CPC value.
        $adGroup = new AdGroup(
            [
            'name' => 'Earth to Mars Cruises #' . Helper::getPrintableDatetime(),
            'campaign' => $campaignResourceName,
            'status' => AdGroupStatus::PAUSED,
            'type' => AdGroupType::SEARCH_DYNAMIC_ADS,
            'tracking_url_template' => 'http://tracker.examples.com/traveltracker/{escapedlpurl}',
            'cpc_bid_micros' => 10000000
            ]
        );

        // Creates an ad group operation.
        $adGroupOperation = new AdGroupOperation();
        $adGroupOperation->setCreate($adGroup);

        // Issues a mutate request to add the ad groups.
        $adGroupServiceClient = $googleAdsClient->getAdGroupServiceClient();
        /**
 * @var MutateAdGroupsResponse $adGroupResponse
*/
        $adGroupResponse = $adGroupServiceClient->mutateAdGroups(
            MutateAdGroupsRequest::build($customerId, [$adGroupOperation])
        );

        $adGroupResourceName = $adGroupResponse->getResults()[0]->getResourceName();
        printf("Added ad group named '%s'.%s", $adGroupResourceName, PHP_EOL);

        return $adGroupResourceName;
    }
      
```

### Python

```python
def create_ad_group(
    client: GoogleAdsClient, customer_id: str, campaign_resource_name: str
) -> str:
    """Creates a Dynamic Search Ad Group under the given Campaign.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID str.
        campaign_resource_name: a resource_name str for a Campaign.

    Returns:
        A resource_name str for the newly created Ad Group.
    """
    # Retrieve a new ad group operation object.
    ad_group_operation: AdGroupOperation = client.get_type("AdGroupOperation")
    # Create an ad group.
    ad_group: AdGroup = ad_group_operation.create
    # Required: set the ad group's type to Dynamic Search Ads.
    ad_group.type_ = client.enums.AdGroupTypeEnum.SEARCH_DYNAMIC_ADS
    ad_group.name = f"Earth to Mars Cruises {uuid4()}"
    ad_group.campaign = campaign_resource_name
    ad_group.status = client.enums.AdGroupStatusEnum.PAUSED
    # Recommended: set a tracking URL template for your ad group if you want to
    # use URL tracking software.
    ad_group.tracking_url_template = (
        "http://tracker.example.com/traveltracker/{escapedlpurl}"
    )
    # Optional: Set the ad group bid value.
    ad_group.cpc_bid_micros = 10000000

    # Retrieve the ad group service.
    ad_group_service: AdGroupServiceClient = client.get_service(
        "AdGroupService"
    )

    # Issues a mutate request to add the ad group.
    response: MutateAdGroupsResponse = ad_group_service.mutate_ad_groups(
        customer_id=customer_id, operations=[ad_group_operation]
    )
    resource_name: str = response.results[0].resource_name

    print(f'Created Ad Group with resource_name: "{resource_name}"')
      
```

### Ruby

```ruby
def create_ad_group(client, customer_id, campaign_resource_name)
  ad_group = client.resource.ad_group do |ag|
    ag.type = :SEARCH_DYNAMIC_ADS
    ag.name = "Earth to Mars Cruises #{(Time.now.to_f * 1000).to_i}"

    ag.campaign =  campaign_resource_name

    ag.status = :PAUSED
    ag.tracking_url_template = "http://tracker.example.com/traveltracker/{escapedlpurl}"

    ag.cpc_bid_micros = 3_000_000
  end

  operation = client.operation.create_resource.ad_group(ad_group)

  response = client.service.ad_group.mutate_ad_groups(
    customer_id: customer_id,
    operations: [operation],
  )

  puts("Created ad group with ID: #{response.results.first.resource_name}")
  response.results.first.resource_name
end
      
```

### Perl

```perl
sub create_ad_group {
  my ($api_client, $customer_id, $campaign_resource_name) = @_;

  # Construct an ad group and set an optional CPC value.
  my $ad_group = Google::Ads::GoogleAds::V26::Resources::AdGroup->new({
    name     => "Earth to Mars Cruises #" . uniqid(),
    campaign => $campaign_resource_name,
    status   => Google::Ads::GoogleAds::V26::Enums::AdGroupStatusEnum::PAUSED,
    type     => SEARCH_DYNAMIC_ADS,
    trackingUrlTemplate =>
      "http://tracker.examples.com/traveltracker/{escapedlpurl}",
    cpcBidMicros => 3000000
  });

  # Create an ad group operation.
  my $ad_group_operation =
    Google::Ads::GoogleAds::V26::Services::AdGroupService::AdGroupOperation->
    new({create => $ad_group});

  # Add the ad group.
  my $ad_groups_response = $api_client->AdGroupService()->mutate({
      customerId => $customer_id,
      operations => [$ad_group_operation]});

  my $ad_group_resource_name = $ad_groups_response->{results}[0]{resourceName};

  printf "Created ad group '%s'.\n", $ad_group_resource_name;

  return $ad_group_resource_name;
}
      
```

### 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 />

## Create the DSA

To create the DSA, instantiate an
[`ExpandedDynamicSearchAdInfo`](https://developers.google.com/google-ads/api/reference/rpc/v26/ExpandedDynamicSearchAdInfo.md.txt) object and set the following
fields:

- **Required:** `description`
- **Optional:** `description2`

The ad's headline, display URL, and final URL are auto-generated at serving time
based on domain-specific information provided by the
`DynamicSearchAdsSetting` configured at the campaign level.


### Java

```java
private static void addExpandedDSA(
    GoogleAdsClient googleAdsClient, long customerId, String adGroupResourceName) {
  // Creates an ad group ad.
  AdGroupAd adGroupAd =
      AdGroupAd.newBuilder()
          .setAdGroup(adGroupResourceName)
          .setStatus(AdGroupAdStatus.PAUSED)
          // Sets the ad as an expanded dynamic search ad
          .setAd(
              Ad.newBuilder()
                  .setExpandedDynamicSearchAd(
                      ExpandedDynamicSearchAdInfo.newBuilder()
                          .setDescription("Buy tickets now!")
                          .build())
                  .build())
          .build();

  // Creates the operation.
  AdGroupAdOperation operation = AdGroupAdOperation.newBuilder().setCreate(adGroupAd).build();

  // Creates the ad group ad service client.
  try (AdGroupAdServiceClient adGroupAdServiceClient =
      googleAdsClient.getLatestVersion().createAdGroupAdServiceClient()) {
    // Adds the dynamic search ad.
    MutateAdGroupAdsResponse response =
        adGroupAdServiceClient.mutateAdGroupAds(
            Long.toString(customerId), ImmutableList.of(operation));
    // Displays the response.
    System.out.printf(
        "Added ad group ad with resource name '%s'.%n", response.getResults(0).getResourceName());
  }
}
      
```

### C#

```c#
private static void AddExpandedDSA(GoogleAdsClient client, long customerId,
    string adGroupResourceName)
{
    // Get the AdGroupAdService.
    AdGroupAdServiceClient adGroupAdService =
        client.GetService(Services.V26.AdGroupAdService);

    // Create an ad group ad.
    AdGroupAd adGroupAd = new AdGroupAd()
    {
        AdGroup = adGroupResourceName,
        Status = AdGroupAdStatus.Paused,

        // Set the ad as an expanded dynamic search ad.
        Ad = new Ad()
        {
            ExpandedDynamicSearchAd = new ExpandedDynamicSearchAdInfo()
            {
                Description = "Buy tickets now!"
            }
        }
    };

    // Create the operation.
    AdGroupAdOperation operation = new AdGroupAdOperation()
    {
        Create = adGroupAd
    };

    // Add the dynamic search ad.
    MutateAdGroupAdsResponse response = adGroupAdService.MutateAdGroupAds(
        customerId.ToString(), new AdGroupAdOperation[] { operation });

    // Display the response.
    Console.WriteLine($"Added ad group ad with resource name " +
        $"'{response.Results[0].ResourceName}'.");
}
      
```

### PHP

```php
    private static function createExpandedDSA(
        GoogleAdsClient $googleAdsClient,
        int $customerId,
        string $adGroupResourceName
    ) {
        $adGroupAd = new AdGroupAd(
            [
            'ad_group' => $adGroupResourceName,
            'status' => AdGroupAdStatus::PAUSED,
            'ad' => new Ad(
                [
                'expanded_dynamic_search_ad' => new ExpandedDynamicSearchAdInfo(
                    [
                    'description' => 'Buy tickets now!'
                    ]
                )
                ]
            )
            ]
        );

        $adGroupAdOperation = new AdGroupAdOperation();
        $adGroupAdOperation->setCreate($adGroupAd);

        // Issues a mutate request to add the ad group ads.
        $adGroupAdServiceClient = $googleAdsClient->getAdGroupAdServiceClient();
        /**
 * @var MutateAdGroupAdsResponse $adGroupAdResponse
*/
        $adGroupAdResponse = $adGroupAdServiceClient->mutateAdGroupAds(
            MutateAdGroupAdsRequest::build($customerId, [$adGroupAdOperation])
        );

        $adGroupAdResourceName = $adGroupAdResponse->getResults()[0]->getResourceName();
        printf("Added ad group ad named '%s'.%s", $adGroupAdResourceName, PHP_EOL);

        return $adGroupAdResourceName;
    }
      
```

### Python

```python
def create_expanded_dsa(
    client: GoogleAdsClient, customer_id: str, ad_group_resource_name: str
) -> None:
    """Creates a dynamic search ad under the given ad group.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID str.
        ad_group_resource_name: a resource_name str for an Ad Group.
    """
    # Retrieve a new ad group ad operation object.
    ad_group_ad_operation: AdGroupAdOperation = client.get_type(
        "AdGroupAdOperation"
    )
    # Create and expanded dynamic search ad. This ad will have its headline,
    # display URL and final URL auto-generated at serving time according to
    # domain name specific information provided by DynamicSearchAdSetting at
    # the campaign level.
    ad_group_ad: AdGroupAd = ad_group_ad_operation.create
    # Optional: set the ad status.
    ad_group_ad.status = client.enums.AdGroupAdStatusEnum.PAUSED
    # Set the ad description.
    ad_group_ad.ad.expanded_dynamic_search_ad.description = "Buy tickets now!"
    ad_group_ad.ad_group = ad_group_resource_name

    # Retrieve the ad group ad service.
    ad_group_ad_service: AdGroupAdServiceClient = client.get_service(
        "AdGroupAdService"
    )

    # Submit the ad group ad operation to add the ad group ad.
    response: MutateAdGroupAdsResponse = (
        ad_group_ad_service.mutate_ad_group_ads(
            customer_id=customer_id, operations=[ad_group_ad_operation]
        )
    )
    resource_name: str = response.results[0].resource_name

    print(f'Created Ad Group Ad with resource_name: "{resource_name}"')
      
```

### Ruby

```ruby
def create_expanded_dsa(client, customer_id, ad_group_resource_name)
  ad_group_ad = client.resource.ad_group_ad do |aga|
    aga.status = :PAUSED
    aga.ad = client.resource.ad do |ad|
      ad.expanded_dynamic_search_ad = client.resource.expanded_dynamic_search_ad_info do |info|
        info.description = "Buy tickets now!"
      end
    end

    aga.ad_group = ad_group_resource_name
  end

  operation = client.operation.create_resource.ad_group_ad(ad_group_ad)

  response = client.service.ad_group_ad.mutate_ad_group_ads(
    customer_id: customer_id,
    operations: [operation],
  )
  puts("Created ad group ad with ID: #{response.results.first.resource_name}")
end
      
```

### Perl

```perl
sub create_expanded_dsa {
  my ($api_client, $customer_id, $ad_group_resource_name) = @_;

  # Create an ad group ad.
  my $ad_group_ad = Google::Ads::GoogleAds::V26::Resources::AdGroupAd->new({
      adGroup => $ad_group_resource_name,
      status => Google::Ads::GoogleAds::V26::Enums::AdGroupAdStatusEnum::PAUSED,
      ad     => Google::Ads::GoogleAds::V26::Resources::Ad->new({
          expandedDynamicSearchAd =>
            Google::Ads::GoogleAds::V26::Common::ExpandedDynamicSearchAdInfo->
            new({
              description => "Buy tickets now!"
            })})});

  # Create an ad group ad operation.
  my $ad_group_ad_operation =
    Google::Ads::GoogleAds::V26::Services::AdGroupAdService::AdGroupAdOperation
    ->new({create => $ad_group_ad});

  # Add the ad group ad.
  my $ad_group_ads_response = $api_client->AdGroupAdService()->mutate({
      customerId => $customer_id,
      operations => [$ad_group_ad_operation]});

  my $ad_group_ad_resource_name =
    $ad_group_ads_response->{results}[0]{resourceName};

  printf "Created ad group ad '%s'.\n", $ad_group_ad_resource_name;

  return $ad_group_ad_resource_name;
}
      
```

### 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 />

Because [`final_urls`](https://developers.google.com/google-ads/api/reference/rpc/v26/Ad.md.txt#final_urls%5B%5D) is computed dynamically by Google Ads, you must
not set `final_urls` on the parent [`Ad`](https://developers.google.com/google-ads/api/reference/rpc/v26/Ad.md.txt) when creating a DSA. To use URL
tracking software, you can [configure tracking templates](https://support.google.com/google-ads/answer/7362441)
using the [`tracking_url_template`](https://developers.google.com/google-ads/api/reference/rpc/v26/Ad.md.txt#tracking_url_template) field on the parent
`Ad` object (`Ad.tracking_url_template`, not on `ExpandedDynamicSearchAdInfo`),
or at the [`AdGroup`](https://developers.google.com/google-ads/api/reference/rpc/v26/AdGroup.md.txt#tracking_url_template) (as shown in the preceding ad group
snippet) or [`Campaign`](https://developers.google.com/google-ads/api/reference/rpc/v26/Campaign.md.txt#tracking_url_template) level. When specifying this field,
include one of the following ValueTrack parameters so Google Ads can insert the
matched final URL:

| Parameter | Explanation |
|---|---|
| `{unescapedlpurl}` | Unescaped landing page URL---use when appending query parameters to the end, for example: `{unescapedlpurl}?dsa=true` |
| `{escapedlpurl}` | Escaped (URL-encoded) landing page URL---use when redirecting through a third-party tracker, for example: `https://tracking.example.com/?lp={escapedlpurl}` |
| `{lpurlpath}` | Only the path and query parameters from the computed URL, for example: `https://tracking.example.com/track/{lpurlpath}` |
| `{lpurl}` | Encodes `?` and `=` of the landing page URL and ends with the search query. If placed at the very beginning of the `tracking_url_template` field, it is replaced by the `{unescapedlpurl}` value, for example: https://tracking.example.com/redir.php?tracking=xyz&url={lpurl} |

For example, in Java, set `tracking_url_template` on the `Ad` builder:

```java
adBuilder.setTrackingUrlTemplate(
    "https://example.com/traveltracker/{escapedlpurl}");
```

## Specify criteria for the DSA

Finally, configure criteria to trigger serving of the DSAs using the
[`webpage`](https://developers.google.com/google-ads/api/reference/rpc/v26/AdGroupCriterion.md.txt#webpage) field of [`AdGroupCriterion`](https://developers.google.com/google-ads/api/reference/rpc/v26/AdGroupCriterion.md.txt) (see the
complete [Add Dynamic Search Ads sample](https://developers.google.com/google-ads/api/samples/add-dynamic-search-ads.md.txt)). Set `webpage` to a
[`WebpageInfo`](https://developers.google.com/google-ads/api/reference/rpc/v26/WebpageInfo.md.txt) object with a required
[`criterion_name`](https://developers.google.com/google-ads/api/reference/rpc/v26/WebpageInfo.md.txt#criterion_name) (required on `CREATE` and prohibited on
`UPDATE`) and up to three [`conditions`](https://developers.google.com/google-ads/api/reference/rpc/v26/WebpageInfo.md.txt#conditions%5B%5D) (logically `AND`-ed
together when evaluated; an empty `conditions` list targets all pages of the
campaign's website).

These `conditions` are [`WebpageConditionInfo`](https://developers.google.com/google-ads/api/reference/rpc/v26/WebpageConditionInfo.md.txt)
instances that specify what to filter or match within the domain configured in
the campaign settings using an [`operand`](https://developers.google.com/google-ads/api/reference/rpc/v26/WebpageConditionInfo.md.txt#operand), an
[`argument`](https://developers.google.com/google-ads/api/reference/rpc/v26/WebpageConditionInfo.md.txt#argument), and an optional
[`operator`](https://developers.google.com/google-ads/api/reference/rpc/v26/WebpageConditionInfo.md.txt#operator) (`EQUALS` or `CONTAINS`). You can filter on
five operand types:

| [WebpageConditionOperand](https://developers.google.com/google-ads/api/reference/rpc/v26/WebpageConditionOperandEnum.WebpageConditionOperand.md.txt) | Description |
|---|---|
| `URL` | A string matching a partial URL of a page. |
| `CATEGORY` | A string with a category to match against precisely. |
| `PAGE_TITLE` | A string matching a partial page title. |
| `PAGE_CONTENT` | A string matching content within any indexed page. |
| `CUSTOM_LABEL` | A string matching a web page custom label targeting condition. See [Target URL inclusions using custom labels](https://developers.google.com/google-ads/api/docs/dynamic-search-ads/dsa-page-feeds.md.txt#labels). |

For example, you can create a web page criterion that targets pages under the
`/children` path of a vacation site (`URL` condition) that also contain
"Special Offer" in the title (`PAGE_TITLE` condition).

### Discover site categories

You can retrieve and filter the list of
[`DomainCategory`](https://developers.google.com/google-ads/api/reference/rpc/v26/DomainCategory.md.txt) objects that Google Ads identifies for your
site by querying the [`domain_category`](https://developers.google.com/google-ads/api/fields/v26/domain_category.md.txt) resource in
GAQL.

The following GAQL query retrieves the domain categories for a specific site and
campaign:

```sql
SELECT
  domain_category.category,
  domain_category.language_code,
  domain_category.recommended_cpc_bid_micros
FROM domain_category
WHERE domain_category.domain = 'example.com'
  AND campaign.id = campaign_id
```

### Exclude web page targets

You can also use [`AdGroupCriterionService`](https://developers.google.com/google-ads/api/reference/rpc/v26/AdGroupCriterionService.md.txt) to
create negative `webpage` criteria (by setting `negative = true` on
`AdGroupCriterion`). For example, you can exclude pages with a specific title
that you manage in a separate campaign or ad group.

### Other criteria

DSA campaigns and ad groups aren't restricted to only web page criteria; you can
combine them with other criterion types to refine targeting. Use additional
criteria judiciously, however, because overly restrictive targeting can reduce
the effectiveness of DSA auto-targeting.