Affiliate location extensions

To use affiliate location extensions, you need to create a new affiliate location extensions feed in your account. Perform a FeedService.MutateFeeds create operation to create the feed:

Java

private String createAffiliateLocationExtensionFeed(
    GoogleAdsClient googleAdsClient, long customerId, long chainId) {
  // Removes all existing location extension feeds. This is an optional step, but is required for
  // this code example to run correctly more than once. This is because:
  //   1. Google Ads only allows one location extension feed per email address.
  //   2. A Google Ads account cannot have a location extension feed and an affiliate
  // location extension feed at the same time.
  removeLocationExtensionFeeds(googleAdsClient, customerId);

  // Creates a feed that will sync to retail addresses for a given retail chain ID.
  // Do not add FeedAttributes to this object as Google Ads will add
  // them automatically because this will be a system generated feed.
  Feed feed =
      Feed.newBuilder()
          .setName("Affiliate Location Extension feed #" + getPrintableDateTime())
          .setAffiliateLocationFeedData(
              AffiliateLocationFeedData.newBuilder()
                  .addChainIds(chainId)
                  .setRelationshipType(AffiliateLocationFeedRelationshipType.GENERAL_RETAILER))
          // Since this feed's contents will be managed by Google,
          // you must set its origin to GOOGLE.
          .setOrigin(FeedOrigin.GOOGLE)
          .build();

  // Constructs an operation to create the feed.
  FeedOperation op = FeedOperation.newBuilder().setCreate(feed).build();

  // Creates the FeedServiceClient.
  try (FeedServiceClient feedService =
      googleAdsClient.getLatestVersion().createFeedServiceClient()) {
    // Issues a mutate request to add the feed.
    MutateFeedsResponse response =
        feedService.mutateFeeds(String.valueOf(customerId), ImmutableList.of(op));

    // Displays the results.
    String resourceName = response.getResults(0).getResourceName();
    System.out.printf(
        "Affliate location extension feed created with resource name: %s.%n", resourceName);

    return resourceName;
  }
}
      

C#

private static string CreateAffiliateLocationExtensionFeed(GoogleAdsClient client,
    long customerId, long chainId)
{
    // Optional: Delete all existing location extension feeds. This is an optional step, and
    // is required for this code example to run correctly more than once.
    // 1. Google Ads only allows one location extension feed per email address.
    // 2. A Google Ads account cannot have a location extension feed and an affiliate
    // location extension feed at the same time.
    DeleteLocationExtensionFeeds(client, customerId);

    // Get the FeedServiceClient.
    FeedServiceClient feedService = client.GetService(Services.V7.FeedService);

    // Creates a feed that will sync to retail addresses for a given retail chain ID. Do not
    // add FeedAttributes to this object as Google Ads will add them automatically because
    // this will be a system generated feed.
    Feed feed = new Feed()
    {
        Name = "Affiliate Location Extension feed #" + ExampleUtilities.GetRandomString(),

        AffiliateLocationFeedData = new AffiliateLocationFeedData()
        {
            ChainIds = { chainId },
            RelationshipType = AffiliateLocationFeedRelationshipType.GeneralRetailer
        },
        // Since this feed's contents will be managed by Google, you must set its origin to
        // GOOGLE.
        Origin = FeedOrigin.Google
    };

    FeedOperation operation = new FeedOperation()
    {
        Create = feed
    };

    // Adds the feed.
    MutateFeedsResponse response =
        feedService.MutateFeeds(customerId.ToString(), new[] { operation });

    // Displays the results.
    string feedResourceName = response.Results[0].ResourceName;
    Console.WriteLine($"Affliate location extension feed created with resource name: " +
        $"{feedResourceName}.");
    return feedResourceName;
}
      

PHP

private static function createAffiliateLocationExtensionFeed(
    GoogleAdsClient $googleAdsClient,
    int $customerId,
    int $chainId
): string {
    // Creates a feed that will sync to retail addresses for a given retail chain ID.
    // Do not add feed attributes, Google Ads will add them automatically because this will
    // be a system generated feed.
    $feed = new Feed([
        'name' => 'Affiliate Location Extension feed #' . Helper::getPrintableDatetime(),
        'affiliate_location_feed_data' => new AffiliateLocationFeedData([
            'chain_ids' => [$chainId],
            'relationship_type' => AffiliateLocationFeedRelationshipType::GENERAL_RETAILER
        ]),
        // Since this feed's contents will be managed by Google, you must set its origin to
        // GOOGLE.
        'origin' => FeedOrigin::GOOGLE
    ]);

    // Creates the feed operation.
    $operation = new FeedOperation();
    $operation->setCreate($feed);

    // Issues a mutate request to add the feed and prints some information.
    $feedServiceClient = $googleAdsClient->getFeedServiceClient();
    $response = $feedServiceClient->mutateFeeds($customerId, [$operation]);
    $feedResourceName = $response->getResults()[0]->getResourceName();
    printf(
        "Affiliate location extension feed created with resource name: '%s'.%s",
        $feedResourceName,
        PHP_EOL
    );

    return $feedResourceName;
}
      

