Requesting Exemption for Expanded Text Ads and Responsive Search Ads

Expanded text ads and responsive search ads require steps for exemption request that are different from other ad types:

  1. Store all the ignorable policy topic included in PolicyTopicEntry, which is stored inside PolicyFindingDetails, returned when your first attempt to create an ad failed.
  2. Send a mutate request to create the ad again by including the stored ignorable policy topics.

Visit this guide if you wish to request exemption for other ad types instead. In this guide, we will use an expanded text ad as an example. The steps for requesting exemption for responsive search ads are mostly the same, except for the step of creating ExpandedTextAdInfo, which you need to replace with ResponsiveSearchAdInfo.

Store all ignorable policy topics

The error details for expanded text ads and responsive search ads will be included in PolicyFindingDetails, which in turn stores a list of PolicyTopicEntry objects.

In this step, you need to store the topic field of each PolicyTopicEntry:

Java

private List<String> fetchIgnorablePolicyTopics(GoogleAdsException gae) {
  System.out.println("Google Ads failure details:");

  // Creates a list to store the result.
  List<String> ignorableTopics = new ArrayList<>();

  // Searches all errors for ignorable policy topics.
  for (GoogleAdsError error : gae.getGoogleAdsFailure().getErrorsList()) {
    // Supports sending exemption request for the policy finding error only.
    if (error.getErrorCode().getErrorCodeCase() != ErrorCodeCase.POLICY_FINDING_ERROR) {
      throw gae;
    }

    // Shows some information about the error encountered.
    System.out.printf("\t%s: %s%n", error.getErrorCode().getErrorCodeCase(), error.getMessage());

    // Checks policy finding details for ignorable policy topics.
    if (error.getDetails() != null) {
      PolicyFindingDetails policyFindingDetails = error.getDetails().getPolicyFindingDetails();
      if (policyFindingDetails != null) {
        System.out.println("\tPolicy finding details:");
        // Shows all the policy topics for the current error.
        for (PolicyTopicEntry policyTopicEntry :
            policyFindingDetails.getPolicyTopicEntriesList()) {
          // Adds this topic to the result.
          ignorableTopics.add(policyTopicEntry.getTopic());
          System.out.printf("\t\tPolicy topic name: '%s'%n", policyTopicEntry.getTopic());
          System.out.printf("\t\tPolicy topic entry type: '%s'%n", policyTopicEntry.getType());
          // For the sake of brevity, we exclude printing "policy topic evidences" and
          // "policy topic constraints" here. You can fetch those data by calling:
          // - policyTopicEntry.getEvidences()
          // - policyTopicEntry.getConstraints()
        }
      }
    }
  }
  return ignorableTopics;
}

C#

private static string[] FetchIgnorablePolicyTopics(GoogleAdsException ex)
{
    List<string> ignorablePolicyTopics = new List<string>(); ;

    Console.WriteLine("Google Ads failure details:");
    foreach (GoogleAdsError error in ex.Failure.Errors)
    {
        if (error.ErrorCode.ErrorCodeCase != ErrorCode.ErrorCodeOneofCase.PolicyFindingError)
        {
            throw ex;
        }
        if (error.Details != null && error.Details.PolicyFindingDetails != null)
        {
            PolicyFindingDetails details = error.Details.PolicyFindingDetails;
            Console.WriteLine($"- Policy finding details:");

            foreach (PolicyTopicEntry entry in details.PolicyTopicEntries)
            {
                ignorablePolicyTopics.Add(entry.Topic);
                Console.WriteLine($"  - Policy topic name: '{entry.Topic}");
                Console.WriteLine($"  - Policy topic entry type: '{entry.Type}");
                // For the sake of brevity, we exclude printing "policy topic evidences"
                // and "policy topic constraints" here. You can fetch those data by
                // calling:
                // - entry.Evidences
                // - entry.Constraints
            }
        }
    }
    return ignorablePolicyTopics.ToArray();
}


PHP

private static function fetchIgnorablePolicyTopics(GoogleAdsException $googleAdsException)
{
    $ignorablePolicyTopics = [];

    printf("Google Ads failure details:%s", PHP_EOL);
    foreach ($googleAdsException->getGoogleAdsFailure()->getErrors() as $error) {
        /** @var GoogleAdsError $error */
        if ($error->getErrorCode()->getErrorCode() !== 'policy_finding_error') {
            // This example supports sending exemption request for the policy finding error
            // only.
            throw $googleAdsException;
        }

        printf(
            "\t%s: %s%s",
            $error->getErrorCode()->getErrorCode(),
            $error->getMessage(),
            PHP_EOL
        );
        if (
            !is_null($error->getDetails())
            && !is_null($error->getDetails()->getPolicyFindingDetails())
        ) {
            $policyFindingDetails = $error->getDetails()->getPolicyFindingDetails();
            printf("\tPolicy finding details:%s", PHP_EOL);

            foreach ($policyFindingDetails->getPolicyTopicEntries() as $policyTopicEntry) {
                /** @var PolicyTopicEntry $policyTopicEntry */
                $ignorablePolicyTopics[] = $policyTopicEntry->getTopic();
                printf(
                    "\t\tPolicy topic name: '%s'%s",
                    $policyTopicEntry->getTopic(),
                    PHP_EOL
                );
                printf(
                    "\t\tPolicy topic entry type: '%s'%s",
                    PolicyTopicEntryType::name($policyTopicEntry->getType()),
                    PHP_EOL
                );
                // For the sake of brevity, we exclude printing "policy topic evidences" and
                // "policy topic constraints" here. You can fetch those data by calling:
                // - $policyTopicEntry->getEvidences()
                // - $policyTopicEntry->getConstraints()
            }
        }
    }
    return $ignorablePolicyTopics;
}

