Dynamic Search Ads Page Feeds

By default, Dynamic Search Ads (DSAs) are set up to target entire websites, or portions of them without focusing on specific page URLs. If you need better control over the URLs, you can use DSA page feeds to specify precisely which URLs to use with your Dynamic Search Ads. When you provide a page feed of your products and their landing pages, it helps Google Ads determine when to show your ads and where to direct people on your website.

To set up a DSA page feed:

  1. Create a feed and populate it with page URLs.
  2. Set up the campaign to use the DSA page feed.
  3. Optional, but recommended: Add custom labels to the URLs in your page feed to categorize and organize the targets for your Dynamic Search Ads.

Create a page feed

The first step in using DSA page feeds is to create a feed with the field criterion_type of the FeedMapping set as DSA_PAGE_FEED. The procedure is similar to that listed in our feed services guide, except for the following differences.

  1. DSA page feeds use the criterion_type field instead of the placeholder_type field to set the target of the FeedMapping.
  2. You only need to create the feed, populate the items, and map the feed to the DSA page feed criterion fields.
DsaPageFeedCriterionField Description Required? Data Type
PAGE_URL URL of the web page you want to target. Yes URL or URL_LIST
LABEL The labels that will help you target ads within your page feed.

It should not contain the following string patterns: *, >>, ==, &+.

No STRING_LIST

Set up the campaign for page feeds

You can set up a DSA campaign to use page feeds by setting the feeds field of its DynamicSearchAdsSetting.

Start by retrieving the DynamicSearchAdSetting for your Dynamic Search Ad campaign.

Java

private static DynamicSearchAdsSetting getDsaSetting(
    GoogleAdsClient googleAdsClient, long customerId, long campaignId) {
  // Creates the query.
  // You must request all DSA fields in order to update the DSA settings in the following step.
  String query =
      String.format(
          "SELECT campaign.id, campaign.name, campaign.dynamic_search_ads_setting.domain_name,"
              + " campaign.dynamic_search_ads_setting.language_code,"
              + " campaign.dynamic_search_ads_setting.use_supplied_urls_only "
              + "FROM campaign "
              + "WHERE campaign.id = '%s'",
          campaignId);

  // Creates the request.
  SearchGoogleAdsRequest request =
      SearchGoogleAdsRequest.newBuilder()
          .setCustomerId(Long.toString(customerId))
          .setPageSize(PAGE_SIZE)
          .setQuery(query)
          .build();

  // Creates the service client.
  try (GoogleAdsServiceClient googleAdsServiceClient =
      googleAdsClient.getLatestVersion().createGoogleAdsServiceClient()) {
    // Issues the search request.
    SearchPagedResponse response = googleAdsServiceClient.search(request);

    // Throws an exception if the campaign is not a DSA campaign.
    // The server will return an error when trying to update the campaign with the DSA feed in
    // the following step if the campaign is not a DSA campaign. However, this
    // exception is easier to interpret.
    if (!response
        .getPage()
        .getResponse()
        .getResults(0)
        .getCampaign()
        .hasDynamicSearchAdsSetting()) {
      throw new IllegalArgumentException(
          String.format("Campaign with ID '%s' is not a " + "DSA campaign.", campaignId));
    }

    // Retrieves and returns the DSA setting.
    return response
        .getPage()
        .getResponse()
        .getResults(0)
        .getCampaign()
        .getDynamicSearchAdsSetting();
  }
}

C#

private DynamicSearchAdsSetting GetDsaSetting(GoogleAdsClient client, long customerId,
    long campaignId)
{
    // Get the GoogleAdsService.
    GoogleAdsServiceClient googleAdsService = client.GetService(
        Services.V3.GoogleAdsService);

    // Creates the query.
    // You must request all DSA fields in order to update the DSA settings in the
    // following step.
    string query =
        "SELECT "
            + "campaign.id, "
            + "campaign.name, "
            + "campaign.dynamic_search_ads_setting.domain_name, "
            + "campaign.dynamic_search_ads_setting.language_code, "
            + "campaign.dynamic_search_ads_setting.use_supplied_urls_only "
            + "FROM "
            + "campaign "
            + "WHERE "
            + "campaign.id = "
            + campaignId;

    GoogleAdsRow result = googleAdsService.Search(
        customerId.ToString(), query).FirstOrDefault();

    if (result == null)
    {
        throw new Exception("No campaign found with ID: " + campaignId);
    }

    // Gets the DSA settings.
    DynamicSearchAdsSetting dynamicSearchAdsSetting =
        result.Campaign.DynamicSearchAdsSetting;

    // Throws an exception if the campaign is not a DSA campaign.
    if (dynamicSearchAdsSetting == null || string.IsNullOrEmpty(
        dynamicSearchAdsSetting.DomainName))
    {
        throw new Exception($"Campaign with ID {campaignId} is not a DSA campaign.");
    }

    return dynamicSearchAdsSetting;
}