Python

def _create_affiliate_location_extension_feed(client, customer_id, chain_id):
    """Creates the Affiliate Location Extension feed.

    Args:
        client: The Google Ads API client.
        customer_id: The Google Ads customer ID.
        chain_id: The retail chain ID.

    Returns:
        The string resource name of the newly created Affiliate Location
        Extension feed.
    """
    # Optional: Remove all existing location extension feeds. This is an
    # optional step, and is required for this code example to run correctly more
    # than once.
    # This is because Google Ads only allows one location extension feed per
    # email address, and a Google Ads account cannot have a location extension
    # feed and an affiliate location extension feed at the same time.
    _remove_location_extension_feeds(client, customer_id)

    # Get the FeedServiceClient.
    feed_service = client.get_service("FeedService")

    # Create a feed that will sync to retail addresses for a given retail chain
    # ID. Do not add FeedAttributes to this object as Google Ads will add
    # them automatically as this will be a system generated feed.
    feed_operation = client.get_type("FeedOperation")
    feed = feed_operation.create
    feed.name = f"Affiliate Location Extension feed #{uuid4()}"
    feed.affiliate_location_feed_data.chain_ids.append(chain_id)
    feed.affiliate_location_feed_data.relationship_type = client.get_type(
        "AffiliateLocationFeedRelationshipTypeEnum"
    ).AffiliateLocationFeedRelationshipType.GENERAL_RETAILER
    # Since this feed's contents will be managed by Google, you must set its
    # origin to GOOGLE.
    feed.origin = client.get_type("FeedOriginEnum").FeedOrigin.GOOGLE

    # Add the feed.
    mutate_feeds_response = feed_service.mutate_feeds(
        customer_id=customer_id, operations=[feed_operation]
    )

    # Display the results.
    feed_resource_name = mutate_feeds_response.results[0].resource_name
    print(
        "Affliate location extension feed created with resource name: "
        f"{feed_resource_name}."
    )
    return feed_resource_name
      

Ruby

def create_affiliate_location_extension_feed(client, customer_id, chain_id)
  # Creates a feed that will sync to retail addresses for a given retail
  # chain ID.
  # Do not add feed attributes, Google Ads will add them automatically because
  # this will be a system generated feed.
  operation = client.operation.create_resource.feed do |feed|
    feed.name = "Affiliate Location Extension feed ##{(Time.new.to_f * 1000).to_i}"
    feed.affiliate_location_feed_data = client.resource.affiliate_location_feed_data do |data|
      data.chain_ids << chain_id
      data.relationship_type = :GENERAL_RETAILER
    end
    # Since this feed's contents will be managed by Google, you must set its
    # origin to GOOGLE.
    feed.origin = :GOOGLE
  end

  # Issues a mutate request to add the feed and prints some information.
  response = client.service.feed.mutate_feeds(
    customer_id: customer_id,
    operations: [operation],
  )

  feed_resource_name = response.results.first.resource_name
  puts "Affiliate location extension feed created with resource name: #{feed_resource_name}"

  feed_resource_name
end
      

Perl

sub create_affiliate_location_extension_feed {
  my ($api_client, $customer_id, $chain_id) = @_;

  # Create a feed that will sync to retail addresses for a given retail chain ID.
  # Do not add feed attributes, Google Ads will add them automatically because
  # this will be a system generated feed.
  my $feed = Google::Ads::GoogleAds::V7::Resources::Feed->new({
      name => "Affiliate Location Extension feed #" . uniqid(),
      affiliateLocationFeedData =>
        Google::Ads::GoogleAds::V7::Resources::AffiliateLocationFeedData->new({
          chainIds         => [$chain_id],
          relationshipType => GENERAL_RETAILER
        }
        ),
      # Since this feed's contents will be managed by Google, you must set its
      # origin to GOOGLE.
      origin => GOOGLE
    });

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

  # Issue a mutate request to add the feed and print some information.
  my $response = $api_client->FeedService()->mutate({
      customerId => $customer_id,
      operations => [$operation]});
  my $feed_resource_name = $response->{results}[0]{resourceName};
  printf
    "Affiliate location extension feed created with resource name: '%s'.\n",
    $feed_resource_name;

  return $feed_resource_name;
}
      

You need to populate the following fields that are specific to location extensions feeds:

Attribute Required Description
origin Yes Since the location extensions feed is system-generated, you need to set the origin field to GOOGLE.
attributes No Do not specify any attributes for the feed. Google Ads will create these for you automatically because this is a system-generated feed.
affiliate_location_feed_data No Setting the affiliate_location_feed_data attribute to a AffiliateLocationFeedData object on your feed tells Google Ads to:
  • Automatically create feed attributes for your feed.
  • Automatically create a FeedMapping for your feed.
  • Populate the feed with a list of locations that corresponds to the retail chains that you specified in the chain_ids attribute.

Attributes of AffiliateLocationFeedData

Attribute Required Description
chain_ids Yes The list of chains that you want to advertise. See the list of valid chain IDs.
relationship_type Yes The relationship type between the advertiser and retail chains.

Wait for the feed to be ready

Once the Feed is created, Google Ads will create the feed attributes and FeedMapping. Afterwards, it will populate the feed contents by creating the FeedItem objects that correspond to the locations in the GMB account.

You need to wait until the FeedMapping is created to ensure that the feed is properly set up, and that it can be used for the next steps. This can be done by attempting to retrieve the FeedMapping for the relevant feed with placeholder_type equal to AFFILIATE_LOCATION.

Java

private Optional<FeedMapping> getFeedMapping(
    GoogleAdsClient googleAdsServiceClient, long customerId, String feedResourceName) {
  String query =
      String.format(
          "SELECT"
              + "  feed_mapping.resource_name, "
              + "  feed_mapping.attribute_field_mappings, "
              + "  feed_mapping.status "
              + "FROM"
              + "  feed_mapping "
              + "WHERE feed_mapping.feed = '%s'"
              + "  AND feed_mapping.status = ENABLED "
              + "  AND feed_mapping.placeholder_type = AFFILIATE_LOCATION "
              + "LIMIT 1",
          feedResourceName);
  try (GoogleAdsServiceClient client =
      googleAdsServiceClient.getLatestVersion().createGoogleAdsServiceClient()) {
    SearchPagedResponse response = client.search(String.valueOf(customerId), query);
    Iterator<GoogleAdsRow> iterator = response.iterateAll().iterator();
    if (iterator.hasNext()) {
      return Optional.of(iterator.next().getFeedMapping());
    }
    return Optional.empty();
  }
}
      

C#

private static FeedMapping GetAffiliateLocationExtensionFeedMapping(GoogleAdsClient client,
    long customerId, string feedResourceName)
{
    // Get the GoogleAdsService.
    GoogleAdsServiceClient googleAdsService = client.GetService(
        Services.V7.GoogleAdsService);

    // Create the query.
    string query = $"SELECT feed_mapping.resource_name, " +
        $"feed_mapping.attribute_field_mappings, feed_mapping.status FROM " +
        $"feed_mapping WHERE feed_mapping.feed = '{feedResourceName}' and " +
        $"feed_mapping.status = ENABLED and feed_mapping.placeholder_type = " +
        "AFFILIATE_LOCATION LIMIT 1";

    // Issue a search request.
    PagedEnumerable<SearchGoogleAdsResponse, GoogleAdsRow> result =
        googleAdsService.Search(customerId.ToString(), query);

    // Display the results.
    GoogleAdsRow googleAdsRow = result.FirstOrDefault();
    return (googleAdsRow == null) ? null : googleAdsRow.FeedMapping;
}
      

PHP

private static function getAffiliateLocationExtensionFeedMapping(
    GoogleAdsClient $googleAdsClient,
    int $customerId,
    string $feedResourceName
): ?FeedMapping {
    $googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient();
    // Creates a query that retrieves the feed mapping.
    $query = sprintf(
        "SELECT feed_mapping.resource_name, " .
        "feed_mapping.attribute_field_mappings, " .
        "feed_mapping.status " .
        "FROM feed_mapping " .
        "WHERE feed_mapping.feed = '%s' " .
        "AND feed_mapping.status = ENABLED " .
        "AND feed_mapping.placeholder_type = AFFILIATE_LOCATION " .
        "LIMIT 1",
        $feedResourceName
    );

    // Issues a search request.
    $response = $googleAdsServiceClient->search(
        $customerId,
        $query,
        ['returnTotalResultsCount' => true]
    );

    return $response->getPage()->getPageElementCount() === 1
        ? $response->getIterator()->current()->getFeedMapping()
        : null;
}
      

Python

def _get_affiliate_location_extension_feed_mapping(
    client, customer_id, feed_resource_name
):
    """Gets the Affiliate Location Extension feed mapping.

    Args:
        client: The Google Ads API client.
        customer_id: The Google Ads customer ID.
        feed_resource_name: The feed resource name.
    Returns:
        The newly created feed mapping.
    """
    # Get the GoogleAdsService.
    googleads_service = client.get_service("GoogleAdsService")

    # Create the query.
    query = f"""
        SELECT
          feed_mapping.resource_name,
          feed_mapping.attribute_field_mappings,
          feed_mapping.status
        FROM feed_mapping
        WHERE
          feed_mapping.feed = '{feed_resource_name}'
          AND feed_mapping.status = ENABLED
          AND feed_mapping.placeholder_type = AFFILIATE_LOCATION
        LIMIT 1"""

    # Issue a search request.
    search_results = googleads_service.search(
        customer_id=customer_id, query=query
    )

    # Return the feed mapping that results from the search.
    # It is possible that the feed is not yet ready, so we catch the exception
    # if there the feed mapping is not yet available.
    try:
        row = next(iter(search_results))
    except StopIteration:
        return None
    else:
        return row.feed_mapping
      