Python

def _fetch_ignorable_policy_topics(client, google_ads_exception):
    """Collects all ignorable policy topics to be sent for exemption request.

    Args:
        client: The GoogleAds client instance.
        google_ads_exception: The exception that contains the policy
            violation(s).

    Returns:
        A list of ignorable policy topics.
    """
    ignorable_policy_topics = []

    print("Google Ads failure details:")
    for error in google_ads_exception.failure.errors:
        if (
            error.error_code.policy_finding_error
            != client.get_type(
                "PolicyFindingErrorEnum", version="v5"
            ).POLICY_FINDING
        ):
            print(
                "This example supports sending exemption request for the "
                "policy finding error only."
            )
            raise google_ads_exception

        print(f"\t{error.error_code.policy_finding_error}: {error.message}")

        if (
            error.details is not None
            and error.details.policy_finding_details is not None
        ):
            policy_finding_details = error.details.policy_finding_details
            print("\tPolicy finding details:")

            for (
                policy_topic_entry
            ) in policy_finding_details.policy_topic_entries:
                ignorable_policy_topics.append(policy_topic_entry.topic)
                print(f"\t\tPolicy topic name: '{policy_topic_entry.topic}'")
                print(
                    f"\t\tPolicy topic entry type: '{policy_topic_entry.type}'"
                )
                # For the sake of brevity, we exclude printing "policy topic
                # evidences" and "policy topic constraints" here. You can fetch
                # those data by calling:
                # - policy_topic_entry.evidences
                # - policy_topic_entry.constraints

    return ignorable_policy_topics

Ruby

def fetch_ignorable_policy_topics(exception)
  ignorable_policy_topics = []

  exception.failure.errors.each do |error|
    if error.error_code.policy_finding_error != :POLICY_FINDING
      puts "Non-policy finding error found. Aborting."
      raise exception
    end
    puts "#{error.error_code.policy_finding_error}: #{error.message}"

    error&.details&.policy_finding_details&.policy_topic_entries.each do |entry|
      ignorable_policy_topics << entry.topic
      puts "\tPolicy topic name: #{entry.topic}"
      puts "\tPolicy topic entry type: #{entry.type}"
    end
  end

  ignorable_policy_topics
end

Perl

sub fetch_ignorable_policy_topics {
  my $google_ads_exception = shift;

  my $ignorable_policy_topics = [];

  printf "Google Ads failure details:\n";
  foreach
    my $error (@{$google_ads_exception->get_google_ads_failure()->{errors}})
  {
    if ([keys %{$error->{errorCode}}]->[0] ne "policyFindingError") {
      # This example supports sending exemption request for the policy finding
      # error only.
      die $google_ads_exception->get_message();
    }

    printf "\t%s: %s\n", [keys %{$error->{errorCode}}]->[0], $error->{message};

    if ($error->{details}{policyFindingDetails}) {
      my $policy_finding_details = $error->{details}{policyFindingDetails};
      printf "\tPolicy finding details:\n";

      foreach my $policy_topic_entry (
        @{$policy_finding_details->{policyTopicEntries}})
      {
        push @$ignorable_policy_topics, $policy_topic_entry->{topic};
        printf
          "\t\tPolicy topic name: '%s'\n",
          $policy_topic_entry->{topic};
        printf "\t\tPolicy topic entry type: '%s'\n",
          $policy_topic_entry->{type};
        # For the sake of brevity, we exclude printing "policy topic evidences" and
        # "policy topic constraints" here. You can fetch those data by calling:
        # - $policy_topic_entry->{evidences}
        # - $policy_topic_entry->{constraints}
      }
    }
  }

  return $ignorable_policy_topics;
}

Send another mutate request by including ignorable policy topics

  1. Create an object of PolicyValidationParameter.
  2. Set stored ignorable policy topics to the ignorable_policy_topics field of the created PolicyValidationParameter.
  3. Set PolicyValidationParameter to the policy_validation_parameter field of an ad group ad operation.
  4. Send a mutate request for creating the ad group ad as usual.

Java