PHP

private static function getDsaSetting(
    GoogleAdsClient $googleAdsClient,
    int $customerId,
    int $campaignId
) {
    // Creates the query.
    // You must request all DSA fields in order to update the DSA settings in the following
    // step.
    $query = "SELECT campaign.id, campaign.name, " .
    "campaign.dynamic_search_ads_setting.domain_name, " .
    "campaign.dynamic_search_ads_setting.language_code, " .
    "campaign.dynamic_search_ads_setting.use_supplied_urls_only " .
    "FROM campaign where campaign.id = $campaignId";

    $googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient();
    $response = $googleAdsServiceClient->search(
        $customerId,
        $query,
        ['pageSize' => self::PAGE_SIZE, 'returnTotalResultsCount' => true]
    );

    // Throws an exception if a campaign with the provided ID does not exist.
    if ($response->getPage()->getResponseObject()->getTotalResultsCount() === 0) {
        throw new \InvalidArgumentException("No campaign found with ID $campaignId");
    }

    $dynamicSearchAdsSetting = $response
        ->getPage()
        ->getResponseObject()
        ->getResults()[0]
        ->getCampaign()
        ->getDynamicSearchAdsSetting();

    // Throws an exception if the campaign is not a DSA campaign.
    if (is_null($dynamicSearchAdsSetting)) {
        throw new \InvalidArgumentException(
            "Campaign with ID $campaignId is not a DSA campaign."
        );
    }

    return $dynamicSearchAdsSetting;
}

Python

def update_campaign_dsa_setting(client, customer_id, campaign_id, feed_details):
    """Updates the given campaign with the given feed details

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID str.
        campaign_id: a campaign ID str;
        feed_details: a FeedDetails instance with feed attribute information.
    """
    query = '''
        SELECT
            campaign.id,
            campaign.name,
            campaign.dynamic_search_ads_setting.domain_name
        FROM
            campaign
        WHERE
            campaign.id = {}
        LIMIT 1
    '''.format(campaign_id)

    ga_service = client.get_service('GoogleAdsService', version='v3')
    results = ga_service.search(customer_id, query=query)

    for row in results:
        campaign = row.campaign

    if not campaign:
        raise ValueError('Campaign with id #{} not found'.format(campaign_id))

    if not campaign.dynamic_search_ads_setting.domain_name:
        raise ValueError(
            'Campaign id #{} is not set up for Dynamic Search Ads.'.format(
                campaign_id))

Ruby

def update_campaign_dsa_setting(client, customer_id, campaign_id, feed_details)
  query = <<~EOD
    SELECT
      campaign.id, campaign.name, campaign.dynamic_search_ads_setting.domain_name
    FROM
      campaign
    WHERE
      campaign.id = #{campaign_id}
    LIMIT 1000
  EOD
  response = client.service.google_ads.search(customer_id, query)

  result = response.first

Perl

sub get_dsa_setting {
  my ($api_client, $customer_id, $campaign_id) = @_;

  # Create the query.
  # You must request all DSA fields in order to update the DSA settings in the
  # following step.
  my $search_query =
    "SELECT campaign.id, campaign.name, " .
    "campaign.dynamic_search_ads_setting.domain_name, " .
    "campaign.dynamic_search_ads_setting.language_code, " .
    "campaign.dynamic_search_ads_setting.use_supplied_urls_only " .
    "FROM campaign where campaign.id = $campaign_id";

  my $search_response = $api_client->GoogleAdsService()->search({
    customerId => $customer_id,
    query      => $search_query,
    pageSize   => PAGE_SIZE
  });

  # Die if a campaign with the provided ID does not exist.
  die "No campaign found with ID $campaign_id.\n"
    if scalar @{$search_response->{results}} == 0;

  my $dynamic_search_ads_setting =
    $search_response->{results}[0]{campaign}{dynamicSearchAdsSetting};

  # Die if the campaign is not a DSA campaign.
  die "Campaign with ID $campaign_id is not a DSA campaign.\n"
    if not $dynamic_search_ads_setting;

  return $dynamic_search_ads_setting;
}

