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:

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.V5.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;
}

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 wish 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.

C#

private static FeedMapping GetAffiliateLocationExtensionFeedMapping(GoogleAdsClient client,
    long customerId, string feedResourceName)
{
    // Get the GoogleAdsService.
    GoogleAdsServiceClient googleAdsService = client.GetService(
        Services.V5.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;
}

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

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."));
}

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.

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.V5.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;
}

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

C#

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