Ruby

def get_affiliated_location_extension_feed_mapping(
  client,
  customer_id,
  feed_resource_name)
  # Creates a query that retrieves the feed mapping.
  query = <<~QUERY
    SELECT feed_mapping.resource_name,
           feed_mapping.attribute_field_mappings,
           feed_mapping.status
    FROM feed_mapping
    WHERE feed_mapping.feed = '#{feed_resource_name}'
    AND feed_mapping.status = ENABLED
    AND feed_mapping.placeholder_type = AFFILIATE_LOCATION
    LIMIT 1
  QUERY

  # Issues a search request
  responses = client.service.google_ads.search(
    customer_id: customer_id,
    query: query,
    return_total_results_count: true,
  )

  response = responses.page.response
  response.total_results_count == 1 ? response.results.first.feed_mapping : nil
end
      

Perl

sub get_affiliate_location_extension_feed_mapping {
  my ($api_client, $customer_id, $feed_resource_name) = @_;

  # Create a query that retrieves the feed mapping.
  my $search_query =
    "SELECT feed_mapping.resource_name, " .
    "feed_mapping.attribute_field_mappings, " .
    "feed_mapping.status FROM feed_mapping " .
    "WHERE feed_mapping.feed = '$feed_resource_name' " .
    "AND feed_mapping.status = ENABLED " .
    "AND feed_mapping.placeholder_type = AFFILIATE_LOCATION LIMIT 1";

  # Issue a search request.
  my $response = $api_client->GoogleAdsService()->search({
    customerId              => $customer_id,
    query                   => $search_query,
    returnTotalResultsCount => "true"
  });

  return $response->{totalResultsCount} && $response->{totalResultsCount} == 1
    ? $response->{results}[0]{feedMapping}
    : undef;
}
      

If the FeedMapping is not yet available, retry the calls with an exponential back-off policy until the Feed is ready.

Java

private FeedMapping waitForFeedToBeReady(
    GoogleAdsClient googleAdsServiceClient, long customerId, String feedResourceName) {
  int numAttempts = 0;
  int sleepSeconds = 0;

  // Waits for Google's servers to setup the feed with feed attributes and attribute mapping.
  // This process is asynchronous, so we wait until the feed mapping is created, with exponential
  // backoff.
  while (numAttempts < MAX_FEEDMAPPING_RETRIEVAL_ATTEMPTS) {
    Optional<FeedMapping> feedMapping =
        getFeedMapping(googleAdsServiceClient, customerId, feedResourceName);

    if (feedMapping.isPresent()) {
      System.out.printf("Feed with resource name '%s' is now ready.%n", feedResourceName);
      return feedMapping.get();
    } else {
      numAttempts++;
      sleepSeconds = (int) (5 * Math.pow(2, numAttempts));
      System.out.printf(
          "Checked: %d time(s). Feed is not ready "
              + "yet. Waiting %d seconds before trying again.%n",
          numAttempts, sleepSeconds);
      try {
        Thread.sleep(sleepSeconds * 1000);
      } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        throw new RuntimeException(e);
      }
    }
  }
  throw new ApiException(
      String.format("Feed is not ready after %d retries.", numAttempts),
      null,
      GrpcStatusCode.of(Code.DEADLINE_EXCEEDED),
      true);
}
      

C#

private static FeedMapping WaitForFeedToBeReady(GoogleAdsClient client, long customerId,
    string feedResourceName)
{
    int numAttempts = 0;
    int sleepSeconds = 0;

    while (numAttempts < MAX_FEEDMAPPING_RETRIEVAL_ATTEMPTS)
    {
        // Once you create a feed, Google's servers will setup the feed by creating feed
        // attributes and feed mapping. Once the feed mapping is created, it is ready to be
        // used for creating customer feed. This process is asynchronous, so we wait until
        // the feed mapping is created, peforming exponential backoff.
        FeedMapping feedMapping = GetAffiliateLocationExtensionFeedMapping(
            client, customerId, feedResourceName);

        if (feedMapping == null)
        {
            numAttempts++;
            sleepSeconds = (int) (5 * Math.Pow(2, numAttempts));
            Console.WriteLine($"Checked: #{numAttempts} time(s). Feed is not ready " +
                $"yet. Waiting {sleepSeconds} seconds before trying again.");
            Thread.Sleep(sleepSeconds * 1000);
        }
        else
        {
            Console.WriteLine($"Feed {feedResourceName} is now ready.");
            return feedMapping;
        }
    }
    throw new RpcException(new Status(StatusCode.DeadlineExceeded,
        $"Feed is not ready after {MAX_FEEDMAPPING_RETRIEVAL_ATTEMPTS}" +
        $" retries."));
}
      

PHP

private static function waitForFeedToBeReady(
    GoogleAdsClient $googleAdsClient,
    int $customerId,
    string $feedResourceName
): FeedMapping {
    $numAttempts = 0;

    while ($numAttempts < self::MAX_FEED_MAPPING_RETRIEVAL_ATTEMPTS) {
        // Once you create a feed, Google's servers will setup the feed by creating feed
        // attributes and feed mapping. Once the feed mapping is created, it is ready to be
        // used for creating customer feed.
        // This process is asynchronous, so we wait until the feed mapping is created,
        // performing exponential backoff.
        $feedMapping = self::getAffiliateLocationExtensionFeedMapping(
            $googleAdsClient,
            $customerId,
            $feedResourceName
        );

        if (is_null($feedMapping)) {
            $numAttempts++;
            $sleepSeconds = intval(5 * pow(2, $numAttempts));
            printf(
                'Checked: %d time(s). Feed is not ready yet. ' .
                'Waiting %d seconds before trying again.%s',
                $numAttempts,
                $sleepSeconds,
                PHP_EOL
            );
            sleep($sleepSeconds);
        } else {
            printf("Feed '%s' is now ready.%s", $feedResourceName, PHP_EOL);
            return $feedMapping;
        }
    }

    throw new RuntimeException(sprintf(
        "The affiliate location feed mapping is still not ready after %d attempt(s).%s",
        self::MAX_FEED_MAPPING_RETRIEVAL_ATTEMPTS,
        PHP_EOL
    ));
}
      

Python

def _wait_for_feed_to_be_ready(client, customer_id, feed_resource_name):
    """Waits for the Affliate location extension feed to be ready.

    Args:
        client: The Google Ads API client.
        customer_id: The Google Ads customer ID.
        feed_resource_name: The resource name of the feed.

    Returns:
        The newly created FeedMapping.

    Raises:
        Exception: if the feed is not ready after the specified number of
            retries.
    """
    num_attempts = 0
    sleep_seconds = 0

    while num_attempts < MAX_FEEDMAPPING_RETRIEVAL_ATTEMPTS:
        # Once you create a feed, Google's servers will setup the feed by
        # creating feed attributes and feed mapping. Once the feed mapping is
        # created, it is ready to be used for creating customer feed.
        # This process is asynchronous, so we wait until the feed mapping is
        # created, peforming exponential backoff.
        feed_mapping = _get_affiliate_location_extension_feed_mapping(
            client, customer_id, feed_resource_name
        )

        if feed_mapping is None:
            num_attempts += 1
            sleep_seconds = 5 * 2 ** num_attempts
            print(
                f"Checked {num_attempts} time(s). Feed is not ready "
                f"yet. Waiting {sleep_seconds} seconds before trying again."
            )
            sleep(sleep_seconds)
        else:
            print(f"Feed {feed_resource_name} is now ready.")
            return feed_mapping

    raise Exception(
        f"Feed is not ready after "
        f"{MAX_FEEDMAPPING_RETRIEVAL_ATTEMPTS} retries."
    )
      

Ruby

def wait_for_feed_to_be_ready(client, customer_id, feed_resource_name)
  number_of_attempts = 0

  while number_of_attempts < MAX_FEEDMAPPING_RETRIEVAL_ATTEMPTS
    # Once you create a feed, Google's servers will setup the feed by creating
    # feed attributes and feed mapping. Once the feed mapping is created, it is
    # ready to be used for creating customer feed.
    # This process is asynchronous, so we wait until the feed mapping is
    # created, performing exponential backoff.
    feed_mapping = get_affiliated_location_extension_feed_mapping(
      client, customer_id, feed_resource_name)

    if feed_mapping.nil?
      number_of_attempts += 1
      sleep_seconds = POLL_FREQUENCY_SECONDS * (2 ** number_of_attempts)
      puts "Checked #{number_of_attempts} time(s). Feed is not ready yet. " \
        "Waiting #{sleep_seconds} seconds before trying again."
      sleep sleep_seconds
    else
      puts "Feed #{feed_resource_name} is now ready."
      return feed_mapping
    end
  end

  raise "The affiliate location feed mapping is still not ready after " \
    "#{MAX_FEEDMAPPING_RETRIEVAL_ATTEMPTS} attempt(s)."
end
      

Perl

sub wait_for_feed_to_be_ready {
  my ($api_client, $customer_id, $feed_resource_name) = @_;

  my $num_attempts = 0;
  while ($num_attempts < MAX_FEED_MAPPING_RETRIEVAL_ATTEMPTS) {
    # Once you create a feed, Google's servers will setup the feed by creating
    # feed attributes and feed mapping. Once the feed mapping is created, it is
    # ready to be used for creating customer feed.
    # This process is asynchronous, so we wait until the feed mapping is created,
    # performing exponential backoff.
    my $feed_mapping =
      get_affiliate_location_extension_feed_mapping($api_client, $customer_id,
      $feed_resource_name);

    if (!$feed_mapping) {
      $num_attempts++;
      my $sleep_seconds = 5 * (2**$num_attempts);
      printf "Checked: %d time(s). Feed is not ready yet. " .
        "Waiting %d seconds before trying again.\n",
        $num_attempts,
        $sleep_seconds;
      sleep($sleep_seconds);
    } else {
      printf "Feed '%s' is now ready.\n", $feed_resource_name;
      return $feed_mapping;
    }
  }

  die(
    sprintf "The affiliate location feed mapping is still not ready " .
      "after %d attempt(s).\n",
    MAX_FEED_MAPPING_RETRIEVAL_ATTEMPTS
  );
}
      

Associate the feed with the customer, campaign, or ad group

Once the feed is ready to use, you can create a CampaignFeed object to associate it with a campaign. Associating the feed to an ad group or the customer is similar, except that you'd create an AdGroupFeed or CustomerFeed object, respectively, and use an appropriate matching function.

The following code snippet filters the affiliate location extensions for a campaign to serve only locations from a single retail chain ID.

Java

private void createCampaignFeed(
    GoogleAdsClient googleAdsClient,
    long customerId,
    long campaignId,
    FeedMapping feedMapping,
    String feedResourceName,
    long chainId) {
  // Gets the attribute ID that is used for the chain ID. This will be used to filter the feed to
  // extract affiliate locations.
  long attributeIdForChainId = getAttributeIdForChainId(feedMapping);

  // Extracts the feed ID.
  long feedId = Long.valueOf(FeedName.parse(feedResourceName).getFeedId());

  // Constructs a matching function string which filters the Feed to extract affiliate locations.
  String matchingFunction =
      String.format("IN(FeedAttribute[%d, %d], %d)", feedId, attributeIdForChainId, chainId);

  // Creates a CampaignFeed object.
  CampaignFeed campaignFeed =
      CampaignFeed.newBuilder()
          .setFeed(feedResourceName)
          .addPlaceholderTypes(PlaceholderType.AFFILIATE_LOCATION)
          .setMatchingFunction(
              MatchingFunction.newBuilder().setFunctionString(matchingFunction).build())
          .setCampaign(ResourceNames.campaign(customerId, campaignId))
          .build();

  // Creates an operation to create the CampaignFeed.
  CampaignFeedOperation operation =
      CampaignFeedOperation.newBuilder().setCreate(campaignFeed).build();

  // Adds a CampaignFeed that associates the feed with this campaign for
  // the AFFILIATE_LOCATION placeholder type.
  try (CampaignFeedServiceClient feedServiceClient =
      googleAdsClient.getLatestVersion().createCampaignFeedServiceClient()) {
    MutateCampaignFeedsResponse response =
        feedServiceClient.mutateCampaignFeeds(
            String.valueOf(customerId), ImmutableList.of(operation));
    System.out.printf(
        "Campaign feed created with resource name: %s.%n",
        response.getResultsList().get(0).getResourceName());
  }
}
      

C#

private static void CreateCampaignFeed(GoogleAdsClient client, long customerId,
    long campaignId, FeedMapping feedMapping, string feedResourceName, long chainId)
{
    // Get the CampaignFeedService.
    CampaignFeedServiceClient campaignFeedService = client.GetService(
        Services.V7.CampaignFeedService);

    long attributeIdForChainId = GetAttributeIdForChainId(feedMapping);
    string feedId = FeedName.Parse(feedResourceName).FeedId;

    string matchingFunction =
        $"IN(FeedAttribute[{feedId}, {attributeIdForChainId}], {chainId})";
    // Adds a CampaignFeed that associates the feed with this campaign for the
    // AFFILIATE_LOCATION placeholder type.
    CampaignFeed campaignFeed = new CampaignFeed()
    {
        Feed = feedResourceName,
        PlaceholderTypes = { PlaceholderType.AffiliateLocation },
        MatchingFunction = new MatchingFunction()
        {
            FunctionString = matchingFunction
        },
        Campaign = ResourceNames.Campaign(customerId, campaignId),
    };

    CampaignFeedOperation operation = new CampaignFeedOperation()
    {
        Create = campaignFeed
    };

    MutateCampaignFeedsResponse campaignFeedsResponse =
        campaignFeedService.MutateCampaignFeeds(
            customerId.ToString(), new[] { operation });

    // Displays the result.
    string addedCampaignFeed = campaignFeedsResponse.Results[0].ResourceName;
    Console.WriteLine($"Campaign feed created with resource name: {addedCampaignFeed}.");
    return;
}
      