Next, set the page feeds by specifying their resource names in the feeds field of your campaign's DynamicSearchAdsSetting. You can optionally use the use_supplied_urls_only field to specify whether or not to use only the specified URLs for your Dynamic Search Ads.

Java

private static void updateCampaignDsaSetting(
    GoogleAdsClient googleAdsClient, long customerId, String feedResourceName, long campaignId) {
  // Retrieves the existing dynamic search ads settings for the campaign.
  DynamicSearchAdsSetting dsaSetting = getDsaSetting(googleAdsClient, customerId, campaignId);
  dsaSetting.toBuilder().addAllFeeds(ImmutableList.of(StringValue.of(feedResourceName))).build();

  // Creates the campaign object to update.
  Campaign campaign =
      Campaign.newBuilder()
          .setResourceName(ResourceNames.campaign(customerId, campaignId))
          .setDynamicSearchAdsSetting(dsaSetting)
          .build();

  // Creates the update operation and sets the update mask.
  CampaignOperation operation =
      CampaignOperation.newBuilder()
          .setUpdate(campaign)
          .setUpdateMask(FieldMasks.allSetFieldsOf(campaign))
          .build();

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

    // Displays the results.
    System.out.printf(
        "Updated campaign with resource name '%s'.%n", response.getResults(0).getResourceName());
  }
}

C#

private void UpdateCampaignDsaSetting(GoogleAdsClient client, long customerId,
    string feedResourceName, long campaignId)
{
    // Get the CampaignService.
    CampaignServiceClient campaignService = client.GetService(
        Services.V3.CampaignService);

    DynamicSearchAdsSetting dsaSetting = GetDsaSetting(client, customerId, campaignId);
    dsaSetting.Feeds.Add(feedResourceName);

    // Create the campaign.
    Campaign campaign = new Campaign()
    {
        ResourceName = ResourceNames.Campaign(customerId, campaignId),
        DynamicSearchAdsSetting = dsaSetting
    };

    // Create the operation.
    CampaignOperation operation = new CampaignOperation()
    {
        Update = campaign,
        UpdateMask = FieldMasks.AllSetFieldsOf(campaign)
    };

    // Update the campaign.
    MutateCampaignsResponse response =
        campaignService.MutateCampaigns(customerId.ToString(), new[] { operation });
    // Display the results.
    foreach (MutateCampaignResult mutateCampaignResult in response.Results)
    {
        Console.WriteLine($"Updated campaign with resourceName: " +
            $"'{mutateCampaignResult.ResourceName}'.");
    }
}

PHP

private static function updateCampaignDsaSetting(
    GoogleAdsClient $googleAdsClient,
    int $customerId,
    array $feedDetails,
    int $campaignId
) {
    // Retrieves the existing dynamic search ads settings for the campaign.
    $dsaSetting = self::getDsaSetting(
        $googleAdsClient,
        $customerId,
        $campaignId
    );

    $feedResourceName = $feedDetails['resource_name'];
    $dsaSetting->setFeeds([new StringValue(['value' => $feedResourceName])]);

    // Creates the campaign object to be updated.
    $campaign = new Campaign();
    $campaign->setResourceName(ResourceNames::forCampaign($customerId, $campaignId));
    $campaign->setDynamicSearchAdsSetting($dsaSetting);

    // Creates the update operation and sets the update mask.
    $campaignOperation = new CampaignOperation();
    $campaignOperation->setUpdate($campaign);
    $campaignOperation->setUpdateMask(FieldMasks::allSetFieldsOf($campaign));

    // Updates the campaign.
    $campaignServiceClient = $googleAdsClient->getCampaignServiceClient();
    $response = $campaignServiceClient->mutateCampaigns(
        $customerId,
        [$campaignOperation]
    );

    // Displays the results.
    $campaignResourceName = $response->getResults()[0]->getResourceName();
    printf(
        "Updated campaign with resourceName: '%s'.%s",
        $campaignResourceName,
        PHP_EOL
    );
}

Python

# Retrieve a new campaign operation
campaign_operation = client.get_type('CampaignOperation', version='v3')
# Copy the retrieved campaign onto the new campaign operation.
campaign_operation.update.CopyFrom(campaign)
updated_campaign = campaign_operation.update
feed = updated_campaign.dynamic_search_ads_setting.feeds.add()
# Use a page feed to specify precisely which URLs to use with your Dynamic
# Search ads.
feed.value = feed_details.resource_name
field_mask = protobuf_helpers.field_mask(campaign, updated_campaign)
campaign_operation.update_mask.CopyFrom(field_mask)

# Retrieve the campaign service.
campaign_service = client.get_service('CampaignService', version='v3')
# Submit the campaign operation and update the campaign.
response = campaign_service.mutate_campaigns(customer_id,
                                             [campaign_operation])
resource_name = response.results[0].resource_name

# Display the results.
print('Updated campaign #{}'.format(resource_name))

Ruby

campaign = result.campaign

if !campaign.dynamic_search_ads_setting || !campaign.dynamic_search_ads_setting.domain_name \
  || campaign.dynamic_search_ads_setting.domain_name.value == ""
  raise "Campaign id #{campaign_id} is not set up for dynamic search ads"
end

op = client.operation.update_resource.campaign(campaign) do
  campaign.dynamic_search_ads_setting.feeds << feed_details.resource_name
end

response = client.service.campaign.mutate_campaigns(customer_id, [op])
puts "Updated campaign #{response.results.first.resource_name}"

Perl

sub update_campaign_dsa_setting {
  my ($api_client, $customer_id, $feed_details, $campaign_id) = @_;

  # Retrieve the existing dynamic search ads settings for the campaign.
  my $dsa_setting = get_dsa_setting($api_client, $customer_id, $campaign_id);

  my $feed_resource_name = $feed_details->{resourceName};
  $dsa_setting->{feeds} = [$feed_resource_name];

  # Create the campaign object to be updated.
  my $campaign = Google::Ads::GoogleAds::V3::Resources::Campaign->new({
      resourceName =>
        Google::Ads::GoogleAds::V3::Utils::ResourceNames::campaign(
        $customer_id, $campaign_id
        ),
      dynamicSearchAdsSetting => $dsa_setting
    });

  # Create the update operation and set the update mask.
  my $campaign_operation =
    Google::Ads::GoogleAds::V3::Services::CampaignService::CampaignOperation->
    new({
      update => $campaign,
      updateMask =>
        Google::Ads::GoogleAds::Utils::FieldMasks::all_set_fields_of($campaign)}
    );

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

  printf "Updated campaign with resource name: '%s'.\n",
    $campaign_response->{results}[0]{resourceName};
}

These settings map to the Google Ads UI as follows.

use_supplied_urls_only feeds Google Ads UI Setting
false N/A Use Google’s index of my website.
false One or more are specified. Use URLs from both Google’s index of my website and my page feed.
true One or more are specified. Use URLs from my page feed only.
true Empty or null. Not supported. The Google Ads API throws a SettingError.DYNAMIC_SEARCH_ADS_SETTING_AT_LEAST_ONE_FEED_ID_MUST_BE_PRESENT.

Target page feed URLs using custom labels

You can optionally use custom labels to target and bid on URLs in the page feed. This can be done by creating a criterion based on a WebpageInfo that filters using a condition that has its operand set as WebpageConditionOperand.CUSTOM_LABEL.

Java

private static void addDsaTarget(
    GoogleAdsClient googleAdsClient, long customerId, long adGroupId, String dsaPageUrlLabel) {
  String adGroupResourceName = ResourceNames.adGroup(customerId, adGroupId);

  // Creates the webpage condition info that targets an advertiser's webpages based on the
  // custom label specified by the dsaPageUrlLabel (e.g. "discounts").
  WebpageConditionInfo webpageConditionInfo =
      WebpageConditionInfo.newBuilder()
          .setOperand(WebpageConditionOperand.CUSTOM_LABEL)
          .setArgument(StringValue.of(dsaPageUrlLabel))
          .build();

  // Creates the webpage info, or criterion for targeting webpages of an advertiser's website.
  WebpageInfo webpageInfo =
      WebpageInfo.newBuilder()
          .setCriterionName(StringValue.of("Test Criterion"))
          .addAllConditions(ImmutableList.of(webpageConditionInfo))
          .build();

  // Creates the ad group criterion.
  AdGroupCriterion adGroupCriterion =
      AdGroupCriterion.newBuilder()
          .setAdGroup(StringValue.of(adGroupResourceName))
          .setWebpage(webpageInfo)
          .setCpcBidMicros(Int64Value.of(1_500_000))
          .build();

  // Creates the operation.
  AdGroupCriterionOperation operation =
      AdGroupCriterionOperation.newBuilder().setCreate(adGroupCriterion).build();

  // Creates the service client.
  try (AdGroupCriterionServiceClient adGroupCriterionServiceClient =
      googleAdsClient.getLatestVersion().createAdGroupCriterionServiceClient()) {
    // Adds the ad group criterion.
    MutateAdGroupCriteriaResponse response =
        adGroupCriterionServiceClient.mutateAdGroupCriteria(
            Long.toString(customerId), ImmutableList.of(operation));

    // Displays the results.
    System.out.printf(
        "Created ad group criterion with resource name '%s'.%n",
        response.getResults(0).getResourceName());
  }
}

C#

private void AddDsaTarget(GoogleAdsClient client, long customerId, long adGroupId, string dsaPageUrlLabel)
{
    // Get the AdGroupCriterionService.
    AdGroupCriterionServiceClient adGroupCriterionService = client.GetService(
        Services.V3.AdGroupCriterionService);

    // Create the webpage condition info.
    WebpageConditionInfo webpageConditionInfo = new WebpageConditionInfo()
    {
        Operand = WebpageConditionOperand.CustomLabel,
        Argument = dsaPageUrlLabel,
    };

    // Creates the webpage info.
    WebpageInfo webpageInfo = new WebpageInfo()
    {
        CriterionName = "Test Criterion",
        Conditions = { webpageConditionInfo }
    };

    // Creates the ad group criterion.
    AdGroupCriterion adGroupCriterion = new AdGroupCriterion()
    {
        AdGroup = ResourceNames.AdGroup(customerId, adGroupId),
        Webpage = webpageInfo,
        CpcBidMicros = 1_500_000
    };

    // Create the operation.
    AdGroupCriterionOperation operation = new AdGroupCriterionOperation()
    {
        Create = adGroupCriterion
    };

    // Add the ad group criterion.
    MutateAdGroupCriteriaResponse mutateAdGroupCriteriaResponse =
        adGroupCriterionService.MutateAdGroupCriteria(customerId.ToString(),
            new[] { operation });

    // Display the results.
    foreach (MutateAdGroupCriterionResult result in mutateAdGroupCriteriaResponse.Results)
    {
        Console.WriteLine($"Created ad group criterion with resource name " +
            $"'{result.ResourceName}'.");
    }
}

PHP

public static function addDsaTarget(
    GoogleAdsClient $googleAdsClient,
    int $customerId,
    int $adGroupId,
    string $dsaPageUrlLabel
) {
    $adGroupResourceName = ResourceNames::forAdGroup($customerId, $adGroupId);

    // Creates the webpage condition info.
    $webPageConditionInfo = new WebpageConditionInfo([
        'operand' => WebpageConditionOperand::CUSTOM_LABEL,
        'argument' => $dsaPageUrlLabel
    ]);

    // Creates the webpage info.
    $webPageInfo = new WebpageInfo([
        'criterion_name' => new StringValue(['value' => 'Test Criterion']),
        'conditions' => [$webPageConditionInfo]
    ]);

    // Creates the ad group criterion.
    $adGroupCriterion = new AdGroupCriterion([
        'ad_group' => $adGroupResourceName,
        'webpage' => $webPageInfo,
        'cpc_bid_micros' => new Int64Value(['value' => 1500000])
    ]);

    // Creates the operation.
    $adGroupCriterionOperation = new AdGroupCriterionOperation();
    $adGroupCriterionOperation->setCreate($adGroupCriterion);

    $adGroupCriterionServiceClient = $googleAdsClient->getAdGroupCriterionServiceClient();
    $response = $adGroupCriterionServiceClient->mutateAdGroupCriteria(
        $customerId,
        [$adGroupCriterionOperation]
    );

    $adGroupCriterionResourceName = $response->getResults()[0]->getResourceName();
    printf(
        "Created ad group criterion with resource name '%s'.%s",
        $adGroupCriterionResourceName,
        PHP_EOL
    );
}

Python

def add_dsa_targeting(client, customer_id, ad_group_resource_name, label):
    """Adds Dynamic Search Ad targeting criteria to 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.
        label: a Dynamic Search Ad URL label str.
    """
    # Retrieve a new ad group criterion operation object.
    ad_group_criterion_operation = client.get_type(
        'AdGroupCriterionOperation', version='v3')
    # Create a new ad group criterion.
    ad_group_criterion = ad_group_criterion_operation.create
    ad_group_criterion.ad_group.value = ad_group_resource_name
    # Set the custom bid for this criterion.
    ad_group_criterion.cpc_bid_micros.value = 1500000
    ad_group_criterion.webpage.criterion_name.value = 'Test criterion'
    # Add a condition for label=specified_label_name
    webpage_criterion_info = ad_group_criterion.webpage.conditions.add()
    webpage_criterion_info.argument.value = label
    webpage_criterion_info.operand = client.get_type(
        'WebpageConditionOperandEnum', version='v3').CUSTOM_LABEL

    # Retrieve the ad group criterion service.
    ad_group_criterion_service = client.get_service('AdGroupCriterionService',
                                                    version='v3')
    response = ad_group_criterion_service.mutate_ad_group_criteria(
        customer_id, [ad_group_criterion_operation])
    resource_name = response.results[0].resource_name

    # Display the results.
    print('Created ad group criterion with resource_name: # {}'.format(
        resource_name))

Ruby

def add_dsa_targeting(client, customer_id, ad_group_resource_name, label)
  webpage_condition_info = client.resource.webpage_condition_info do |wci|
    wci.operand = :CUSTOM_LABEL
    wci.argument = label
  end

  webpage_criterion = client.resource.webpage_info do |wi|
    wi.criterion_name = "Test criterion"
    wi.conditions << webpage_condition_info
  end

  ad_group_criterion = client.resource.ad_group_criterion do |agc|
    agc.ad_group = ad_group_resource_name
    agc.webpage = webpage_criterion
    agc.cpc_bid_micros = 1_500_000
  end

  op = client.operation.create_resource.ad_group_criterion(ad_group_criterion)

  response = client.service.ad_group_criterion.mutate_ad_group_criteria(customer_id, [op])

  puts "Created ad group criterion with id: #{response.results.first.resource_name}"
end

Perl

sub add_dsa_target {
  my ($api_client, $customer_id, $ad_group_id, $dsa_page_url_label) = @_;

  my $ad_group_resource_name =
    Google::Ads::GoogleAds::V3::Utils::ResourceNames::ad_group($customer_id,
    $ad_group_id);

  # Create the webpage condition info.
  my $web_page_condition_info =
    Google::Ads::GoogleAds::V3::Common::WebpageConditionInfo->new({
      operand  => CUSTOM_LABEL,
      argument => $dsa_page_url_label
    });

  # Create the webpage info.
  my $web_page_info = Google::Ads::GoogleAds::V3::Common::WebpageInfo->new({
      criterionName => "Test Criterion",
      conditions    => [$web_page_condition_info]});

  # Create the ad group criterion.
  my $ad_group_criterion =
    Google::Ads::GoogleAds::V3::Resources::AdGroupCriterion->new({
      adGroup      => $ad_group_resource_name,
      webpage      => $web_page_info,
      cpcBidMicros => 1500000
    });

  # Create the operation.
  my $ad_group_criterion_operation =
    Google::Ads::GoogleAds::V3::Services::AdGroupCriterionService::AdGroupCriterionOperation
    ->new({
      create => $ad_group_criterion
    });

  my $ad_group_criterion_response =
    $api_client->AdGroupCriterionService()->mutate({
      customerId => $customer_id,
      operations => [$ad_group_criterion_operation]});

  printf "Created ad group criterion with resource name: '%s'.\n",
    $ad_group_criterion_response->{results}[0]{resourceName};
}