private void requestExemption(
    List<String> ignorablePolicyTopics,
    AdGroupAdServiceClient client,
    AdGroupAdOperation operation,
    long customerID) {
  System.out.println(
      "Trying to add an expanded text ad again by requesting exemption for its policy"
          + " violations.");
  // Converts the operation back to a builder.
  AdGroupAdOperation.Builder operationBuilder = operation.toBuilder();

  // Adds the exemption request.
  operationBuilder
      .getPolicyValidationParameterBuilder()
      .addAllIgnorablePolicyTopics(ignorablePolicyTopics);

  // Sends the request back to the API.
  MutateAdGroupAdsResponse response =
      client.mutateAdGroupAds(
          String.valueOf(customerID), ImmutableList.of(operationBuilder.build()));

  // Shows the newly added ad resource name.
  System.out.printf(
      "Successfully added an expanded text ad with resource name '%s' by requesting a policy"
          + " violation exemption.%n",
      response.getResults(0).getResourceName());
}

C#

private static void RequestExemption(long customerId, AdGroupAdServiceClient service,
    AdGroupAdOperation operation, string[] ignorablePolicyTopics)
{
    Console.WriteLine("Try adding an expanded text ad again by requesting exemption for " +
        "its policy violations.");
    PolicyValidationParameter validationParameter = new PolicyValidationParameter();
    validationParameter.IgnorablePolicyTopics.AddRange(ignorablePolicyTopics);
    operation.PolicyValidationParameter = validationParameter;

    MutateAdGroupAdsResponse response = service.MutateAdGroupAds(
        customerId.ToString(), new[] { operation });
    Console.WriteLine($"Successfully added an expanded text ad with resource name " +
        $"'{response.Results[0].ResourceName}' by requesting for policy violation " +
        $"exemption.");
}

PHP

private static function requestExemption(
    int $customerId,
    AdGroupAdServiceClient $adGroupAdServiceClient,
    AdGroupAdOperation $adGroupAdOperation,
    array $ignorablePolicyTopics
) {
    print "Try adding an expanded text ad again by requesting exemption for its policy"
        . " violations." . PHP_EOL;
    $adGroupAdOperation->setPolicyValidationParameter(
        new PolicyValidationParameter(['ignorable_policy_topics' => $ignorablePolicyTopics])
    );
    $response = $adGroupAdServiceClient->mutateAdGroupAds(
        $customerId,
        [$adGroupAdOperation]
    );
    printf(
        "Successfully added an expanded text ad with resource name '%s' by requesting"
        . " for policy violation exemption.%s",
        $response->getResults()[0]->getResourceName(),
        PHP_EOL
    );
}

Python

def _request_exemption(
    customer_id,
    ad_group_ad_service_client,
    ad_group_ad_operation,
    ignorable_policy_topics,
):
    """Sends exemption requests for creating an expanded text ad.

    Args:
        customer_id: The customer ID for which to add the expanded text ad.
        ad_group_ad_service_client: The AdGroupAdService client instance.
        ad_group_ad_operation: The AdGroupAdOperation that returned policy
            violation(s).
        ignorable_policy_topics: The extracted list of policy topic entries.
    """
    print(
        "Attempting to add an expanded text ad again by requesting exemption "
        "for its policy violations."
    )
    ad_group_ad_operation.policy_validation_parameter.ignorable_policy_topics.extend(
        ignorable_policy_topics
    )
    response = ad_group_ad_service_client.mutate_ad_group_ads(
        customer_id, [ad_group_ad_operation]
    )
    print(
        "Successfully added an expanded text ad with resource name "
        f"'{response.results[0].resource_name}' for policy violation "
        "exemption."
    )

Ruby

def request_exemption(
    client, customer_id, ad_group_ad_service, ad_group_ad_operation, ignorable_policy_topics)
  # Add all the found ignorable policy topics to the operation.
  ad_group_ad_operation.policy_validation_parameter =
      client.resource.policy_validation_parameter do |pvp|
    pvp.ignorable_policy_topics.push(
      *ignorable_policy_topics
    )
  end
  response = ad_group_ad_service.mutate_ad_group_ads(
    customer_id: customer_id,
    operations: [ad_group_ad_operation],
  )
  puts "Successfully added an expanded text ad with resource name " \
    "#{response.results.first.resource_name} for policy violation exception."
end

Perl

sub request_exemption {
  my ($api_client, $customer_id, $ad_group_ad_operation,
    $ignorable_policy_topics)
    = @_;

  print
    "Try adding an expanded text ad again by requesting exemption for its " .
    "policy violations.\n";

  $ad_group_ad_operation->{policyValidationParameter} =
    Google::Ads::GoogleAds::V5::Common::PolicyValidationParameter->new(
    {ignorablePolicyTopics => $ignorable_policy_topics});

  my $ad_group_ad_response = $api_client->AdGroupAdService()->mutate({
      customerId => $customer_id,
      operations => [$ad_group_ad_operation]});

  printf "Successfully added an expanded text ad with resource name '%s' by " .
    "requesting for policy violation exemption.\n",
    $ad_group_ad_response->{results}[0]{resourceName};
}

Code examples

The ErrorHandling folder of each client library contains the following code example that shows how to use this feature: