Add Ad Customizer

Java

// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.ads.googleads.examples.advancedoperations;

import static com.google.ads.googleads.examples.utils.CodeSampleHelper.getShortPrintableDateTime;

import com.beust.jcommander.Parameter;
import com.google.ads.googleads.examples.utils.ArgumentNames;
import com.google.ads.googleads.examples.utils.CodeSampleParams;
import com.google.ads.googleads.lib.GoogleAdsClient;
import com.google.ads.googleads.v7.common.ExpandedTextAdInfo;
import com.google.ads.googleads.v7.enums.AdCustomizerPlaceholderFieldEnum.AdCustomizerPlaceholderField;
import com.google.ads.googleads.v7.enums.FeedAttributeTypeEnum.FeedAttributeType;
import com.google.ads.googleads.v7.enums.PlaceholderTypeEnum.PlaceholderType;
import com.google.ads.googleads.v7.errors.GoogleAdsError;
import com.google.ads.googleads.v7.errors.GoogleAdsException;
import com.google.ads.googleads.v7.resources.Ad;
import com.google.ads.googleads.v7.resources.AdGroupAd;
import com.google.ads.googleads.v7.resources.AttributeFieldMapping;
import com.google.ads.googleads.v7.resources.Feed;
import com.google.ads.googleads.v7.resources.FeedAttribute;
import com.google.ads.googleads.v7.resources.FeedItem;
import com.google.ads.googleads.v7.resources.FeedItemAttributeValue;
import com.google.ads.googleads.v7.resources.FeedItemTarget;
import com.google.ads.googleads.v7.resources.FeedMapping;
import com.google.ads.googleads.v7.services.AdGroupAdOperation;
import com.google.ads.googleads.v7.services.AdGroupAdServiceClient;
import com.google.ads.googleads.v7.services.FeedItemOperation;
import com.google.ads.googleads.v7.services.FeedItemServiceClient;
import com.google.ads.googleads.v7.services.FeedItemTargetOperation;
import com.google.ads.googleads.v7.services.FeedItemTargetServiceClient;
import com.google.ads.googleads.v7.services.FeedMappingOperation;
import com.google.ads.googleads.v7.services.FeedMappingServiceClient;
import com.google.ads.googleads.v7.services.FeedOperation;
import com.google.ads.googleads.v7.services.FeedServiceClient;
import com.google.ads.googleads.v7.services.GoogleAdsServiceClient;
import com.google.ads.googleads.v7.services.GoogleAdsServiceClient.SearchPagedResponse;
import com.google.ads.googleads.v7.services.MutateAdGroupAdResult;
import com.google.ads.googleads.v7.services.MutateAdGroupAdsResponse;
import com.google.ads.googleads.v7.services.MutateFeedItemResult;
import com.google.ads.googleads.v7.services.MutateFeedItemTargetsResponse;
import com.google.ads.googleads.v7.services.MutateFeedItemsResponse;
import com.google.ads.googleads.v7.services.MutateFeedMappingsResponse;
import com.google.ads.googleads.v7.services.MutateFeedsResponse;
import com.google.ads.googleads.v7.services.SearchGoogleAdsRequest;
import com.google.ads.googleads.v7.utils.ResourceNames;
import com.google.common.collect.ImmutableList;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.joda.time.DateTime;

/**
 * Adds an ad customizer feed and associates it with the customer. Then it adds an ad that uses the
 * feed to populate dynamic data.
 */
public class AddAdCustomizer {

  // We're doing only searches by resource_name in this example, we can set page size = 1.
  private static final int PAGE_SIZE = 1;

  // We're creating two different ad groups to be dynamically populated by the same feed.
  private static final int NUMBER_OF_AD_GROUPS = 2;

  private static class AddAdCustomizerParams extends CodeSampleParams {

    @Parameter(names = ArgumentNames.CUSTOMER_ID, required = true)
    private Long customerId;

    @Parameter(names = ArgumentNames.AD_GROUP_IDS, required = true)
    private List<Long> adGroupIds;
  }

  public static void main(String[] args) throws IOException {
    AddAdCustomizerParams params = new AddAdCustomizerParams();
    if (!params.parseArguments(args)) {

      // Either pass the required parameters for this example on the command line, or insert them
      // into the code here. See the parameter class definition above for descriptions.
      params.customerId = Long.parseLong("INSERT_CUSTOMER_ID_HERE");
      params.adGroupIds =
          Arrays.asList(
              Long.parseLong("INSERT_AD_GROUP_ID_HERE"), Long.parseLong("INSERT_AD_GROUP_ID_HERE"));
    }

    GoogleAdsClient googleAdsClient = null;
    try {
      googleAdsClient = GoogleAdsClient.newBuilder().fromPropertiesFile().build();
    } catch (FileNotFoundException fnfe) {
      System.err.printf(
          "Failed to load GoogleAdsClient configuration from file. Exception: %s%n", fnfe);
      System.exit(1);
    } catch (IOException ioe) {
      System.err.printf("Failed to create GoogleAdsClient. Exception: %s%n", ioe);
      System.exit(1);
    }

    try {
      new AddAdCustomizer().runExample(googleAdsClient, params);
    } catch (GoogleAdsException gae) {
      // GoogleAdsException is the base class for most exceptions thrown by an API request.
      // Instances of this exception have a message and a GoogleAdsFailure that contains a
      // collection of GoogleAdsErrors that indicate the underlying causes of the
      // GoogleAdsException.
      System.err.printf(
          "Request ID %s failed due to GoogleAdsException. Underlying errors:%n",
          gae.getRequestId());
      int i = 0;
      for (GoogleAdsError googleAdsError : gae.getGoogleAdsFailure().getErrorsList()) {
        System.err.printf("  Error %d: %s%n", i++, googleAdsError);
      }
      System.exit(1);
    }
  }

  /**
   * Runs the example.
   *
   * @param googleAdsClient the Google Ads API client.
   * @param params the example parameters.
   * @throws GoogleAdsException if an API request failed with one or more service errors.
   */
  private void runExample(GoogleAdsClient googleAdsClient, AddAdCustomizerParams params) {

    if (params.adGroupIds.size() != NUMBER_OF_AD_GROUPS) {
      throw new IllegalArgumentException(
          "Please pass exactly two ad group IDs in the adGroupId parameter.");
    }

    String feedName = "Ad Customizer example feed " + getShortPrintableDateTime();

    // Create a feed to be used as the ad customizer.
    String adCustomizerFeedResourceName =
        createAdCustomizerFeed(googleAdsClient, params.customerId, feedName);

    // Retrieve the attributes for the newly created feed.
    Map<String, FeedAttribute> adCustomizerFeedAttributes =
        getFeedAttributes(googleAdsClient, params.customerId, adCustomizerFeedResourceName);

    // Map the feed to the ad customizer placeholder type to mark it as an ad customizer.
    createAdCustomizerMapping(
        googleAdsClient,
        params.customerId,
        adCustomizerFeedResourceName,
        adCustomizerFeedAttributes);

    // Create the feed items that will fill the placeholders in the ads customized by the feed.
    List<String> feedItemResourceNames =
        createFeedItems(
            googleAdsClient,
            params.customerId,
            adCustomizerFeedResourceName,
            adCustomizerFeedAttributes);

    // Create a feed item targeting to associate the feed items with specific ad groups to
    // prevent them from being used in other ways.
    createFeedItemTargets(
        googleAdsClient, params.customerId, params.adGroupIds, feedItemResourceNames);

    // Create ads with the customizations provided by the feed items.
    createAdsWithCustomizations(googleAdsClient, params.customerId, params.adGroupIds, feedName);
  }

  /**
   * Creates a feed to be used for ad customization.
   *
   * @param googleAdsClient the Google Ads API client.
   * @param customerId the client customer ID.
   * @param feedName the name of the feed to create.
   * @return the resource name of the newly created feed.
   */
  private String createAdCustomizerFeed(
      GoogleAdsClient googleAdsClient, long customerId, String feedName) {

    // Creates three feed attributes: a name, a price and a date. The attribute names are arbitrary
    // choices and will be used as placeholders in the ad text fields.
    FeedAttribute nameAttribute =
        FeedAttribute.newBuilder().setName("Name").setType(FeedAttributeType.STRING).build();

    FeedAttribute priceAttribute =
        FeedAttribute.newBuilder().setName("Price").setType(FeedAttributeType.STRING).build();

    FeedAttribute dateAttribute =
        FeedAttribute.newBuilder().setName("Date").setType(FeedAttributeType.DATE_TIME).build();

    Feed adCustomizerFeed =
        Feed.newBuilder()
            .setName(feedName)
            .addAttributes(nameAttribute)
            .addAttributes(priceAttribute)
            .addAttributes(dateAttribute)
            .build();

    FeedOperation feedOperation = FeedOperation.newBuilder().setCreate(adCustomizerFeed).build();

    try (FeedServiceClient feedServiceClient =
        googleAdsClient.getLatestVersion().createFeedServiceClient()) {

      MutateFeedsResponse response =
          feedServiceClient.mutateFeeds(Long.toString(customerId), ImmutableList.of(feedOperation));

      String feedResourceName = response.getResults(0).getResourceName();
      System.out.printf("Added feed with resource name %s.%n", feedResourceName);
      return feedResourceName;
    }
  }

  /**
   * Retrieves all the attributes for a feed and returns them in a map using the attribute names as
   * keys.
   *
   * @param googleAdsClient the Google Ads API client.
   * @param customerId the client customer ID.
   * @param feedResourceName the resource name of the feed.
   * @return the attributes of the feed.
   */
  private Map<String, FeedAttribute> getFeedAttributes(
      GoogleAdsClient googleAdsClient, long customerId, String feedResourceName) {
    String query =
        String.format(
            "SELECT feed.attributes, feed.name FROM feed WHERE feed.resource_name = '%s'",
            feedResourceName);

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

    Map<String, FeedAttribute> feedAttributes = new HashMap<>();
    try (GoogleAdsServiceClient googleAdsServiceClient =
        googleAdsClient.getLatestVersion().createGoogleAdsServiceClient()) {
      SearchPagedResponse searchPagedResponse = googleAdsServiceClient.search(request);

      Feed feed = searchPagedResponse.iterateAll().iterator().next().getFeed();

      System.out.printf(
          "Found the following attributes for feed with name '%s':%n", feed.getName());
      for (FeedAttribute feedAttribute : feed.getAttributesList()) {
        System.out.printf(
            "\t'%s' with id %d and type '%s'%n",
            feedAttribute.getName(), feedAttribute.getId(), feedAttribute.getType());
        feedAttributes.put(feedAttribute.getName(), feedAttribute);
      }
    }
    return feedAttributes;
  }

  /**
   * Creates a feed mapping and sets the feed as an ad customizer feed.
   *
   * @param googleAdsClient the Google Ads API client.
   * @param customerId the client customer ID.
   * @param feedResourceName the resource name of the feed.
   * @param feedAttributes the attributes of the feed.
   */
  private void createAdCustomizerMapping(
      GoogleAdsClient googleAdsClient,
      long customerId,
      String feedResourceName,
      Map<String, FeedAttribute> feedAttributes) {

    // Map the feed attributes to ad customizer placeholder fields.
    // For a full list of ad customizer placeholder fields, see
    // https://developers.google.com/google-ads/api/reference/rpc/latest/AdCustomizerPlaceholderFieldEnum.AdCustomizerPlaceholderField
    AttributeFieldMapping nameFieldMapping =
        AttributeFieldMapping.newBuilder()
            .setFeedAttributeId(feedAttributes.get("Name").getId())
            .setAdCustomizerField(AdCustomizerPlaceholderField.STRING)
            .build();

    AttributeFieldMapping priceFieldMapping =
        AttributeFieldMapping.newBuilder()
            .setFeedAttributeId(feedAttributes.get("Price").getId())
            .setAdCustomizerField(AdCustomizerPlaceholderField.PRICE)
            .build();

    AttributeFieldMapping dateFieldMapping =
        AttributeFieldMapping.newBuilder()
            .setFeedAttributeId(feedAttributes.get("Date").getId())
            .setAdCustomizerField(AdCustomizerPlaceholderField.DATE)
            .build();

    FeedMapping feedMapping =
        FeedMapping.newBuilder()
            .setFeed(feedResourceName)
            // Sets the feed to the AD_CUSTOMIZER placeholder type.
            .setPlaceholderType(PlaceholderType.AD_CUSTOMIZER)
            .addAttributeFieldMappings(nameFieldMapping)
            .addAttributeFieldMappings(priceFieldMapping)
            .addAttributeFieldMappings(dateFieldMapping)
            .build();

    FeedMappingOperation feedMappingOperation =
        FeedMappingOperation.newBuilder().setCreate(feedMapping).build();

    try (FeedMappingServiceClient feedMappingServiceClient =
        googleAdsClient.getLatestVersion().createFeedMappingServiceClient()) {

      MutateFeedMappingsResponse response =
          feedMappingServiceClient.mutateFeedMappings(
              Long.toString(customerId), ImmutableList.of(feedMappingOperation));

      System.out.printf(
          "Added feed mapping with resource name %s.%n", response.getResults(0).getResourceName());
    }
  }