PHP

private static function createCampaignFeed(
    GoogleAdsClient $googleAdsClient,
    int $customerId,
    int $campaignId,
    FeedMapping $feedMapping,
    string $feedResourceName,
    int $chainId
) {
    $matchingFunction = sprintf(
        'IN(FeedAttribute[%d, %d], %d)',
        FeedServiceClient::parseName($feedResourceName)['feed'],
        self::getAttributeIdForChainId($feedMapping),
        $chainId
    );

    // Adds a campaign feed that associates the feed with this campaign for the
    // AFFILIATE_LOCATION placeholder type.
    $campaignFeed = new CampaignFeed([
        'feed' => $feedResourceName,
        'placeholder_types' => [PlaceholderType::AFFILIATE_LOCATION],
        'matching_function' => new MatchingFunction(['function_string' => $matchingFunction]),
        'campaign' => ResourceNames::forCampaign($customerId, $campaignId)
    ]);

    // Creates the campaign feed operation.
    $operation = new CampaignFeedOperation();
    $operation->setCreate($campaignFeed);

    // Issues a mutate request to add the campaign feed and prints some information.
    $campaignFeedServiceClient = $googleAdsClient->getCampaignFeedServiceClient();
    $response = $campaignFeedServiceClient->MutateCampaignFeeds($customerId, [$operation]);
    printf(
        "Campaign feed created with resource name: '%s'.%s",
        $response->getResults()[0]->getResourceName(),
        PHP_EOL
    );
}
      

Python

def _create_campaign_feed(
    client, customer_id, campaign_id, feed_mapping, feed_resource_name, chain_id
):
    """Creates the campaign feed.

    Args:
        client: The Google Ads API client.
        customer_id: The Google Ads customer ID.
        campaign_id: The campaign ID to which the affiliate location extensions
            will be added.
        feed_mapping: The affliate location extension feedmapping for the feed
            resource name.
        feed_resource_name: The feed resource name.
        chain_id: The retail chain ID.
    """
    # Get the CampaignFeedService.
    campaign_feed_service = client.get_service("CampaignFeedService")
    feed_service = client.get_service("FeedService", versions="v6")

    attribute_id_for_chain_id = _get_attribute_id_for_chain_id(
        client, feed_mapping
    )
    feed_id = feed_service.parse_feed_path(feed_resource_name)["feed_id"]

    matching_function = (
        f"IN(FeedAttribute[{feed_id}, {attribute_id_for_chain_id}], {chain_id})"
    )

    # Add a CampaignFeed that associates the feed with this campaign for
    # the AFFILIATE_LOCATION placeholder type.
    campaign_feed_operation = client.get_type("CampaignFeedOperation")
    campaign_feed = campaign_feed_operation.create
    campaign_feed.feed = feed_resource_name
    campaign_feed.placeholder_types.append(
        client.get_type(
            "PlaceholderTypeEnum"
        ).PlaceholderType.AFFILIATE_LOCATION
    )
    campaign_feed.matching_function.function_string = matching_function
    campaign_feed.campaign = client.get_service(
        "CampaignService"
    ).campaign_path(customer_id, campaign_id)

    mutate_campaign_feeds_response = campaign_feed_service.mutate_campaign_feeds(
        customer_id=customer_id, operations=[campaign_feed_operation]
    )

    # Display the result.
    print(
        "Campaign feed created with resource name: "
        f"{mutate_campaign_feeds_response.results[0].resource_name}."
    )
      

Ruby

def create_campaign_feed(
  client,
  customer_id,
  campaign_id,
  feed_mapping,
  feed_resource_name,
  chain_id)
  matching_function = "IN(FeedAttribute[#{feed_resource_name.split('/')[3]}, " \
    "#{get_attribute_id_for_chain_id(feed_mapping)}], #{chain_id})"

  # Adds a campaign feed that associates the feed with this campaign for the
  # AFFILIATE_LOCATION placeholder type.
  operation = client.operation.create_resource.campaign_feed do |cf|
    cf.feed = feed_resource_name
    cf.placeholder_types << :AFFILIATE_LOCATION
    cf.matching_function = client.resource.matching_function do |m|
      m.function_string = matching_function
    end
    cf.campaign = client.path.campaign(customer_id, campaign_id)
  end

  # Issues a mutate request to add the campaign feed and prints some information.
  response = client.service.campaign_feed.mutate_campaign_feeds(
    customer_id: customer_id,
    operations: [operation],
  )
  puts "Campaign feed created with resource name: " \
    "#{response.results.first.resource_name}"
end
      

