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.V6.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; }
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::V6::Resources::Feed->new({ name => "Affiliate Location Extension feed #" . uniqid(), affiliateLocationFeedData => Google::Ads::GoogleAds::V6::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::V6::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:
|
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
.
C#
private static FeedMapping GetAffiliateLocationExtensionFeedMapping(GoogleAdsClient client, long customerId, string feedResourceName) { // Get the GoogleAdsService. GoogleAdsServiceClient googleAdsService = client.GetService( Services.V6.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; }
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.
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 )); }
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.
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.V6.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 ); }
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::V6::Resources::CampaignFeed->new({ feed => $feed_resource_name, placeholderTypes => AFFILIATE_LOCATION, matchingFunction => Google::Ads::GoogleAds::V6::Common::MatchingFunction->new({ functionString => $matching_function } ), campaign => Google::Ads::GoogleAds::V6::Utils::ResourceNames::campaign( $customer_id, $campaign_id )}); # Create the campaign feed operation. my $operation = Google::Ads::GoogleAds::V6::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:
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 ); }
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."; }