  /**
   * Creates two different feed items to enable two different ad customizations.
   *
   * @param googleAdsClient the Google Ads API client.
   * @param customerId the client customer ID.
   * @param feedResourceName the resource name of the feed.
   * @param feedAttributes the attributes of the feed.
   * @return the resource names of the feed items.
   */
  private List<String> createFeedItems(
      GoogleAdsClient googleAdsClient,
      long customerId,
      String feedResourceName,
      Map<String, FeedAttribute> feedAttributes) {

    List<FeedItemOperation> feedItemOperations = new ArrayList<>();

    DateTime marsDate = DateTime.now().withDayOfMonth(1).withHourOfDay(0).withMinuteOfHour(0);
    feedItemOperations.add(
        createFeedItemOperation(
            "Mars",
            "$1234.56",
            marsDate.toString("yyyyMMdd HHmmss"),
            feedResourceName,
            feedAttributes));

    DateTime venusDate = DateTime.now().withDayOfMonth(15).withHourOfDay(0).withMinuteOfHour(0);
    feedItemOperations.add(
        createFeedItemOperation(
            "Venus",
            "$1450.00",
            venusDate.toString("yyyyMMdd HHmmss"),
            feedResourceName,
            feedAttributes));

    try (FeedItemServiceClient feedItemServiceClient =
        googleAdsClient.getLatestVersion().createFeedItemServiceClient()) {
      List<String> feedItemResourceNames = new ArrayList<>();
      MutateFeedItemsResponse response =
          feedItemServiceClient.mutateFeedItems(Long.toString(customerId), feedItemOperations);

      System.out.printf("Added %d feed items:%n", response.getResultsCount());

      for (MutateFeedItemResult result : response.getResultsList()) {
        String feedItemResourceName = result.getResourceName();
        feedItemResourceNames.add(feedItemResourceName);
        System.out.printf("Added feed item with resource name %s.%n", feedItemResourceName);
      }
      return feedItemResourceNames;
    }
  }

  /**
   * Helper function to create a FeedItemOperation.
   *
   * @param name the value of the Name attribute.
   * @param price the value of the Price attribute.
   * @param date the value of the Date attribute.
   * @param feedResourceName the resource name of the feed.
   * @param feedAttributes the attributes to be set on the feed.
   * @return a FeedItemOperation to create a feed item.
   */
  private FeedItemOperation createFeedItemOperation(
      String name,
      String price,
      String date,
      String feedResourceName,
      Map<String, FeedAttribute> feedAttributes) {
    FeedItemAttributeValue nameAttributeValue =
        FeedItemAttributeValue.newBuilder()
            .setFeedAttributeId(feedAttributes.get("Name").getId())
            .setStringValue(name)
            .build();

    FeedItemAttributeValue priceAttributeValue =
        FeedItemAttributeValue.newBuilder()
            .setFeedAttributeId(feedAttributes.get("Price").getId())
            .setStringValue(price)
            .build();

    FeedItemAttributeValue dateAttributeValue =
        FeedItemAttributeValue.newBuilder()
            .setFeedAttributeId(feedAttributes.get("Date").getId())
            .setStringValue(date)
            .build();

    FeedItem feedItem =
        FeedItem.newBuilder()
            .setFeed(feedResourceName)
            .addAttributeValues(nameAttributeValue)
            .addAttributeValues(priceAttributeValue)
            .addAttributeValues(dateAttributeValue)
            .build();

    return FeedItemOperation.newBuilder().setCreate(feedItem).build();
  }

  /**
   * Restricts the feed items to work only with a specific ad group; this prevents the feed items
   * from being used elsewhere and makes sure they are used only for customizing a specific ad
   * group.
   *
   * @param googleAdsClient the Google Ads API client.
   * @param customerId the client customer ID.
   * @param adGroupIds the ad group IDs to bind the feed items to.
   * @param feedItemResourceNames the resource names of the feed items.
   */
  private void createFeedItemTargets(
      GoogleAdsClient googleAdsClient,
      long customerId,
      List<Long> adGroupIds,
      List<String> feedItemResourceNames) {

    // Bind each feed item to a specific ad group to make sure it will only be used to customize
    // ads inside that ad group; using the feed item elsewhere will result in an error.
    for (int i = 0; i < feedItemResourceNames.size(); i++) {
      String feedItemResourceName = feedItemResourceNames.get(i);
      Long adGroupId = adGroupIds.get(i);

      FeedItemTarget feedItemTarget =
          FeedItemTarget.newBuilder()
              .setAdGroup(ResourceNames.adGroup(customerId, adGroupId))
              .setFeedItem(feedItemResourceName)
              .build();

      FeedItemTargetOperation feedItemTargetOperation =
          FeedItemTargetOperation.newBuilder().setCreate(feedItemTarget).build();

      try (FeedItemTargetServiceClient feedItemTargetServiceClient =
          googleAdsClient.getLatestVersion().createFeedItemTargetServiceClient()) {

        MutateFeedItemTargetsResponse response =
            feedItemTargetServiceClient.mutateFeedItemTargets(
                Long.toString(customerId), ImmutableList.of(feedItemTargetOperation));

        String feedItemTargetResourceName = response.getResults(0).getResourceName();
        System.out.printf(
            "Added feed item target with resource name '%s'.%n", feedItemTargetResourceName);
      }
    }
  }

  /**
   * Creates expanded text ads that use the ad customizer feed to populate the placeholders.
   *
   * @param googleAdsClient the Google Ads API client.
   * @param customerId the client customer ID.
   * @param adGroupIds the ad group IDs in which to create the ads.
   * @param feedName the name of the feed.
   */
  private void createAdsWithCustomizations(
      GoogleAdsClient googleAdsClient, long customerId, List<Long> adGroupIds, String feedName) {

    // Creates an expanded text ad using the feed attribute names as placeholders.
    ExpandedTextAdInfo expandedTextAdInfo =
        ExpandedTextAdInfo.newBuilder()
            .setHeadlinePart1(String.format("Luxury cruise to {=%s.Name}", feedName))
            .setHeadlinePart2(String.format("Only {=%s.Price}", feedName))
            .setDescription(String.format("Offer ends in {=countdown(%s.Date)}!", feedName))
            .build();

    Ad ad =
        Ad.newBuilder()
            .setExpandedTextAd(expandedTextAdInfo)
            .addFinalUrls("http://www.example.com")
            .build();

    List<AdGroupAdOperation> adGroupAdOperations = new ArrayList<>();

    // Creates the same ad in all ad groups. When they serve, they will show different values,
    // since they match different feed items.
    for (Long adGroupId : adGroupIds) {
      AdGroupAd adGroupAd =
          AdGroupAd.newBuilder()
              .setAd(ad)
              .setAdGroup(ResourceNames.adGroup(customerId, adGroupId))
              .build();

      AdGroupAdOperation adGroupAdOperation =
          AdGroupAdOperation.newBuilder().setCreate(adGroupAd).build();

      adGroupAdOperations.add(adGroupAdOperation);
    }

    try (AdGroupAdServiceClient adGroupAdServiceClient =
        googleAdsClient.getLatestVersion().createAdGroupAdServiceClient()) {

      MutateAdGroupAdsResponse response =
          adGroupAdServiceClient.mutateAdGroupAds(Long.toString(customerId), adGroupAdOperations);

      System.out.printf("Added %d ads:%n", response.getResultsCount());
      for (MutateAdGroupAdResult result : response.getResultsList()) {
        System.out.printf("Added an ad with resource name '%s'.%n", result.getResourceName());
      }
    }
  }
}

      

C#

// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Google.Ads.GoogleAds.Lib;
using Google.Ads.GoogleAds.V7.Common;
using Google.Ads.GoogleAds.V7.Errors;
using Google.Ads.GoogleAds.V7.Resources;
using Google.Ads.GoogleAds.V7.Services;

using System;
using System.Collections.Generic;
using System.Linq;
using static Google.Ads.GoogleAds.V7.Enums.AdCustomizerPlaceholderFieldEnum.Types;
using static Google.Ads.GoogleAds.V7.Enums.FeedAttributeTypeEnum.Types;
using static Google.Ads.GoogleAds.V7.Enums.PlaceholderTypeEnum.Types;

namespace Google.Ads.GoogleAds.Examples.V7
{
    /// <summary>
    /// This code example adds an ad customizer feed and associates it with the customer.
    /// Then it adds an ad that uses the feed to populate dynamic data.
    /// </summary>
    public class AddAdCustomizer : ExampleBase
    {
        /// <summary>
        /// Main method, to run this code example as a standalone application.
        /// </summary>
        /// <param name="args">The command line arguments.</param>
        public static void Main(string[] args)
        {
            AddAdCustomizer codeExample = new AddAdCustomizer();
            Console.WriteLine(codeExample.Description);

            // The Google Ads customer ID for which the call is made.
            long customerId = long.Parse("INSERT_CUSTOMER_ID_HERE");

            // ID of the ad groups to which ads are added.
            long[] adGroupIds = new[]
            {
                long.Parse("INSERT_AD_GROUP_ID_HERE"),
                long.Parse("INSERT_AD_GROUP_ID_HERE"),
            };

            codeExample.Run(new GoogleAdsClient(), customerId, adGroupIds);
        }

        /// <summary>
        /// Returns a description about the code example.
        /// </summary>
        public override string Description =>
            "This code example adds an ad customizer feed and associates it with the customer. " +
            "Then it adds an ad that uses the feed to populate dynamic data.";

        /// <summary>
        /// Runs the code example.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The Google Ads customer ID for which the call is made.</param>
        /// <param name="adGroupIds">ID of the ad groups to which ad customizers are added.</param>
        public void Run(GoogleAdsClient client, long customerId, long[] adGroupIds)
        {
            // Get the AdGroupBidModifierService.
            AdGroupBidModifierServiceClient adGroupBidModifierService =
                client.GetService(Services.V7.AdGroupBidModifierService);

            string feedName = "Ad_Customizer_example_feed_" + ExampleUtilities.GetShortRandomString();

            try
            {
                // Create a feed to be used as the ad customizer.
                string adCustomizerFeedResourceName =
                    CreateAdCustomizerFeed(client, customerId, feedName);

                // Retrieve the attributes for the newly created feed.
                Dictionary<string, FeedAttribute> adCustomizerFeedAttributes =
                    GetFeedAttributes(client, customerId, adCustomizerFeedResourceName);

                // Map the feed to the ad customizer placeholder type to mark it as an
                // ad customizer.
                CreateAdCustomizerMapping(client, customerId, adCustomizerFeedResourceName,
                    adCustomizerFeedAttributes);

                // Create the feed items that will fill the placeholders in the ads customized by
                // the feed.
                List<string> feedItemResourceNames = CreateFeedItems(client, customerId,
                    adCustomizerFeedResourceName, adCustomizerFeedAttributes);

                // Create a feed item targeting to associate the feed items with specific
                // ad groups to prevent them from being used in other ways.
                CreateFeedItemTargets(client, customerId, adGroupIds, feedItemResourceNames);

                // Create ads with the customizations provided by the feed items.
                CreateAdsWithCustomizations(client, customerId, adGroupIds, feedName);
            }
            catch (GoogleAdsException e)
            {
                Console.WriteLine("Failure:");
                Console.WriteLine($"Message: {e.Message}");
                Console.WriteLine($"Failure: {e.Failure}");
                Console.WriteLine($"Request ID: {e.RequestId}");
                throw;
            }

        }