Perl

sub create_campaign_feed {
  my ($api_client, $customer_id, $campaign_id, $feed_mapping,
    $feed_resource_name, $chain_id)
    = @_;

  my $feed_id                   = $1 if $feed_resource_name =~ /(\d+)$/;
  my $attribute_id_for_chain_id = get_attribute_id_for_chain_id($feed_mapping);
  my $matching_function =
    "IN(FeedAttribute[$feed_id, $attribute_id_for_chain_id], $chain_id)";

  # Add a campaign feed that associates the feed with this campaign for the
  # AFFILIATE_LOCATION placeholder type.
  my $campaign_feed = Google::Ads::GoogleAds::V7::Resources::CampaignFeed->new({
      feed             => $feed_resource_name,
      placeholderTypes => AFFILIATE_LOCATION,
      matchingFunction =>
        Google::Ads::GoogleAds::V7::Common::MatchingFunction->new({
          functionString => $matching_function
        }
        ),
      campaign => Google::Ads::GoogleAds::V7::Utils::ResourceNames::campaign(
        $customer_id, $campaign_id
      )});

  # Create the campaign feed operation.
  my $operation =
    Google::Ads::GoogleAds::V7::Services::CampaignFeedService::CampaignFeedOperation
    ->new({
      create => $campaign_feed
    });

  # Issue a mutate request to add the campaign feed and print some information.
  my $response = $api_client->CampaignFeedService()->mutate({
      customerId => $customer_id,
      operations => [$operation]});

  printf
    "Campaign feed created with resource name: '%s'.\n",
    $response->{results}[0]{resourceName};
}
      

The feed attribute ID can be retrieved from the feed's FeedMapping as follows:

Java

private long getAttributeIdForChainId(FeedMapping feedMapping) {
  Optional<AttributeFieldMapping> fieldMapping =
      feedMapping.getAttributeFieldMappingsList().stream()
          .filter(
              m -> m.getAffiliateLocationField() == AffiliateLocationPlaceholderField.CHAIN_ID)
          .findFirst();
  if (!fieldMapping.isPresent()) {
    throw new RuntimeException("Affiliate location field mapping isn't setup correctly");
  }
  return fieldMapping.get().getFeedAttributeId();
}
      

C#

public static long GetAttributeIdForChainId(FeedMapping feedMapping)
{
    foreach (AttributeFieldMapping fieldMapping in feedMapping.AttributeFieldMappings)
    {
        if (fieldMapping.AffiliateLocationField ==
            AffiliateLocationPlaceholderField.ChainId)
        {
            return fieldMapping.FeedAttributeId;
        }
    }
    throw new ArgumentException("Affiliate location feed mapping isn't setup correctly.");
}
      

PHP

private static function getAttributeIdForChainId(FeedMapping $feedMapping): int
{
    foreach ($feedMapping->getAttributeFieldMappings() as $fieldMapping) {
        /** @var AttributeFieldMapping $fieldMapping */
        if (
            $fieldMapping->getAffiliateLocationField()
            === AffiliateLocationPlaceholderField::CHAIN_ID
        ) {
            return $fieldMapping->getFeedAttributeId();
        }
    }

    throw new RuntimeException(
        "Affiliate location feed mapping isn't setup correctly." . PHP_EOL
    );
}
      

Python

def _get_attribute_id_for_chain_id(client, feed_mapping):
    """Gets the feed attribute ID for the retail chain ID.

    Args:
        client: The Google Ads API client.
        feed_mapping: The FeedMapping in which to search.
    Returns:
        The feed attribute ID.
    Raises:
        Exception: If no AffiliateLocationField with a retail chain ID is found
            in the FeedMapping.
    """
    for field_mapping in feed_mapping.attribute_field_mappings:
        if (
            field_mapping.affiliate_location_field
            == client.get_type(
                "AffiliateLocationPlaceholderFieldEnum"
            ).AffiliateLocationPlaceholderField.CHAIN_ID
        ):
            return field_mapping.feed_attribute_id

    raise Exception(
        "No AffiliateLocationField with a retail chain ID was "
        "found in the FeedMapping."
    )
      

Ruby

def get_attribute_id_for_chain_id(feed_mapping)
  feed_mapping.attribute_field_mappings.each do |fm|
    if fm.affiliate_location_field == :CHAIN_ID
      return fm.feed_attribute_id
    end
  end

  raise "Affiliate location feed mapping isn't setup correctly."
end
      

Perl

sub get_attribute_id_for_chain_id {
  my ($feed_mapping) = @_;

  foreach my $field_mapping (@{$feed_mapping->{attributeFieldMappings}}) {
    if ($field_mapping->{affiliateLocationField} eq CHAIN_ID) {
      return $field_mapping->{feedAttributeId};
    }
  }

  die "Affiliate location feed mapping isn't setup correctly.";
}