        /// <summary>
        /// Creates a feed to be used for ad customization.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The Google Ads customer ID for which the call is made.</param>
        /// <param name="feedName">Name of the feed.</param>
        /// <returns>The resource name of the newly created feed.</returns>
        private string CreateAdCustomizerFeed(GoogleAdsClient client, long customerId,
            string feedName)
        {
            // Get the FeedServiceClient.
            FeedServiceClient feedService = client.GetService(Services.V7.FeedService);

            // Creates three feed attributes: a name, a price and a date. The attribute names
            // are arbitrary choices and will be used as placeholders in the ad text fields.
            FeedAttribute nameAttribute = new FeedAttribute()
            {
                Name = "Name",
                Type = FeedAttributeType.String
            };

            FeedAttribute priceAttribute = new FeedAttribute()
            {
                Name = "Price",
                Type = FeedAttributeType.String
            };

            FeedAttribute dateAttribute = new FeedAttribute()
            {
                Name = "Date",
                Type = FeedAttributeType.DateTime
            };

            Feed adCustomizerFeed = new Feed()
            {
                Name = feedName,
                Attributes = { nameAttribute, priceAttribute, dateAttribute }
            };

            FeedOperation feedOperation = new FeedOperation()
            {
                Create = adCustomizerFeed
            };

            MutateFeedsResponse response =
                feedService.MutateFeeds(customerId.ToString(), new[] { feedOperation });

            string feedResourceName = response.Results[0].ResourceName;
            Console.WriteLine($"Added feed with resource name '{feedResourceName}'.");
            return feedResourceName;
        }

        /// <summary>
        ///  Retrieves all the attributes for a feed and returns them in a map using the
        ///  attribute names as keys.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The Google Ads customer ID for which the call is made.</param>
        /// <param name="feedResourceName">The resource name of the feed.</param>
        /// <returns>The attributes of the feed.</returns>
        private Dictionary<string, FeedAttribute> GetFeedAttributes(GoogleAdsClient client,
                    long customerId, string feedResourceName)
        {
            // Get the GoogleAdsServiceClient.
            GoogleAdsServiceClient googleAdsService =
                client.GetService(Services.V7.GoogleAdsService);

            string query = $"SELECT feed.attributes, feed.name FROM feed WHERE " +
                $"feed.resource_name = '{feedResourceName}'";

            SearchGoogleAdsRequest request = new SearchGoogleAdsRequest()
            {
                CustomerId = customerId.ToString(),
                Query = query
            };

            Dictionary<string, FeedAttribute> feedAttributes =
                new Dictionary<string, FeedAttribute>();

            Feed feed = googleAdsService.Search(request).First().Feed;

            Console.WriteLine($"Found the following attributes for feed with name '{feed.Name}'");
            foreach (FeedAttribute feedAttribute in feed.Attributes)
            {
                Console.WriteLine($"\t'{feedAttribute.Name}' with id {feedAttribute.Id} and " +
                    $"type '{feedAttribute.Type}'");
                feedAttributes[feedAttribute.Name] = feedAttribute;
            }
            return feedAttributes;
        }

        /// <summary>
        /// Creates a feed mapping and sets the feed as an ad customizer feed.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The Google Ads customer ID for which the call is made.</param>
        /// <param name="feedResourceName">The resource name of the feed.</param>
        /// <param name="feedAttributes">The attributes of the feed.</param>
        private void CreateAdCustomizerMapping(GoogleAdsClient client, long customerId,
                    string feedResourceName, Dictionary<string, FeedAttribute> feedAttributes)
        {
            // Get the FeedMappingService.
            FeedMappingServiceClient feedMappingService =
                client.GetService(Services.V7.FeedMappingService);

            // Map the feed attributes to ad customizer placeholder fields.
            // For a full list of ad customizer placeholder fields, see
            // https://developers.google.com/google-ads/api/reference/rpc/latest/AdCustomizerPlaceholderFieldEnum.AdCustomizerPlaceholderField
            AttributeFieldMapping nameFieldMapping = new AttributeFieldMapping()
            {
                FeedAttributeId = feedAttributes["Name"].Id,
                AdCustomizerField = AdCustomizerPlaceholderField.String
            };

            AttributeFieldMapping priceFieldMapping = new AttributeFieldMapping()
            {
                FeedAttributeId = feedAttributes["Price"].Id,
                AdCustomizerField = AdCustomizerPlaceholderField.Price
            };

            AttributeFieldMapping dateFieldMapping = new AttributeFieldMapping()
            {
                FeedAttributeId = feedAttributes["Date"].Id,
                AdCustomizerField = AdCustomizerPlaceholderField.Date
            };

            FeedMapping feedMapping = new FeedMapping()
            {
                Feed = feedResourceName,
                PlaceholderType = PlaceholderType.AdCustomizer,
                AttributeFieldMappings = { nameFieldMapping, priceFieldMapping, dateFieldMapping }
            };

            FeedMappingOperation operation = new FeedMappingOperation()
            {
                Create = feedMapping
            };

            MutateFeedMappingsResponse response =
                feedMappingService.MutateFeedMappings(customerId.ToString(), new[] { operation });

            Console.WriteLine($"Added feed mapping with resource name" +
                $" '{response.Results[0].ResourceName}'.");
        }

        /// <summary>
        /// Creates two different feed items to enable two different ad customizations.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The Google Ads customer ID for which the call is made.</param>
        /// <param name="feedResourceName">The resource name of the feed.</param>
        /// <param name="feedAttributes">The attributes of the feed.</param>
        /// <returns>The resource names of the feed items.</returns>
        private List<string> CreateFeedItems(GoogleAdsClient client, long customerId,
                    string feedResourceName, Dictionary<string, FeedAttribute> feedAttributes)
        {
            // Get the FeedItemServiceClient.
            FeedItemServiceClient feedItemService =
                client.GetService(Services.V7.FeedItemService);

            List<FeedItemOperation> feedItemOperations = new List<FeedItemOperation>();

            DateTime marsDate = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
            feedItemOperations.Add(
                CreateFeedItemOperation("Mars", "$1234.56", marsDate.ToString("yyyyMMdd HHmmss"),
                    feedResourceName, feedAttributes));

            DateTime venusDate = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 15);
            feedItemOperations.Add(
                CreateFeedItemOperation("Venus", "$1450.00", venusDate.ToString("yyyyMMdd HHmmss"),
                    feedResourceName, feedAttributes));

            List<string> feedItemResourceNames = new List<string>();
            MutateFeedItemsResponse response =
                feedItemService.MutateFeedItems(customerId.ToString(), feedItemOperations);

            Console.WriteLine($"Added {response.Results.Count} feed items:");

            foreach (MutateFeedItemResult result in response.Results)
            {
                string feedItemResourceName = result.ResourceName;
                feedItemResourceNames.Add(feedItemResourceName);
                Console.WriteLine($"Added feed item with resource name '{feedItemResourceName}'.");
            }
            return feedItemResourceNames;
        }

        /// <summary>
        /// Helper function to create a FeedItemOperation.
        /// </summary>
        /// <param name="name">The value of the Name attribute.</param>
        /// <param name="price">The value of the Price attribute.</param>
        /// <param name="date">The value of the Date attribute.</param>
        /// <param name="feedResourceName">The resource name of the feed.</param>
        /// <param name="feedAttributes">The attributes to be set on the feed.</param>
        /// <returns>A FeedItemOperation to create a feed item.</returns>
        private FeedItemOperation CreateFeedItemOperation(string name, string price, string date,
                    string feedResourceName, Dictionary<string, FeedAttribute> feedAttributes)
        {
            FeedItemAttributeValue nameAttributeValue = new FeedItemAttributeValue()
            {
                FeedAttributeId = feedAttributes["Name"].Id,
                StringValue = name
            };

            FeedItemAttributeValue priceAttributeValue = new FeedItemAttributeValue()
            {
                FeedAttributeId = feedAttributes["Price"].Id,
                StringValue = price
            };

            FeedItemAttributeValue dateAttributeValue = new FeedItemAttributeValue()
            {
                FeedAttributeId = feedAttributes["Date"].Id,
                StringValue = date
            };

            FeedItem feedItem = new FeedItem()
            {
                Feed = feedResourceName,
                AttributeValues = { nameAttributeValue, priceAttributeValue, dateAttributeValue }
            };

            return new FeedItemOperation()
            {
                Create = feedItem
            };
        }

        /// <summary>
        /// Restricts the feed items to work only with a specific ad group; this prevents the
        /// feed items from being used elsewhere and makes sure they are used only for
        /// customizing a specific ad group.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The Google Ads customer ID for which the call is made.</param>
        /// <param name="adGroupIds">The ad group IDs to bind the feed items to..</param>
        /// <param name="feedItemResourceNames">The resource names of the feed items.</param>
        private void CreateFeedItemTargets(GoogleAdsClient client,
                    long customerId, long[] adGroupIds, List<string> feedItemResourceNames)
        {
            // Get the FeedItemTargetServiceClient.
            FeedItemTargetServiceClient feedItemTargetService =
                client.GetService(Services.V7.FeedItemTargetService);

            // Bind each feed item to a specific ad group to make sure it will only be used to
            // customize ads inside that ad group; using the feed item elsewhere will result
            // in an error.
            for (int i = 0; i < feedItemResourceNames.Count; i++)
            {
                string feedItemResourceName = feedItemResourceNames[i];
                long adGroupId = adGroupIds[i];

                FeedItemTarget feedItemTarget = new FeedItemTarget()
                {
                    AdGroup = ResourceNames.AdGroup(customerId, adGroupId),
                    FeedItem = feedItemResourceName
                };

                FeedItemTargetOperation feedItemTargetOperation = new FeedItemTargetOperation()
                {
                    Create = feedItemTarget
                };

                MutateFeedItemTargetsResponse response =
                    feedItemTargetService.MutateFeedItemTargets(customerId.ToString(),
                        new[] { feedItemTargetOperation });

                string feedItemTargetResourceName = response.Results[0].ResourceName;
                Console.WriteLine($"Added feed item target with resource name " +
                    $"'{response.Results[0].ResourceName}'.");
            }
        }

        /// <summary>
        /// Creates expanded text ads that use the ad customizer feed to populate the placeholders.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The Google Ads customer ID for which the call is made.</param>
        /// <param name="adGroupIds">The ad group IDs in which to create the ads.</param>
        /// <param name="feedName">Name of the feed.</param>
        private void CreateAdsWithCustomizations(GoogleAdsClient client, long customerId,
                    long[] adGroupIds, string feedName)
        {
            // Get the AdGroupAdServiceClient.
            AdGroupAdServiceClient adGroupAdService =
                client.GetService(Services.V7.AdGroupAdService);


            // Creates an expanded text ad using the feed attribute names as placeholders.
            Ad ad = new Ad()
            {
                ExpandedTextAd = new ExpandedTextAdInfo()
                {
                    HeadlinePart1 = $"Luxury cruise to {{={feedName}.Name}}",
                    HeadlinePart2 = $"Only {{={feedName}.Price}}",
                    Description = $"Offer ends in {{=countdown({feedName}.Date)}}!"
                },
                FinalUrls = { "http://www.example.com" }
            };

            List<AdGroupAdOperation> adGroupAdOperations = new List<AdGroupAdOperation>();

            // Creates the same ad in all ad groups. When they serve, they will show
            // different values, since they match different feed items.
            foreach (long adGroupId in adGroupIds)
            {
                AdGroupAd adGroupAd = new AdGroupAd()
                {
                    Ad = ad,
                    AdGroup = ResourceNames.AdGroup(customerId, adGroupId)
                };

                adGroupAdOperations.Add(new AdGroupAdOperation()
                {
                    Create = adGroupAd
                });
            }

            MutateAdGroupAdsResponse response =
                adGroupAdService.MutateAdGroupAds(customerId.ToString(), adGroupAdOperations);

            Console.WriteLine($"Added {response.Results.Count} ads:");
            foreach (MutateAdGroupAdResult result in response.Results)
            {
                Console.WriteLine($"Added an ad with resource name '{result.ResourceName}'.");
            }
        }
    }
}

      

PHP

<?php

/**
 * Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace Google\Ads\GoogleAds\Examples\AdvancedOperations;

require __DIR__ . '/../../vendor/autoload.php';

use DateTime;
use GetOpt\GetOpt;
use Google\Ads\GoogleAds\Examples\Utils\ArgumentNames;
use Google\Ads\GoogleAds\Examples\Utils\ArgumentParser;
use Google\Ads\GoogleAds\Examples\Utils\Helper;
use Google\Ads\GoogleAds\Lib\OAuth2TokenBuilder;
use Google\Ads\GoogleAds\Lib\V7\GoogleAdsClient;
use Google\Ads\GoogleAds\Lib\V7\GoogleAdsClientBuilder;
use Google\Ads\GoogleAds\Lib\V7\GoogleAdsException;
use Google\Ads\GoogleAds\Util\V7\ResourceNames;
use Google\Ads\GoogleAds\V7\Common\ExpandedTextAdInfo;
use Google\Ads\GoogleAds\V7\Enums\AdCustomizerPlaceholderFieldEnum\AdCustomizerPlaceholderField;
use Google\Ads\GoogleAds\V7\Enums\FeedAttributeTypeEnum\FeedAttributeType;
use Google\Ads\GoogleAds\V7\Enums\FeedOriginEnum\FeedOrigin;
use Google\Ads\GoogleAds\V7\Enums\PlaceholderTypeEnum\PlaceholderType;
use Google\Ads\GoogleAds\V7\Errors\GoogleAdsError;
use Google\Ads\GoogleAds\V7\Resources\Ad;
use Google\Ads\GoogleAds\V7\Resources\AdGroupAd;
use Google\Ads\GoogleAds\V7\Resources\AttributeFieldMapping;
use Google\Ads\GoogleAds\V7\Resources\Feed;
use Google\Ads\GoogleAds\V7\Resources\FeedAttribute;
use Google\Ads\GoogleAds\V7\Resources\FeedItem;
use Google\Ads\GoogleAds\V7\Resources\FeedItemAttributeValue;
use Google\Ads\GoogleAds\V7\Resources\FeedItemTarget;
use Google\Ads\GoogleAds\V7\Resources\FeedMapping;
use Google\Ads\GoogleAds\V7\Services\AdGroupAdOperation;
use Google\Ads\GoogleAds\V7\Services\FeedItemOperation;
use Google\Ads\GoogleAds\V7\Services\FeedItemTargetOperation;
use Google\Ads\GoogleAds\V7\Services\FeedMappingOperation;
use Google\Ads\GoogleAds\V7\Services\FeedOperation;
use Google\ApiCore\ApiException;

/**
 * Adds an ad customizer feed and associates it with the customer. Then it adds an ad that uses the
 * feed to populate dynamic data.
 */
class AddAdCustomizer
{
    private const CUSTOMER_ID = 'INSERT_CUSTOMER_ID_HERE';
    private const AD_GROUP_ID_1 = 'INSERT_AD_GROUP_ID_1_HERE';
    private const AD_GROUP_ID_2 = 'INSERT_AD_GROUP_ID_2_HERE';

    // We're creating two different ad groups to be dynamically populated by the same feed.
    private const NUMBER_OF_AD_GROUPS = 2;

    // We're doing only searches by resource_name in this example, we can set page size = 1.
    private const PAGE_SIZE = 1;

    public static function main()
    {
        // Either pass the required parameters for this example on the command line, or insert them
        // into the constants above.
        $options = (new ArgumentParser())->parseCommandArguments([
            ArgumentNames::CUSTOMER_ID => GetOpt::REQUIRED_ARGUMENT,
            ArgumentNames::AD_GROUP_IDS => GetOpt::MULTIPLE_ARGUMENT
        ]);

        // Generate a refreshable OAuth2 credential for authentication.
        $oAuth2Credential = (new OAuth2TokenBuilder())->fromFile()->build();

        // Construct a Google Ads client configured from a properties file and the
        // OAuth2 credentials above.
        $googleAdsClient = (new GoogleAdsClientBuilder())->fromFile()
            ->withOAuth2Credential($oAuth2Credential)
            ->build();

        try {
            self::runExample(
                $googleAdsClient,
                $options[ArgumentNames::CUSTOMER_ID] ?: self::CUSTOMER_ID,
                $options[ArgumentNames::AD_GROUP_IDS] ?: [self::AD_GROUP_ID_1, self::AD_GROUP_ID_2]
            );
        } catch (GoogleAdsException $googleAdsException) {
            printf(
                "Request with ID '%s' has failed.%sGoogle Ads failure details:%s",
                $googleAdsException->getRequestId(),
                PHP_EOL,
                PHP_EOL
            );
            foreach ($googleAdsException->getGoogleAdsFailure()->getErrors() as $error) {
                /** @var GoogleAdsError $error */
                printf(
                    "\t%s: %s%s",
                    $error->getErrorCode()->getErrorCode(),
                    $error->getMessage(),
                    PHP_EOL
                );
            }
            exit(1);
        } catch (ApiException $apiException) {
            printf(
                "ApiException was thrown with message '%s'.%s",
                $apiException->getMessage(),
                PHP_EOL
            );
            exit(1);
        }
    }

    /**
     * Runs the example.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @param array $adGroupIds the ad group IDs
     */
    public static function runExample(
        GoogleAdsClient $googleAdsClient,
        int $customerId,
        array $adGroupIds
    ) {
        if (count($adGroupIds) != self::NUMBER_OF_AD_GROUPS) {
            throw new \InvalidArgumentException(
                'Please pass exactly ' . self::NUMBER_OF_AD_GROUPS .
                ' ad group IDs in the adGroupIds parameter.'
            );
        }

        $feedName = 'Ad Customizer example feed ' . Helper::getShortPrintableDatetime();

        // Create a feed to be used for ad customization.
        $adCustomizerFeedResourceName = self::createAdCustomizerFeed(
            $googleAdsClient,
            $customerId,
            $feedName
        );

        // Retrieve the attributes of the feed.
        $adCustomizerFeedAttributes = self::getFeedAttributes(
            $googleAdsClient,
            $customerId,
            $adCustomizerFeedResourceName
        );

        // Map the feed to the ad customizer placeholder fields.
        self::createAdCustomizerMapping(
            $googleAdsClient,
            $customerId,
            $adCustomizerFeedResourceName,
            $adCustomizerFeedAttributes
        );

        // Create feed items to be used to customize ads.
        $feedItemResourceNames = self::createFeedItems(
            $googleAdsClient,
            $customerId,
            $adCustomizerFeedResourceName,
            $adCustomizerFeedAttributes
        );

        // Set the feed to be used only with the specified ad groups.
        self::createFeedItemTargets(
            $googleAdsClient,
            $customerId,
            $adGroupIds,
            $feedItemResourceNames
        );

        // Create ads that use the feed for customization.
        self::createAdsWithCustomizations(
            $googleAdsClient,
            $customerId,
            $adGroupIds,
            $feedName
        );
    }

   /**
    * Creates a feed to be used for ad customization.
    *
    * @param GoogleAdsClient $googleAdsClient the Google Ads API client
    * @param int $customerId the customer ID in which to create the feed
    * @param string $feedName the name of the feed to create
    * @return string the resource name of the newly created feed
    */
    private static function createAdCustomizerFeed(
        GoogleAdsClient $googleAdsClient,
        int $customerId,
        string $feedName
    ) {
        // Creates three feed attributes: a name, a price and a date. The attribute names are
        // arbitrary choices and will be used as placeholders in the ad text fields.
        $nameAttribute = new FeedAttribute(['type' => FeedAttributeType::STRING, 'name' => 'Name']);
        $priceAttribute =
            new FeedAttribute(['type' => FeedAttributeType::STRING, 'name' => 'Price']);
        $dateAttribute =
            new FeedAttribute(['type' => FeedAttributeType::DATE_TIME, 'name' => 'Date']);

        // Creates the feed.
        $feed = new Feed([
            'name' => $feedName,
            'attributes' => [$nameAttribute, $priceAttribute, $dateAttribute],
            'origin' => FeedOrigin::USER
        ]);

        // Creates a feed operation for creating a feed.
        $feedOperation = new FeedOperation();
        $feedOperation->setCreate($feed);

        // Issues a mutate request to add the feed.
        $feedServiceClient = $googleAdsClient->getFeedServiceClient();
        $feedResponse = $feedServiceClient->mutateFeeds($customerId, [$feedOperation]);

        $feedResourceName = $feedResponse->getResults()[0]->getResourceName();
        printf("Added feed with resource name '%s'.%s", $feedResourceName, PHP_EOL);

        return $feedResourceName;
    }

    /**
     * Retrieves attributes for a feed.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @param string $feedResourceName the resource name of the feed
     * @return array the feed attributes, keyed by attribute name
     */
    private static function getFeedAttributes(
        GoogleAdsClient $googleAdsClient,
        int $customerId,
        string $feedResourceName
    ) {
        $query = "SELECT feed.attributes, feed.name FROM feed "
            . "WHERE feed.resource_name = '$feedResourceName'";

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

        /** @var Feed $feed */
        $feed = $response->getIterator()->current()->getFeed();
        $feedDetails = [];
        printf(
            "Found the following attributes for feed with name %s:%s",
            $feed->getName(),
            PHP_EOL
        );
        foreach ($feed->getAttributes() as $feedAttribute) {
            /** @var FeedAttribute $feedAttribute */
            $feedDetails[$feedAttribute->getName()] = $feedAttribute->getId();
            printf(
                "\t'%s' with id %d and type '%s'%s",
                $feedAttribute->getName(),
                $feedAttribute->getId(),
                FeedAttributeType::name($feedAttribute->getType()),
                PHP_EOL
            );
        }
        return $feedDetails;
    }

    /**
     * Creates a feed mapping for a given feed.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @param string $adCustomizerFeedResourceName the resource name of the ad customizer feed
     * @param array $feedDetails an associative array from feed attribute names to their IDs
     */
    private static function createAdCustomizerMapping(
        GoogleAdsClient $googleAdsClient,
        int $customerId,
        string $adCustomizerFeedResourceName,
        array $feedDetails
    ) {
        // Maps the feed attribute IDs to the field ID constants.
        $nameFieldMapping = new AttributeFieldMapping([
            'feed_attribute_id' => $feedDetails['Name'],
            'ad_customizer_field' => AdCustomizerPlaceholderField::STRING
        ]);

        $priceFieldMapping = new AttributeFieldMapping([
            'feed_attribute_id' => $feedDetails['Price'],
            'ad_customizer_field' => AdCustomizerPlaceholderField::PRICE
        ]);

        $dateFieldMapping = new AttributeFieldMapping([
            'feed_attribute_id' => $feedDetails['Date'],
            'ad_customizer_field' => AdCustomizerPlaceholderField::DATE
        ]);

        // Creates the feed mapping.
        $feedMapping = new FeedMapping([
            'placeholder_type' => PlaceholderType::AD_CUSTOMIZER,
            'feed' => $adCustomizerFeedResourceName,
            'attribute_field_mappings' => [$nameFieldMapping, $priceFieldMapping, $dateFieldMapping]
        ]);

        // Creates the operation.
        $feedMappingOperation = new FeedMappingOperation();
        $feedMappingOperation->setCreate($feedMapping);

        // Issues a mutate request to add the feed mapping.
        $feedMappingServiceClient = $googleAdsClient->getFeedMappingServiceClient();
        $response = $feedMappingServiceClient->mutateFeedMappings(
            $customerId,
            [$feedMappingOperation]
        );

        // Displays the results.
        foreach ($response->getResults() as $result) {
            printf(
                "Created feed mapping with resource name '%s'.%s",
                $result->getResourceName(),
                PHP_EOL
            );
        }
    }

    /**
     * Creates two different feed items to enable two different ad customizations.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @param string $adCustomizerFeedResourceName the resource name of the feed
     * @param array $adCustomizerFeedAttributes the attributes of the feed
     * @return string[] the created feed item resource names
     */
    private static function createFeedItems(
        GoogleAdsClient $googleAdsClient,
        int $customerId,
        string $adCustomizerFeedResourceName,
        array $adCustomizerFeedAttributes
    ) {
        $feedItemOperations = [];

        $feedItemOperations[] = self::createFeedItemOperation(
            'Mars',
            '$1234.56',
            date_format(new DateTime('first day of this month'), 'Ymd His'),
            $adCustomizerFeedResourceName,
            $adCustomizerFeedAttributes
        );

        $feedItemOperations[] = self::createFeedItemOperation(
            'Venus',
            '$6543.21',
            // Set the date to the 15th of the current month.
            date_format(DateTime::createFromFormat('d', '15'), 'Ymd His'),
            $adCustomizerFeedResourceName,
            $adCustomizerFeedAttributes
        );

        // Adds the feed items.
        $feedItemServiceClient = $googleAdsClient->getFeedItemServiceClient();
        $response = $feedItemServiceClient->mutateFeedItems($customerId, $feedItemOperations);

        $feedItemResourceNames = [];
        // Displays the results.
        foreach ($response->getResults() as $result) {
            printf(
                "Created feed item with resource name '%s'.%s",
                $result->getResourceName(),
                PHP_EOL
            );
            $feedItemResourceNames[] = $result->getResourceName();
        }

        return $feedItemResourceNames;
    }

    /**
     * Creates a FeedItemOperation.
     *
     * @param string $name the value of the Name attribute
     * @param string $price the value of the Price attribute
     * @param string $date the value of the Date attribute
     * @param string $adCustomizerFeedResourceName the resource name of the feed
     * @param array $adCustomizerFeedAttributes the attributes to be set on the feed
     * @return FeedItemOperation the feed item operation to create a feed item
     */
    private static function createFeedItemOperation(
        string $name,
        string $price,
        string $date,
        string $adCustomizerFeedResourceName,
        array $adCustomizerFeedAttributes
    ) {
        $nameAttributeValue = new FeedItemAttributeValue([
            'feed_attribute_id' => $adCustomizerFeedAttributes['Name'],
            'string_value' => $name
        ]);

        $priceAttributeValue = new FeedItemAttributeValue([
            'feed_attribute_id' => $adCustomizerFeedAttributes['Price'],
            'string_value' => $price
        ]);

        $dateAttributeValue = new FeedItemAttributeValue([
            'feed_attribute_id' => $adCustomizerFeedAttributes['Date'],
            'string_value' => $date
        ]);

        $feedItem = new FeedItem([
            'feed' => $adCustomizerFeedResourceName,
            'attribute_values' => [$nameAttributeValue, $priceAttributeValue, $dateAttributeValue]
        ]);

        $feedItemOperation = new FeedItemOperation();
        $feedItemOperation->setCreate($feedItem);

        return $feedItemOperation;
    }

  /**
   * Restricts the feed items to work only with a specific ad group; this prevents the feed items
   * from being used elsewhere and makes sure they are used only for customizing a specific ad
   * group.
   *
   * @param GoogleAdsClient $googleAdsClient the Google Ads API client
   * @param int $customerId the customer ID
   * @param array $adGroupIds the ad group IDs to bind the feed items to
   * @param array $feedItemResourceNames the resource names of the feed items
   */
    private static function createFeedItemTargets(
        GoogleAdsClient $googleAdsClient,
        int $customerId,
        array $adGroupIds,
        array $feedItemResourceNames
    ) {
        // Bind each feed item to a specific ad group to make sure it will only be used to customize
        // ads inside that ad group; using the feed item elsewhere will result in an error.
        for ($i = 0; $i < count($feedItemResourceNames); $i++) {
            $feedItemResourceName = $feedItemResourceNames[$i];
            $adGroupId = $adGroupIds[$i];

            $feedItemTarget = new FeedItemTarget([
                'feed_item' => $feedItemResourceName,
                'ad_group' => ResourceNames::forAdGroup($customerId, $adGroupId)
            ]);

            // Creates the operation.
            $feedItemTargetOperation = new FeedItemTargetOperation();
            $feedItemTargetOperation->setCreate($feedItemTarget);

            // Issues a mutate request to add the feed item target.
            $feedItemTargetServiceClient = $googleAdsClient->getFeedItemTargetServiceClient();
            $feedItemTargetResponse = $feedItemTargetServiceClient->mutateFeedItemTargets(
                $customerId,
                [$feedItemTargetOperation]
            );

            $feedItemTargetResourceName =
                $feedItemTargetResponse->getResults()[0]->getResourceName();
            printf(
                "Added feed item target with resource name '%s'.%s",
                $feedItemTargetResourceName,
                PHP_EOL
            );
        }
    }

    /**
     * Creates expanded text ads that use the ad customizer feed to populate the placeholders.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the client customer ID
     * @param array $adGroupIds the ad group IDs in which to create the ads
     * @param string $feedName the name of the feed
     */
    private static function createAdsWithCustomizations(
        GoogleAdsClient $googleAdsClient,
        int $customerId,
        array $adGroupIds,
        string $feedName
    ) {
        $expandedTextAdInfo = new ExpandedTextAdInfo([
            'headline_part1' => "Luxury cruise to {=$feedName.Name}",
            'headline_part2' => "Only {=$feedName.Price}",
            'description' => "Offer ends in {=countdown($feedName.Date)}!"
        ]);

        $ad = new Ad([
            'expanded_text_ad' => $expandedTextAdInfo,
            'final_urls' => ['http://www.example.com']
        ]);

        $adGroupAdOperations = [];

        foreach ($adGroupIds as $adGroupId) {
            $adGroupAd = new AdGroupAd([
                'ad' => $ad,
                'ad_group' => ResourceNames::forAdGroup($customerId, $adGroupId)
            ]);

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

            $adGroupAdOperations[] = $adGroupAdOperation;
        }

        // Issues a mutate request to add the ads.
        $adGroupAdServiceClient = $googleAdsClient->getAdGroupAdServiceClient();
        $adGroupAdResponse = $adGroupAdServiceClient->mutateAdGroupAds(
            $customerId,
            $adGroupAdOperations
        );

        printf('Added %d ads:%s', count($adGroupAdResponse->getResults()), PHP_EOL);
        foreach ($adGroupAdResponse->getResults() as $result) {
            printf("Added an ad with resource name '%s'.%s", $result->getResourceName(), PHP_EOL);
        }
    }
}

AddAdCustomizer::main();

      

Python

#!/usr/bin/env python
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Adds an ad customizer feed and associates it with a given customer.

It then adds an ad that uses the feed to populate dynamic data.
"""


import argparse
from datetime import datetime
import sys
from uuid import uuid4

from google.ads.googleads.client import GoogleAdsClient
from google.ads.googleads.errors import GoogleAdsException


def main(client, customer_id, ad_group_ids):
    """The main method that creates all necessary entities for the example.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID.
        ad_group_ids: a list of ad group IDs.
    """
    feed_name = f"Ad customizer example feed {uuid4()}"
    ad_customizer_feed_resource_name = _create_add_customizer_feed(
        client, customer_id, feed_name
    )
    ad_customizer_feed_attributes = _get_feed_attributes(
        client, customer_id, ad_customizer_feed_resource_name
    )

    _create_ad_customizer_mapping(
        client,
        customer_id,
        ad_customizer_feed_resource_name,
        ad_customizer_feed_attributes,
    )

    feed_item_resource_names = _create_feed_items(
        client,
        customer_id,
        ad_customizer_feed_resource_name,
        ad_customizer_feed_attributes,
    )

    _create_feed_item_targets(
        client, customer_id, ad_group_ids, feed_item_resource_names
    )

    _create_ads_with_customizations(
        client, customer_id, ad_group_ids, feed_name
    )


def _create_add_customizer_feed(client, customer_id, feed_name):
    """Creates a feed to be used for ad customization.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID.
        feed_name: the name of the feed to create.

    Returns:
        A str of a resource name for the newly created feed.
    """
    # Creates three feed attributes: a name, a price and a date.
    # The attribute names are arbitrary choices and will be used as
    # placeholders in the ad text fields.
    feed_attr_type_enum = client.get_type(
        "FeedAttributeTypeEnum"
    ).FeedAttributeType

    name_attr = client.get_type("FeedAttribute")
    name_attr.type_ = feed_attr_type_enum.STRING
    name_attr.name = "Name"

    price_attr = client.get_type("FeedAttribute")
    price_attr.type_ = feed_attr_type_enum.STRING
    price_attr.name = "Price"

    date_attr = client.get_type("FeedAttribute")
    date_attr.type_ = feed_attr_type_enum.DATE_TIME
    date_attr.name = "Date"

    feed_operation = client.get_type("FeedOperation")
    feed = feed_operation.create

    feed.name = feed_name
    feed.attributes.extend([name_attr, price_attr, date_attr])
    feed.origin = client.get_type("FeedOriginEnum").FeedOrigin.USER

    feed_service = client.get_service("FeedService")

    try:
        response = feed_service.mutate_feeds(
            customer_id=customer_id, operations=[feed_operation]
        )
        resource_name = response.results[0].resource_name
        print(f"Added feed with resource name {resource_name}")
        return resource_name
    except GoogleAdsException as ex:
        _handle_googleads_exception(ex)


def _get_feed_attributes(client, customer_id, feed_resource_name):
    """Retrieves attributes for a feed.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID.
        feed_resource_name: the resource name of the feed.

    Returns:
        A dict of feed attributes, keyed by attribute name.
    """
    query = f"""
      SELECT
        feed.attributes,
        feed.name
      FROM feed
      WHERE
        feed.resource_name = "{feed_resource_name}"
    """
    ga_service = client.get_service("GoogleAdsService")
    search_request = client.get_type("SearchGoogleAdsRequest")
    search_request.customer_id = customer_id
    search_request.query = query
    search_request.page_size = 1

    try:
        results = ga_service.search(request=search_request)
        feed = list(results)[0].feed
        print(f"Found the following attributes for feed with name {feed.name}")
    except GoogleAdsException as ex:
        _handle_googleads_exception(ex)

    feed_attr_type_enum = client.get_type("FeedAttributeTypeEnum")
    feed_details = {}
    for feed_attribute in feed.attributes:
        name = feed_attribute.name
        feed_attr_id = feed_attribute.id
        feed_type = feed_attribute.type_.name
        feed_details[name] = feed_attr_id
        print(f"\t{name} with id {feed_attr_id} and type {feed_type}.")

    return feed_details


def _create_ad_customizer_mapping(
    client,
    customer_id,
    ad_customizer_feed_resource_name,
    feed_details,
):
    """Creates a feed mapping for a given feed.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID.
        ad_customizer_feed_resource_name: the resource name of the ad customizer
            feed.
        feed_details: a dict mapping feed attribute names to their IDs.
    """
    placeholder_field_enum = client.get_type(
        "AdCustomizerPlaceholderFieldEnum"
    ).AdCustomizerPlaceholderField

    # Map the feed attributes to ad customizer placeholder fields. For a full
    # list of ad customizer placeholder fields, see:
    # https://developers.google.com/google-ads/api/reference/rpc/latest/AdCustomizerPlaceholderFieldEnum.AdCustomizerPlaceholderField
    name_field_mapping = client.get_type("AttributeFieldMapping")
    name_field_mapping.feed_attribute_id = feed_details["Name"]
    name_field_mapping.ad_customizer_field = placeholder_field_enum.STRING

    price_field_mapping = client.get_type("AttributeFieldMapping")
    price_field_mapping.feed_attribute_id = feed_details["Price"]
    price_field_mapping.ad_customizer_field = placeholder_field_enum.PRICE

    date_field_mapping = client.get_type("AttributeFieldMapping")
    date_field_mapping.feed_attribute_id = feed_details["Date"]
    date_field_mapping.ad_customizer_field = placeholder_field_enum.DATE

    feed_mapping_op = client.get_type("FeedMappingOperation")
    feed_mapping = feed_mapping_op.create
    feed_mapping.feed = ad_customizer_feed_resource_name
    feed_mapping.placeholder_type = client.get_type(
        "PlaceholderTypeEnum"
    ).PlaceholderType.AD_CUSTOMIZER
    feed_mapping.attribute_field_mappings.extend(
        [name_field_mapping, price_field_mapping, date_field_mapping]
    )

    feed_mapping_service = client.get_service("FeedMappingService")

    try:
        response = feed_mapping_service.mutate_feed_mappings(
            customer_id=customer_id, operations=[feed_mapping_op]
        )
        for result in response.results:
            print(
                "Created feed mapping with resource name "
                f"{result.resource_name}"
            )
    except GoogleAdsException as ex:
        _handle_googleads_exception(ex)


def _create_feed_items(
    client,
    customer_id,
    ad_customizer_feed_resource_name,
    ad_customizer_feed_attributes,
):
    """Creates two feed items to enable two different ad customizations.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID.
        ad_customizer_feed_resource_name: the resource name of the ad customizer
            feed.
        ad_customizer_feed_attributes: a dict mapping feed attribute names to
            their IDs.

    Returns:
        A list of feed item resource name strs.
    """
    feed_item_operations = []
    feed_item_operations.append(
        _create_feed_item_operation(
            client,
            "Mars",
            "$1234.56",
            # Set the date to the 1st of the current month.
            datetime.now().replace(day=1).strftime("%Y%m%d %H%M%S"),
            ad_customizer_feed_resource_name,
            ad_customizer_feed_attributes,
        )
    )
    feed_item_operations.append(
        _create_feed_item_operation(
            client,
            "Venus",
            "$6543.21",
            # Set the date to the 15th of the current month.
            datetime.now().replace(day=15).strftime("%Y%m%d %H%M%S"),
            ad_customizer_feed_resource_name,
            ad_customizer_feed_attributes,
        )
    )

    feed_item_service = client.get_service("FeedItemService")

    try:
        response = feed_item_service.mutate_feed_items(
            customer_id=customer_id, operations=feed_item_operations
        )
        return [feed_item.resource_name for feed_item in response.results]
    except GoogleAdsException as ex:
        _handle_googleads_exception(ex)


def _create_feed_item_operation(
    client,
    name,
    price,
    date,
    ad_customizer_feed_resource_name,
    ad_customizer_feed_attributes,
):
    """Creates a FeedItemOperation.

    Args:
        client: an initialized GoogleAdsClient instance.
        name: a str value for the name attribute of the feed_item
        price: a str value for the price attribute of the feed_item
        date: a str value for the date attribute of the feed_item
        ad_customizer_feed_resource_name: the resource name of the ad customizer
            feed.
        ad_customizer_feed_attributes: a dict mapping feed attribute names to
            their IDs.

    Returns:
        A FeedItemOperation that creates a FeedItem
    """
    name_attr_value = client.get_type("FeedItemAttributeValue")
    name_attr_value.feed_attribute_id = ad_customizer_feed_attributes["Name"]
    name_attr_value.string_value = name

    price_attr_value = client.get_type("FeedItemAttributeValue")
    price_attr_value.feed_attribute_id = ad_customizer_feed_attributes["Price"]
    price_attr_value.string_value = price

    date_attr_value = client.get_type("FeedItemAttributeValue")
    date_attr_value.feed_attribute_id = ad_customizer_feed_attributes["Date"]
    date_attr_value.string_value = date

    feed_item_op = client.get_type("FeedItemOperation")
    feed_item = feed_item_op.create
    feed_item.feed = ad_customizer_feed_resource_name
    feed_item.attribute_values.extend(
        [name_attr_value, price_attr_value, date_attr_value]
    )

    return feed_item_op


def _create_feed_item_targets(
    client, customer_id, ad_group_ids, feed_item_resource_names
):
    """Restricts the feed items to work only with a specific ad group.

    This prevents the feed items from being used elsewhere and makes sure they
    are used only for customizing a specific ad group.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID.
        ad_group_ids: a list of ad group IDs.
        feed_item_resource_names: a list of feed item resource name strs.
    """
    ad_group_service = client.get_service("AdGroupService")
    feed_item_target_service = client.get_service("FeedItemTargetService")
    # Bind each feed item to a specific ad group to make sure it will only be
    # used to customize ads inside that ad group; using the feed item elsewhere
    # will result in an error.
    for i, resource_name in enumerate(feed_item_resource_names):
        ad_group_id = ad_group_ids[i]

        feed_item_target_op = client.get_type("FeedItemTargetOperation")
        feed_item_target = feed_item_target_op.create
        feed_item_target.feed_item = resource_name
        feed_item_target.ad_group = ad_group_service.ad_group_path(
            customer_id, ad_group_id
        )

        try:
            response = feed_item_target_service.mutate_feed_item_targets(
                customer_id=customer_id, operations=[feed_item_target_op]
            )
            print(
                "Added feed item target with resource name "
                f"{response.results[0].resource_name}"
            )
        except GoogleAdsException as ex:
            _handle_googleads_exception(ex)


def _create_ads_with_customizations(
    client, customer_id, ad_group_ids, feed_name
):
    """Creates expanded text ads that use the ad customizer feed.

    The expanded text ads use the ad customizer feed to populate the
    placeholders.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID.
        ad_group_ids: a list of ad group IDs.
        feed_name: the name of the feed to create.
    """
    ad_group_service = client.get_service("AdGroupService")
    ad_group_ad_service = client.get_service("AdGroupAdService")
    ad_group_ad_operations = []

    for ad_group_id in ad_group_ids:
        ad_group_ad_operation = client.get_type("AdGroupAdOperation")
        ad_group_ad = ad_group_ad_operation.create
        ad_group_ad.ad_group = ad_group_service.ad_group_path(
            customer_id, ad_group_id
        )
        ad_group_ad.ad.final_urls.append("http://www.example.com")
        ad_group_ad.ad.expanded_text_ad.headline_part1 = (
            f"Luxury cruise to {{={feed_name}.Name}}"
        )
        ad_group_ad.ad.expanded_text_ad.headline_part2 = (
            f"Only {{={feed_name}.Price}}"
        )
        # See this documentation for an explanation of how countdown ad
        # customizers work: https://support.google.com/google-ads/answer/6193743?hl=en
        ad_group_ad.ad.expanded_text_ad.description = (
            f"Offer ends in {{=countdown({feed_name}.Date)}}!"
        )
        ad_group_ad_operations.append(ad_group_ad_operation)

    try:
        response = ad_group_ad_service.mutate_ad_group_ads(
            customer_id=customer_id, operations=ad_group_ad_operations
        )
        print(f"Added {len(response.results)} ads:")
        for ad in response.results:
            print(f"Added an ad with resource name {ad.resource_name}")
    except GoogleAdsException as ex:
        _handle_googleads_exception(ex)


def _handle_googleads_exception(exception):
    """Prints the details of a GoogleAdsException object.

    Args:
        exception: an instance of GoogleAdsException.
    """
    print(
        f'Request with ID "{exception.request_id}" failed with status '
        f'"{exception.error.code().name}" and includes the following errors:'
    )
    for error in exception.failure.errors:
        print(f'\tError with message "{error.message}".')
        if error.location:
            for field_path_element in error.location.field_path_elements:
                print(f"\t\tOn field: {field_path_element.field_name}")
    sys.exit(1)


if __name__ == "__main__":
    # GoogleAdsClient will read the google-ads.yaml configuration file in the
    # home directory if none is specified.
    googleads_client = GoogleAdsClient.load_from_storage(version="v7")

    parser = argparse.ArgumentParser(
        description=(
            "Adds an ad customizer feed and associates it with a customer."
        )
    )
    # The following argument(s) should be provided to run the example.
    parser.add_argument(
        "-c",
        "--customer_id",
        type=str,
        required=True,
        help="The Google Ads customer ID.",
    )
    parser.add_argument(
        "-a",
        "--ad_group_ids",
        nargs=2,
        type=str,
        required=True,
        help="Space-delimited list of ad group IDs.",
    )
    args = parser.parse_args()

    main(googleads_client, args.customer_id, args.ad_group_ids)

      

Ruby

#!/usr/bin/env ruby
# Encoding: utf-8
#
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Adds an ad customizer feed and associates it with the customer. Then it adds
# an ad that uses the feed to populate dynamic data.

require 'date'
require 'google/ads/google_ads'
require 'optparse'

def add_ad_customizer(customer_id, ad_group_ids)
  # GoogleAdsClient will read a config file from
  # ENV['HOME']/google_ads_config.rb when called without parameters
  client = Google::Ads::GoogleAds::GoogleAdsClient.new

  if ad_group_ids.size != NUMBER_OF_AD_GROUPS
    raise "Please pass exactly #{NUMBER_OF_AD_GROUPS} ad group IDs in the " \
      "ad_group_ids parameter."
  end

  feed_name = "Ad Customizer example feed #{(Time.new.to_f * 1000).to_i}"

  # Create a feed to be used for ad customization
  ad_customizer_feed_resource_name = create_ad_customizer_feed(
    client, customer_id, feed_name)

  # Retrieve the attributes of the feed.
  ad_customizer_feed_attributes = get_feed_attributes(
    client, customer_id, ad_customizer_feed_resource_name)

  # Map the feed to the ad customizer placeholder fields.
  create_ad_customizer_mapping(
    client,
    customer_id,
    ad_customizer_feed_resource_name,
    ad_customizer_feed_attributes,
  )

  # Create feed items to be used to customize ads.
  feed_item_resource_names = create_feed_items(
    client,
    customer_id,
    ad_customizer_feed_resource_name,
    ad_customizer_feed_attributes,
  )

  # Set the feed to be used only with the specified ad groups.
  create_feed_item_targets(
    client,
    customer_id,
    ad_group_ids,
    feed_item_resource_names,
  )

  # Create ads that use the feed for customization.
  create_ads_with_customizations(
    client,
    customer_id,
    ad_group_ids,
    feed_name,
  )
end

# Creates a feed to be used for ad customization.
def create_ad_customizer_feed(
  client, customer_id, feed_name)
  # Creates a feed operation for creating a feed.
  operation = client.operation.create_resource.feed do |feed|
    feed.name = feed_name
    # Creates three feed attributes: a name, a price and a date. The attribute
    # names are arbitrary choices and will be used as placeholders in the ad
    # text fields.
    feed.attributes << client.resource.feed_attribute do |a|
      a.type = :STRING
      a.name = "Name"
    end
    feed.attributes << client.resource.feed_attribute do |a|
      a.type = :STRING
      a.name = "Price"
    end
    feed.attributes << client.resource.feed_attribute do |a|
      a.type = :DATE_TIME
      a.name = "Date"
    end
    feed.origin = :USER
  end

  # Issues a mutate request to add the feed.
  feed_response = client.service.feed.mutate_feeds(
    customer_id: customer_id,
    operations: [operation],
  )

  feed_resource_name = feed_response.results.first.resource_name
  puts "Added a feed with resource name #{feed_resource_name}."

  feed_resource_name
end

# Retrieves attributes for a feed.
def get_feed_attributes(
  client, customer_id, ad_customizer_feed_resource_name)
  query = <<~QUERY
    SELECT feed.attributes, feed.name
    FROM feed
    WHERE feed.resource_name = "#{ad_customizer_feed_resource_name}"
  QUERY

  response = client.service.google_ads.search(
    customer_id: customer_id,
    query: query,
    page_size: PAGE_SIZE,
  )

  feed = response.first.feed
  feed_details = {}
  puts "Found the following attributes for feed with name #{feed.name}:"
  feed.attributes.each do |a|
    feed_details[a.name.to_sym] = a.id
    puts "\t#{a.name} with id #{a.id} and type #{a.type}"
  end

  feed_details
end

# Creates a feed mapping for a given feed.
def create_ad_customizer_mapping(
  client,
  customer_id,
  ad_customizer_feed_resource_name,
  ad_customizer_feed_attributes)
  # Creates the operation.
  operation = client.operation.create_resource.feed_mapping do |fm|
    fm.placeholder_type = :AD_CUSTOMIZER
    fm.feed = ad_customizer_feed_resource_name
    # Maps the feed attribute IDs to the field ID constants.
    fm.attribute_field_mappings << client.resource.attribute_field_mapping do |af|
      af.feed_attribute_id = ad_customizer_feed_attributes[:Name]
      af.ad_customizer_field = :STRING
    end
    fm.attribute_field_mappings << client.resource.attribute_field_mapping do |af|
      af.feed_attribute_id = ad_customizer_feed_attributes[:Price]
      af.ad_customizer_field = :PRICE
    end
    fm.attribute_field_mappings << client.resource.attribute_field_mapping do |af|
      af.feed_attribute_id = ad_customizer_feed_attributes[:Date]
      af.ad_customizer_field = :DATE
    end
  end

  # Issues a mutate request to add the feed mapping.
  response = client.service.feed_mapping.mutate_feed_mappings(
    customer_id: customer_id,
    operations: [operation],
  )

  # Displays the results.
  response.results.each do |result|
    puts "Created feed mapping with resource name: #{result.resource_name}"
  end
end

# Creates two different feed items to enable two different ad customizations.
def create_feed_items(
  client,
  customer_id,
  ad_customizer_feed_resource_name,
  ad_customizer_feed_attributes)
  feed_item_operations = []

  feed_item_operations << create_feed_item_operation(
    client,
    "Mars",
    "$1234.56",
    # Set the date to the 1st of the current month.
    DateTime.new(Date.today.year, Date.today.month, 1, 0, 0, 0).strftime("%Y%m%d %H%M%S"),
    ad_customizer_feed_resource_name,
    ad_customizer_feed_attributes,
  )

  feed_item_operations << create_feed_item_operation(
    client,
    "Venus",
    "$6543.21",
    # Set the date to the 15th of the current month.
    DateTime.new(Date.today.year, Date.today.month, 15, 0, 0, 0).strftime("%Y%m%d %H%M%S"),
    ad_customizer_feed_resource_name,
    ad_customizer_feed_attributes,
  )

  # Adds the feed items.
  response = client.service.feed_item.mutate_feed_items(
    customer_id: customer_id,
    operations: feed_item_operations,
  )

  feed_item_resource_names = []
  response.results.each do |result|
    puts "Created feed item with resource name #{result.resource_name}"
    feed_item_resource_names << result.resource_name
  end

  feed_item_resource_names
end

# Creates a FeedItemOperation.
def create_feed_item_operation(
  client,
  name,
  price,
  date,
  ad_customizer_feed_resource_name,
  ad_customizer_feed_attributes)
  client.operation.create_resource.feed_item do |item|
    item.feed = ad_customizer_feed_resource_name
    item.attribute_values << client.resource.feed_item_attribute_value do |v|
      v.feed_attribute_id = ad_customizer_feed_attributes[:Name]
      v.string_value = name
    end
    item.attribute_values << client.resource.feed_item_attribute_value do |v|
      v.feed_attribute_id = ad_customizer_feed_attributes[:Price]
      v.string_value = price
    end
    item.attribute_values << client.resource.feed_item_attribute_value do |v|
      v.feed_attribute_id = ad_customizer_feed_attributes[:Date]
      v.string_value = date
    end
  end
end

# Restricts the feed items to work only with a specific ad group; this prevents
# the feed items from being used elsewhere and makes sure they are used only for
# customizing a specific ad group.
def create_feed_item_targets(
  client,
  customer_id,
  ad_group_ids,
  feed_item_resource_names)
  # Bind each feed item to a specific ad group to make sure it will only be
  # used to customize ads inside that ad group; using the feed item elsewhere
  # will result in an error.
  feed_item_resource_names.size.times do |i|
    feed_item_resource_name = feed_item_resource_names[i]
    ad_group_id = ad_group_ids[i]

    # Creates the operation.
    operation = client.operation.create_resource.feed_item_target do |t|
      t.feed_item = feed_item_resource_name
      t.ad_group = client.path.ad_group(customer_id, ad_group_id)
    end

    # Issues a mutate request to add the feed item target.
    response = client.service.feed_item_target.mutate_feed_item_targets(
      customer_id: customer_id,
      operations: [operation],
    )

    puts "Added feed item target with resource name #{response.results.first.resource_name}."
  end
end

# Creates expanded text ads that use the ad customizer feed to populate the
# placeholders.
def create_ads_with_customizations(
  client,
  customer_id,
  ad_group_ids,
  feed_name)
  operations = []

  ad_group_ids.each do |ad_group_id|
    operations << client.operation.create_resource.ad_group_ad do |aga|
      aga.ad = client.resource.ad do |ad|
        ad.expanded_text_ad = client.resource.expanded_text_ad_info do |eta|
          eta.headline_part1 = "Luxury cruise to {=#{feed_name}.Name}"
          eta.headline_part2 = "Only {=#{feed_name}.Price}"
          eta.description = "Offer ends in {=countdown(#{feed_name}.Date)}!"
        end
        ad.final_urls << "http://www.example.com"
      end
      aga.ad_group = client.path.ad_group(customer_id, ad_group_id)
    end
  end

  # Issues a mutate request to add the ads.
  response = client.service.ad_group_ad.mutate_ad_group_ads(
    customer_id: customer_id,
    operations: operations,
  )

  puts "Added #{response.results.size} ads:"
  response.results.each do |result|
    puts "Added an ad with resource name #{result.resource_name}."
  end
end

if __FILE__ == $0
  # We're creating two different ad groups to be dynamically populated by
  # the same feed.
  NUMBER_OF_AD_GROUPS = 2

  # We're doing only searches by resource_name in this example,
  # we can set page size = 1.
  PAGE_SIZE = 1;

  options = {}
  # The following parameter(s) should be provided to run the example. You can
  # either specify these by changing the INSERT_XXX_ID_HERE values below, or on
  # the command line.
  #
  # Parameters passed on the command line will override any parameters set in
  # code.
  #
  # Running the example with -h will print the command line usage.
  options[:customer_id] = 'INSERT_CUSTOMER_ID_HERE'
  options[:ad_group_ids] = [
    'INSERT_AD_GROUP_ID_1_HERE',
    'INSERT_AD_GORUP_ID_2_HERE',
  ]

  OptionParser.new do |opts|
    opts.banner = sprintf('Usage: %s [options]', File.basename(__FILE__))

    opts.separator ''
    opts.separator 'Options:'

    opts.on('-C', '--customer-id CUSTOMER-ID', String, 'Customer ID') do |v|
      options[:customer_id] = v
    end

    opts.on('-A', '--ad-group-ids AD-GROUP-IDS', String, "#{NUMBER_OF_AD_GROUPS} AdGroup IDs (comma-separated)") do |v|
      options[:ad_group_ids] = v.split(',')
    end

    opts.on('-B', '--bid-modifier-value BID-MODIFIER-VALUE', String,
        'Bid Modifier Value') do |v|
      options[:bid_modifier_value] = v
    end

    opts.separator ''
    opts.separator 'Help:'

    opts.on_tail('-h', '--help', 'Show this message') do
      puts opts
      exit
    end
  end.parse!

  begin
    add_ad_customizer(
      options.fetch(:customer_id).tr("-", ""),
      options[:ad_group_ids],
    )
  rescue Google::Ads::GoogleAds::Errors::GoogleAdsError => e
    e.failure.errors.each do |error|
      STDERR.printf("Error with message: %s\n", error.message)
      if error.location
        error.location.field_path_elements.each do |field_path_element|
          STDERR.printf("\tOn field: %s\n", field_path_element.field_name)
        end
      end
      error.error_code.to_h.each do |k, v|
        next if v == :UNSPECIFIED
        STDERR.printf("\tType: %s\n\tCode: %s\n", k, v)
      end
    end
    raise
  end
end

      

Perl

#!/usr/bin/perl -w
#
# Copyright 2019, Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Adds an ad customizer feed and associates it with the customer. Then it adds an
# ad that uses the feed to populate dynamic data.

use strict;
use warnings;
use utf8;

use FindBin qw($Bin);
use lib "$Bin/../../lib";
use Google::Ads::GoogleAds::Client;
use Google::Ads::GoogleAds::Utils::GoogleAdsHelper;
use Google::Ads::GoogleAds::V7::Resources::FeedAttribute;
use Google::Ads::GoogleAds::V7::Resources::Feed;
use Google::Ads::GoogleAds::V7::Resources::AttributeFieldMapping;
use Google::Ads::GoogleAds::V7::Resources::FeedMapping;
use Google::Ads::GoogleAds::V7::Resources::FeedItemAttributeValue;
use Google::Ads::GoogleAds::V7::Resources::FeedItem;
use Google::Ads::GoogleAds::V7::Resources::FeedItemTarget;
use Google::Ads::GoogleAds::V7::Resources::Ad;
use Google::Ads::GoogleAds::V7::Resources::AdGroupAd;
use Google::Ads::GoogleAds::V7::Common::ExpandedTextAdInfo;
use Google::Ads::GoogleAds::V7::Enums::FeedAttributeTypeEnum
  qw(STRING DATE_TIME);
use Google::Ads::GoogleAds::V7::Enums::FeedOriginEnum qw(USER);
use Google::Ads::GoogleAds::V7::Enums::AdCustomizerPlaceholderFieldEnum;
use Google::Ads::GoogleAds::V7::Enums::PlaceholderTypeEnum qw(AD_CUSTOMIZER);
use Google::Ads::GoogleAds::V7::Services::FeedService::FeedOperation;
use
  Google::Ads::GoogleAds::V7::Services::FeedMappingService::FeedMappingOperation;
use Google::Ads::GoogleAds::V7::Services::FeedItemService::FeedItemOperation;
use
  Google::Ads::GoogleAds::V7::Services::FeedItemTargetService::FeedItemTargetOperation;
use Google::Ads::GoogleAds::V7::Services::AdGroupAdService::AdGroupAdOperation;
use Google::Ads::GoogleAds::V7::Utils::ResourceNames;

use Getopt::Long qw(:config auto_help);
use Pod::Usage;
use Cwd qw(abs_path);
use Data::Uniqid qw(uniqid);
use POSIX qw(strftime mktime);

# We're doing only searches by resource_name in this example, we can set page size = 1.
use constant PAGE_SIZE => 1;
# We're creating two different ad groups to be dynamically populated by the same feed.
use constant NUMBER_OF_AD_GROUPS => 2;

# The following parameter(s) should be provided to run the example. You can
# either specify these by changing the INSERT_XXX_ID_HERE values below, or on
# the command line.
#
# Parameters passed on the command line will override any parameters set in
# code.
#
# Running the example with -h will print the command line usage.
my $customer_id   = "INSERT_CUSTOMER_ID_HERE";
my $ad_group_id_1 = "INSERT_AD_GROUP_ID_1_HERE";
my $ad_group_id_2 = "INSERT_AD_GROUP_ID_2_HERE";
my $ad_group_ids  = [];

sub add_ad_customizer {
  my ($api_client, $customer_id, $ad_group_ids) = @_;

  die sprintf
    "Please pass exactly %d ad group IDs in the ad_group_ids parameter.\n",
    NUMBER_OF_AD_GROUPS
    if scalar @$ad_group_ids != NUMBER_OF_AD_GROUPS;

  my $feed_name = "Ad Customizer example feed " . uniqid();

  # Create a feed to be used for ad customization.
  my $ad_customizer_feed_resource_name =
    create_ad_customizer_feed($api_client, $customer_id, $feed_name);

  # Retrieve the attributes of the feed.
  my $ad_customizer_feed_attributes =
    get_feed_attributes($api_client, $customer_id,
    $ad_customizer_feed_resource_name);

  # Map the feed to the ad customizer placeholder fields.
  create_ad_customizer_mapping(
    $api_client, $customer_id,
    $ad_customizer_feed_resource_name,
    $ad_customizer_feed_attributes
  );

  # Create feed items to be used to customize ads.
  my $feed_item_resource_names = create_feed_items(
    $api_client, $customer_id,
    $ad_customizer_feed_resource_name,
    $ad_customizer_feed_attributes
  );

  # Set the feed to be used only with the specified ad groups.
  create_feed_item_targets($api_client, $customer_id, $ad_group_ids,
    $feed_item_resource_names);

  # Create ads that use the feed for customization.
  create_ads_with_customizations($api_client, $customer_id, $ad_group_ids,
    $feed_name);

  return 1;
}

# Creates a feed to be used for ad customization.
sub create_ad_customizer_feed {
  my ($api_client, $customer_id, $feed_name) = @_;

  # Create three feed attributes: a name, a price and a date. The attribute names
  # are arbitrary choices and will be used as placeholders in the ad text fields.
  my $name_attribute =
    Google::Ads::GoogleAds::V7::Resources::FeedAttribute->new({
      type => STRING,
      name => "Name"
    });

  my $price_attribute =
    Google::Ads::GoogleAds::V7::Resources::FeedAttribute->new({
      type => STRING,
      name => "Price"
    });

  my $date_attribute =
    Google::Ads::GoogleAds::V7::Resources::FeedAttribute->new({
      type => DATE_TIME,
      name => "Date"
    });

  # Create the feed.
  my $feed = Google::Ads::GoogleAds::V7::Resources::Feed->new({
    name       => $feed_name,
    attributes => [$name_attribute, $price_attribute, $date_attribute],
    origin     => USER
  });

  # Create a feed operation for creating a feed.
  my $feed_operation =
    Google::Ads::GoogleAds::V7::Services::FeedService::FeedOperation->new({
      create => $feed
    });

  # Issue a mutate request to add the feed.
  my $feeds_response = $api_client->FeedService()->mutate({
      customerId => $customer_id,
      operations => [$feed_operation]});

  my $feed_resource_name = $feeds_response->{results}[0]{resourceName};
  printf "Added feed with resource name '%s'.\n", $feed_resource_name;

  return $feed_resource_name;
}

# Retrieves attributes for a feed.
sub get_feed_attributes {
  my ($api_client, $customer_id, $feed_resource_name) = @_;

  my $search_query = "SELECT feed.attributes, feed.name FROM feed " .
    "WHERE feed.resource_name = '$feed_resource_name'";

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

  my $feed         = $search_response->{results}[0]{feed};
  my $feed_details = {};
  printf "Found the following attributes for feed with name %s:\n",
    $feed->{name};

  foreach my $feed_attribute (@{$feed->{attributes}}) {
    $feed_details->{$feed_attribute->{name}} = $feed_attribute->{id};
    printf "\t'%s' with id %d and type '%s'\n", $feed_attribute->{name},
      $feed_attribute->{id}, $feed_attribute->{type};
  }
  return $feed_details;
}

# Creates a feed mapping for a given feed.
sub create_ad_customizer_mapping {
  my (
    $api_client, $customer_id,
    $ad_customizer_feed_resource_name,
    $ad_customizer_feed_attributes
  ) = @_;

  # Map the feed attribute IDs to the field ID constants.
  my $name_field_mapping =
    Google::Ads::GoogleAds::V7::Resources::AttributeFieldMapping->new({
      feedAttributeId   => $ad_customizer_feed_attributes->{Name},
      adCustomizerField =>
        Google::Ads::GoogleAds::V7::Enums::AdCustomizerPlaceholderFieldEnum::STRING,
    });

  my $price_field_mapping =
    Google::Ads::GoogleAds::V7::Resources::AttributeFieldMapping->new({
      feedAttributeId   => $ad_customizer_feed_attributes->{Price},
      adCustomizerField =>
        Google::Ads::GoogleAds::V7::Enums::AdCustomizerPlaceholderFieldEnum::PRICE,
    });

  my $date_field_mapping =
    Google::Ads::GoogleAds::V7::Resources::AttributeFieldMapping->new({
      feedAttributeId   => $ad_customizer_feed_attributes->{Date},
      adCustomizerField =>
        Google::Ads::GoogleAds::V7::Enums::AdCustomizerPlaceholderFieldEnum::DATE,
    });

  # Create the feed mapping.
  my $feed_mapping = Google::Ads::GoogleAds::V7::Resources::FeedMapping->new({
      placeholderType        => AD_CUSTOMIZER,
      feed                   => $ad_customizer_feed_resource_name,
      attributeFieldMappings =>
        [$name_field_mapping, $price_field_mapping, $date_field_mapping]});

  # Create the operation.
  my $feed_mapping_operation =
    Google::Ads::GoogleAds::V7::Services::FeedMappingService::FeedMappingOperation
    ->new({
      create => $feed_mapping
    });

  # Issue a mutate request to add the feed mapping.
  my $feed_mappings_response = $api_client->FeedMappingService()->mutate({
      customerId => $customer_id,
      operations => [$feed_mapping_operation]});

  # Display the results.
  foreach my $result (@{$feed_mappings_response->{results}}) {
    printf "Created feed mapping with resource name '%s'.\n",
      $result->{resourceName};
  }
}

# Creates two different feed items to enable two different ad customizations.
sub create_feed_items {
  my (
    $api_client, $customer_id,
    $ad_customizer_feed_resource_name,
    $ad_customizer_feed_attributes
  ) = @_;

  my $feed_item_operations = [];

  my ($sec, $min, $hour, $mday, $mon, $year) = localtime(time);

  push @$feed_item_operations,
    create_feed_item_operation(
    "Mars",
    '$1234.56',
    strftime("%Y%m%d %H%M%S", localtime(mktime(0, 0, 0, 1, $mon, $year))),
    $ad_customizer_feed_resource_name,
    $ad_customizer_feed_attributes
    );

  push @$feed_item_operations, create_feed_item_operation(
    "Venus",
    '$6543.21',
    # Set the date to the 15th of the current month.
    strftime("%Y%m%d %H%M%S", localtime(mktime(0, 0, 0, 15, $mon, $year))),
    $ad_customizer_feed_resource_name,
    $ad_customizer_feed_attributes
  );

  # Add the feed items.
  my $feed_items_response = $api_client->FeedItemService()->mutate({
    customerId => $customer_id,
    operations => $feed_item_operations
  });

  my $feed_item_resource_names = [];
  # Displays the results.
  foreach my $result (@{$feed_items_response->{results}}) {
    printf "Created feed item with resource name '%s'.\n",
      $result->{resourceName};
    push @$feed_item_resource_names, $result->{resourceName};
  }

  return $feed_item_resource_names;
}

# Creates a FeedItemOperation.
sub create_feed_item_operation {
  my (
    $name, $price, $date,
    $ad_customizer_feed_resource_name,
    $ad_customizer_feed_attributes
  ) = @_;

  my $name_attribute_value =
    Google::Ads::GoogleAds::V7::Resources::FeedItemAttributeValue->new({
      feedAttributeId => $ad_customizer_feed_attributes->{Name},
      stringValue     => $name
    });

  my $price_attribute_value =
    Google::Ads::GoogleAds::V7::Resources::FeedItemAttributeValue->new({
      feedAttributeId => $ad_customizer_feed_attributes->{Price},
      stringValue     => $price
    });

  my $date_attribute_value =
    Google::Ads::GoogleAds::V7::Resources::FeedItemAttributeValue->new({
      feedAttributeId => $ad_customizer_feed_attributes->{Date},
      stringValue     => $date
    });

  my $feed_item = Google::Ads::GoogleAds::V7::Resources::FeedItem->new({
      feed            => $ad_customizer_feed_resource_name,
      attributeValues =>
        [$name_attribute_value, $price_attribute_value, $date_attribute_value]}
  );

  return
    Google::Ads::GoogleAds::V7::Services::FeedItemService::FeedItemOperation->
    new({
      create => $feed_item
    });
}

# Restricts the feed items to work only with a specific ad group; this prevents
# the feed items from being used elsewhere and makes sure they are used only for
# customizing a specific ad group.
sub create_feed_item_targets {
  my ($api_client, $customer_id, $ad_group_ids, $feed_item_resource_names) = @_;

  # Bind each feed item to a specific ad group to make sure it will only be used
  # to customize ads inside that ad group; using the feed item elsewhere will
  # result in an error.
  for (my $i = 0 ; $i < scalar @$feed_item_resource_names ; $i++) {
    my $feed_item_resource_name = $feed_item_resource_names->[$i];
    my $ad_group_id             = $ad_group_ids->[$i];

    my $feed_item_target =
      Google::Ads::GoogleAds::V7::Resources::FeedItemTarget->new({
        feedItem => $feed_item_resource_name,
        adGroup  => Google::Ads::GoogleAds::V7::Utils::ResourceNames::ad_group(
          $customer_id, $ad_group_id
        )});

    # Create the operation.
    my $feed_item_target_operation =
      Google::Ads::GoogleAds::V7::Services::FeedItemTargetService::FeedItemTargetOperation
      ->new({
        create => $feed_item_target
      });

    # Issue a mutate request to add the feed item target.
    my $feed_item_targets_response =
      $api_client->FeedItemTargetService()->mutate({
        customerId => $customer_id,
        operations => [$feed_item_target_operation]});

    my $feed_item_target_resource_name =
      $feed_item_targets_response->{results}[0]{resourceName};
    printf "Added feed item target with resource name '%s'.\n",
      $feed_item_target_resource_name;
  }
}

# Creates expanded text ads that use the ad customizer feed to populate the placeholders.
sub create_ads_with_customizations {
  my ($api_client, $customer_id, $ad_group_ids, $feed_name) = @_;

  my $expanded_text_ad_info =
    Google::Ads::GoogleAds::V7::Common::ExpandedTextAdInfo->new({
      headlinePart1 => "Luxury cruise to {=$feed_name.Name}",
      headlinePart2 => "Only {=$feed_name.Price}",
      description   => "Offer ends in {=countdown($feed_name.Date)}!"
    });

  my $ad = Google::Ads::GoogleAds::V7::Resources::Ad->new({
      expandedTextAd => $expanded_text_ad_info,
      finalUrls      => ["http://www.example.com"]});

  my $ad_group_ad_operations = [];
  foreach my $ad_group_id (@$ad_group_ids) {
    my $ad_group_ad = Google::Ads::GoogleAds::V7::Resources::AdGroupAd->new({
        ad      => $ad,
        adGroup => Google::Ads::GoogleAds::V7::Utils::ResourceNames::ad_group(
          $customer_id, $ad_group_id
        )});

    push @$ad_group_ad_operations,
      Google::Ads::GoogleAds::V7::Services::AdGroupAdService::AdGroupAdOperation
      ->new({
        create => $ad_group_ad
      });
  }

  # Issue a mutate request to add the ads.
  my $ad_group_ads_response = $api_client->AdGroupAdService()->mutate({
    customerId => $customer_id,
    operations => $ad_group_ad_operations
  });

  my $ad_group_ad_results = $ad_group_ads_response->{results};
  printf "Added %d ads:\n", scalar @$ad_group_ad_results;
  foreach my $ad_group_ad_result (@$ad_group_ad_results) {
    printf "Added an ad with resource name '%s'.\n",
      $ad_group_ad_result->{resourceName};
  }
}

# Don't run the example if the file is being included.
if (abs_path($0) ne abs_path(__FILE__)) {
  return 1;
}

# Get Google Ads Client, credentials will be read from ~/googleads.properties.
my $api_client = Google::Ads::GoogleAds::Client->new();

# By default examples are set to die on any server returned fault.
$api_client->set_die_on_faults(1);

# Parameters passed on the command line will override any parameters set in code.
GetOptions(
  "customer_id=s"  => \$customer_id,
  "ad_group_ids=i" => \@$ad_group_ids
);
$ad_group_ids = [$ad_group_id_1, $ad_group_id_2] unless @$ad_group_ids;

# Print the help message if the parameters are not initialized in the code nor
# in the command line.
pod2usage(2) if not check_params($customer_id, $ad_group_ids);

# Call the example.
add_ad_customizer($api_client, $customer_id =~ s/-//gr, $ad_group_ids);

=pod

=head1 NAME

add_ad_customizer

=head1 DESCRIPTION

Adds an ad customizer feed and associates it with the customer. Then it adds an
ad that uses the feed to populate dynamic data.

=head1 SYNOPSIS

add_ad_customizer.pl [options]

    -help                       Show the help message.
    -customer_id                The Google Ads customer ID.
    -ad_group_ids               The ad group IDs to bind the feed items to.

=cut