Google Ads

Customizing Text Ads  |  AdWords API  |  Google Developers

Customizing standard and expanded text ads can be done through ad customizers,
countdowns, and IF functions.
Ad customizers offer greater flexibility than using
ad parameters.

An ad customizer is a
feed-based solution for
injecting dynamic information into your ads. You can set up a feed with
targeting options for specific campaigns, ad groups, and/or keywords, and
then create ads that reference the information in the feed, so the values in
the feed are shown at serve time.

You can put strings, prices, numbers, and even a countdown to a specific
date or time in your ad.

Ad customizers

A common use case for ad customizers is promoting a sale price on an item
during a specific date range. To do this, you set up a feed with a string
attribute for the item name, another string attribute for the price, and
a date attribute for the date your sale ends, then populate a feed item

When setting up an ad, you reference the feed item, its name attribute,
and its sale price attribute—Google Ads automatically populates the ad
with the name and price from the feed item.

To use the feed item’s end date, you include the date attribute in a function
that tells Google Ads to display a countdown to the end date in your ad. When
creating the ad, reference the feed item and its name, sale price, and end date
attributes—Google Ads automatically populates the ad with the name, price,
and end date from the feed item.

When you have your next sale, you can reuse the ad by updating your feed
item’s price and end date values, instead of creating a new ad each time.

The following sections describe all phases of this use case, including how to:

  • Set up the feed and its attributes
  • Create feed items with the values you want to appear in your ads
  • Target feed items to a specific campaign, ad group or keyword
  • Use the feed in an ad
  • Add a countdown
  • Add an IF function

Set up the feed

The first step is to create a feed with all of the attributes you’ll need to
customize your ad.

The feed below has three attributes; two of type STRING and one of type


AdCustomizerFeed customizerFeed = new AdCustomizerFeed();

AdCustomizerFeedAttribute nameAttribute = new AdCustomizerFeedAttribute();

AdCustomizerFeedAttribute priceAttribute = new AdCustomizerFeedAttribute();

AdCustomizerFeedAttribute dateAttribute = new AdCustomizerFeedAttribute();

    new AdCustomizerFeedAttribute[] {nameAttribute, priceAttribute, dateAttribute});


AdCustomizerFeed feed = new AdCustomizerFeed()
    feedName = feedName,
    feedAttributes = new AdCustomizerFeedAttribute[]
        new AdCustomizerFeedAttribute()
            name = "Name",
            type = AdCustomizerFeedAttributeType.STRING
        new AdCustomizerFeedAttribute()
            name = "Price",
            type = AdCustomizerFeedAttributeType.PRICE
        new AdCustomizerFeedAttribute()
            name = "Date",
            type = AdCustomizerFeedAttributeType.DATE_TIME


customizer_feed = {
    'feedName': feed_name,
    'feedAttributes': [
        {'type': 'STRING', 'name': 'Name'},
        {'type': 'STRING', 'name': 'Price'},
        {'type': 'DATE_TIME', 'name': 'Date'}


$nameAttribute = new AdCustomizerFeedAttribute();

$priceAttribute = new AdCustomizerFeedAttribute();

$dateAttribute = new AdCustomizerFeedAttribute();

$customizerFeed = new AdCustomizerFeed();
    [$nameAttribute, $priceAttribute, $dateAttribute]


my $name_attribute =
    type => "STRING",
    name => "Name"
my $price_attribute =
    type => "STRING",
    name => "Price"
my $date_attribute =
    type => "DATE_TIME",
    name => "Date"
my $ad_customizer_feed = Google::Ads::AdWords::v201809::AdCustomizerFeed->new(
    feedName       => $feed_name,
    feedAttributes => [$name_attribute, $price_attribute, $date_attribute]});


feed = {
  :feed_name => feed_name,
  :feed_attributes => [
    {:name => 'Name', :type => 'STRING'},
    {:name => 'Price', :type => 'PRICE'},
    {:name => 'Date', :type => 'DATE_TIME'}


Using adCustomizerFeedService As AdCustomizerFeedService = DirectCast(

    Dim feed As New AdCustomizerFeed()
    feed.feedName = feedName

    Dim attribute1 As New AdCustomizerFeedAttribute = "Name"
    attribute1.type = AdCustomizerFeedAttributeType.STRING

    Dim attribute2 As New AdCustomizerFeedAttribute = "Price"
    attribute2.type = AdCustomizerFeedAttributeType.PRICE

    Dim attribute3 As New AdCustomizerFeedAttribute = "Date"
    attribute3.type = AdCustomizerFeedAttributeType.DATE_TIME

    feed.feedAttributes = New AdCustomizerFeedAttribute() { _
                                                              attribute1, attribute2,

Take note of the IDs for the feed itself and for its attributes, as you’ll need
them when setting up the feed item. You can fetch these attributes directly from
the result of the mutate call.


AdCustomizerFeedOperation feedOperation = new AdCustomizerFeedOperation();

AdCustomizerFeed addedFeed = adCustomizerFeedService.mutate(
    new AdCustomizerFeedOperation[] {feedOperation}).getValue()[0];

    "Created ad customizer feed with ID %d, name '%s' and attributes:%n",
    addedFeed.getFeedId(), addedFeed.getFeedName());
for (AdCustomizerFeedAttribute feedAttribute : addedFeed.getFeedAttributes()) {
      "  ID: %d, name: '%s', type: %s%n",
      feedAttribute.getId(), feedAttribute.getName(), feedAttribute.getType());


AdCustomizerFeedOperation feedOperation = new AdCustomizerFeedOperation()
    operand = feed,
    @operator = (Operator.ADD)

AdCustomizerFeed addedFeed = adCustomizerFeedService.mutate(
    new AdCustomizerFeedOperation[]

    "Created ad customizer feed with ID = {0} and name = '{1}' and " +
    "attributes: ", addedFeed.feedId, addedFeed.feedName);

foreach (AdCustomizerFeedAttribute feedAttribute in addedFeed.feedAttributes)
    Console.WriteLine("  ID: {0}, name: '{1}', type: {2}",,, feedAttribute.type);


feed_service_operation = {
    'operator': 'ADD',
    'operand': customizer_feed

response = ad_customizer_feed_service.mutate([feed_service_operation])

if response and 'value' in response:
  feed = response['value'][0]
  feed_data = {
      'feedId': feed['feedId'],
      'nameId': feed['feedAttributes'][0]['id'],
      'priceId': feed['feedAttributes'][1]['id'],
      'dateId': feed['feedAttributes'][2]['id']
  print('Feed with name "%s" and ID %s was added with:n'
        'tName attribute ID %s and price attribute ID %s and date attribute'
        'ID %s') % (feed['feedName'], feed['feedId'], feed_data['nameId'],
                    feed_data['priceId'], feed_data['dateId'])


$feedOperation = new AdCustomizerFeedOperation();
$operations = [$feedOperation];

$result = $adCustomizerFeedService->mutate($operations);
$addedFeed = $result->getValue()[0];

    "Created ad customizer feed with ID %d, name '%s' and attributes:n",
if (empty($addedFeed)) {
    print "  No attributesn";
} else {
    foreach ($addedFeed->getFeedAttributes() as $feedAttribute) {
            "  ID: %d, name: '%s', type: %sn",


my $operation = Google::Ads::AdWords::v201809::AdCustomizerFeedOperation->new(
    operator => "ADD",
    operand  => $ad_customizer_feed

my $feed_result =
  $client->AdCustomizerFeedService()->mutate({operations => [$operation]});

my $added_feed = $feed_result->get_value(0);

  "Created ad customizer feed with ID %d, and name '%s' and attributes:n",
foreach my $feed_attribute (@{$added_feed->get_feedAttributes()}) {
  printf "  ID: %d, name: '%s', type: '%s'n",
    $feed_attribute->get_id(), $feed_attribute->get_name(),


operation = {:operand => feed, :operator => 'ADD'}
added_feed = ad_customizer_srv.mutate([operation])[:value].first()
puts "Created ad customizer feed with ID = %d and name = '%s'." %
    [added_feed[:feed_id], added_feed[:feed_name]]
added_feed[:feed_attributes].each do |feed_attribute|
  puts "  ID: %d, name: '%s', type: %s" %
      [feed_attribute[:id], feed_attribute[:name], feed_attribute[:type]]


Dim feedOperation As New AdCustomizerFeedOperation()
feedOperation.operand = feed
feedOperation.operator = [Operator].ADD

Dim addedFeed As AdCustomizerFeed = adCustomizerFeedService.mutate(
    New AdCustomizerFeedOperation() {feedOperation}).value(0)

Console.WriteLine("Created ad customizer feed with ID = {0} and name = '{1}'.",
                  addedFeed.feedId, addedFeed.feedName)

The returned attributes appear in the same order you specified when creating the

Create targeted FeedItems

Create a FeedItem
to restrict the feed to only a specific campaign, ad group, keyword, or location,
using the
attributes of the FeedItem.

Using the IDs retrieved when creating the feed in the step above, you can add
feed items. The code sample below passes each feed item’s values to a helper


DateTime now = new DateTime();

DateTime marsDate = new DateTime(now.getYear(), now.getMonthOfYear(), 1, 0, 0);
        "Mars", "$1234.56", marsDate.toString("yyyyMMdd HHmmss"), adCustomizerFeed));

DateTime venusDate = new DateTime(now.getYear(), now.getMonthOfYear(), 15, 0, 0);
        "Venus", "$1450.00", venusDate.toString("yyyyMMdd HHmmss"), adCustomizerFeed));


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

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


now =
mars_date = datetime(now.year, now.month, 1, 0, 0)
venus_date = datetime(now.year, now.month, 15, 0, 0)
time_format = '%Y%m%d %H%M%S'

feed_item_operations = [
        'Mars', '$1234.56', mars_date.strftime(time_format),
        'Venus', '$1450.00', venus_date.strftime(time_format),


$marsDate = mktime(0, 0, 0, date('m'), 1, date('Y'));
$venusDate = mktime(0, 0, 0, date('m'), 15, date('Y'));

// Create multiple feed item operations and add them to the operations list.
$operations[] = self::createFeedItemAddOperation(
    date('Ymd His', $marsDate),
$operations[] = self::createFeedItemAddOperation(
    date('Ymd His', $venusDate),


push @operations,
  "Mars", "$1234.56", "20140601 000000");
push @operations,
  "Venus", "$1450.00", "20140615 120000");


# Now adding feed items -- the values we'd like to place.
now_date =

items_data = [
    :name => 'Mars',
    :price => '$1234.56',
    :date => now_date.strftime('%Y%m01 000000'),
    :ad_group_id => ad_group_ids[0]
    :name => 'Venus',
    :price => '$1450.00',
    :date => now_date.strftime('%Y%m15 000000'),
    :ad_group_id => ad_group_ids[1]


Dim marsDate As New DateTime(DateTime.Now.Year, DateTime.Now.Month, 1)
feedItemOperations.Add(CreateFeedItemAddOperation(adCustomizerFeed, "Mars",
                                                      "yyyyMMdd HHmmss")))

Dim venusDate As New DateTime(DateTime.Now.Year, DateTime.Now.Month, 15)
feedItemOperations.Add(CreateFeedItemAddOperation(adCustomizerFeed, "Venus",
                                                      "yyyyMMdd HHmmss")))

The helper function sets up the feed item with the values provided:


FeedItem feedItem = new FeedItem();

List attributeValues = new ArrayList<>();

// FeedAttributes appear in the same order as they were created - Name, Price, Date.
// See the createCustomizerFeed method for details.
FeedItemAttributeValue nameAttributeValue = new FeedItemAttributeValue();

FeedItemAttributeValue priceAttributeValue = new FeedItemAttributeValue();

FeedItemAttributeValue dateAttributeValue = new FeedItemAttributeValue();

    attributeValues.toArray(new FeedItemAttributeValue[attributeValues.size()]));


FeedItem feedItem = new FeedItem()
    feedId = adCustomizerFeed.feedId,

    // FeedAttributes appear in the same order as they were created
    // - Name, Price, Date. See CreateCustomizerFeed method for details.
    attributeValues = new FeedItemAttributeValue[]
        new FeedItemAttributeValue()
            feedAttributeId = adCustomizerFeed.feedAttributes[0].id,
            stringValue = name

        new FeedItemAttributeValue()
            feedAttributeId = adCustomizerFeed.feedAttributes[1].id,
            stringValue = price

        new FeedItemAttributeValue()
            feedAttributeId = adCustomizerFeed.feedAttributes[2].id,
            stringValue = date


feed_item = {
    'feedId': ad_customizer_feed['feedId'],
    'attributeValues': [
            'feedAttributeId': ad_customizer_feed['feedAttributes'][0]['id'],
            'stringValue': name
            'feedAttributeId': ad_customizer_feed['feedAttributes'][1]['id'],
            'stringValue': price
            'feedAttributeId': ad_customizer_feed['feedAttributes'][2]['id'],
            'stringValue': date

operation = {
    'operator': 'ADD',
    'operand': feed_item


$nameAttributeValue = new FeedItemAttributeValue();

$priceAttributeValue = new FeedItemAttributeValue();

$dateAttributeValue = new FeedItemAttributeValue();

$item = new FeedItem();
    [$nameAttributeValue, $priceAttributeValue, $dateAttributeValue]


my ($ad_customizer_feed, $name, $price, $date) = @_;

my $name_attribute_value =
    feedAttributeId =>
    stringValue => $name
my $price_attribute_value =
    feedAttributeId =>
    stringValue => $price
my $date_attribute_value =
    feedAttributeId =>
    stringValue => $date

my $feed_item = Google::Ads::AdWords::v201809::FeedItem->new({
    feedId => $ad_customizer_feed->get_feedId(),
    attributeValues =>
      [$name_attribute_value, $price_attribute_value, $date_attribute_value]


feed_items = do |item|
    :feed_id => feed_data[:feed_id],
    :attribute_values => [
        :feed_attribute_id => feed_data[:name_id],
        :string_value => item[:name]
        :feed_attribute_id => feed_data[:price_id],
        :string_value => item[:price]
        :feed_attribute_id => feed_data[:date_id],
        :string_value => item[:date]


Dim feedItem As New FeedItem
feedItem.feedId = adCustomizerFeed.feedId
Dim attributeValues As New List(Of FeedItemAttributeValue)

' FeedAttributes appear in the same order as they were created
' - Name, Price, Date. See CreateCustomizerFeed method for details.
Dim nameAttributeValue As New FeedItemAttributeValue
nameAttributeValue.feedAttributeId = adCustomizerFeed.feedAttributes(0).id
nameAttributeValue.stringValue = nameValue

Dim priceAttributeValue As New FeedItemAttributeValue
priceAttributeValue.feedAttributeId = adCustomizerFeed.feedAttributes(1).id
priceAttributeValue.stringValue = priceValue

Dim dateAttributeValue As New FeedItemAttributeValue
dateAttributeValue.feedAttributeId = adCustomizerFeed.feedAttributes(2).id
dateAttributeValue.stringValue = dateValue

feedItem.attributeValues = attributeValues.ToArray

The items will be fetched only for the ad group specified for the
targeting_ad_group_id. Any ad in that ad group will use these feed items for
the dynamic replacements.

If multiple feed items match in a given context, the system uses an algorithm to
pick one automatically. This algorithm may vary over time. If you want greater
control over which feed items are used for which contexts, make sure to use
specific targeting within the feed items.

Use the feed in an ad

Once the feed is set up, you can reference it from any ad in the system.

When setting up an ad, you reference a feed and its attributes by name, not by ID.
This is different from the other steps, where you use the system-generated IDs.

The syntax for inserting a custom value from a feed is {=FeedName.AttributeName}.
If you want to specify a default value, the syntax would be
{=FeedName.AttributeName:default value}. For example, using our
feed above, if you want to insert the price of an object in the string with a
default of $10, use {=AdCustomizerFeed.Price:$10}:


ExpandedTextAd textAd = new ExpandedTextAd();
textAd.setHeadlinePart1(String.format("Luxury Cruise to {=%s.Name}", feedName));
textAd.setHeadlinePart2(String.format("Only {=%s.Price}", feedName));
textAd.setDescription(String.format("Offer ends in {=countdown(%s.Date)}!", feedName));
textAd.setFinalUrls(new String[] {""});


ExpandedTextAd expandedTextAd = new ExpandedTextAd()
    headlinePart1 = string.Format("Luxury Cruise to {{={0}.Name}}", feedName),
    headlinePart2 = string.Format("Only {{={0}.Price}}", feedName),
    description =
        string.Format("Offer ends in {{=countdown({0}.Date)}}!", feedName),
    finalUrls = new string[]


expanded_text_ad = {
    'xsi_type': 'ExpandedTextAd',
    'headlinePart1': 'Luxury Cruise to {=%s.Name}' % feed_name,
    'headlinePart2': 'Only {=%s.Price}' % feed_name,
    'description': 'Offer ends in {=countdown(%s.Date)}!' % feed_name,
    'finalUrls': [''],


// Create an expanded text ad that uses ad customization.
$expandedTextAd = new ExpandedTextAd();
    sprintf('Luxury Cruise to {=%s.Name}', $feedName)
    sprintf('Only {=%s.Price}', $feedName)
    sprintf('Offer ends in {=countdown(%s.Date)}!', $feedName)


my $text_ad = Google::Ads::AdWords::v201809::ExpandedTextAd->new({
    headlinePart1 => sprintf("Luxury Cruise to {=%s.Name}", $feed_name),
    headlinePart2 => sprintf("Only {=%s.Price}",            $feed_name),
    description =>
      sprintf("Offer ends in {=countdown(%s.Date)}!", $feed_name),
    finalUrls => ['']});


# All set! We can now create ads with customizations.
expanded_text_ad = {
  :xsi_type => 'ExpandedTextAd',
  :headline_part1 => 'Luxury Cruise to {=%s.Name}' % feed_name,
  :headline_part2 => 'Only {=%s.Price}' % feed_name,
  :description => 'Offer ends in {=countdown(%s.Date)}!' % feed_name,
  :final_urls => ['']


Dim expandedTextAd As New ExpandedTextAd
expandedTextAd.headlinePart1 = String.Format("Luxury Cruise to {{={0}.Name}}",
expandedTextAd.headlinePart2 = String.Format("Only {{={0}.Price}}", feedName)
expandedTextAd.description =
    String.Format("Offer ends in {{=countdown({0}.Date)}}!",
expandedTextAd.finalUrls = New String() {""}

If this ad is added via the AdGroupAdService, the references to
AdCustomizerFeed are populated at serving time with matching data from a
feed item within that feed that matches the current ad group. The ad won’t serve
if no match is found.

The API validates ads that include references to ad customizers: If no feed with
the specified name is mapped to the ad placeholder type, or no attribute with a
specified name exists in the feed, the ad is rejected.

If you change the name of a feed when ads are referencing it, the ads are
automatically updated to reference the new feed name. If you delete a feed when
ads are referencing it, those ads will no longer serve.

Ads using customizers are subject to approvals just like any other ads.
Feed items and ads can both be disapproved separately, though disapproval of either will
prevent the ad from serving. In rare cases where each is individually fine, but
the combination of the two is a violation, the ad will be disapproved to
prevent serving.

Add a countdown

The COUNTDOWN function allows you to dynamically change the way you display a
date field so it shows how much time (days, hours) is left.

For example, the description of the ad example above is set to
'Offer ends in {=COUNTDOWN(AdCustomizerFeed.Date)}!' At serve time, the ad
will show “Offer ends in 5 days!” or “Offer ends in 4 hours!” based on the time

Once the date specified in the countdown is past, the ad will no longer
serve until the date is updated again.

The countdown function takes three arguments, but only the first is required:

  • timestamp: The date to which you are counting down. This value can be a
    reference to a feed attribute or a specific date literal.
  • language: The localization in which the countdown should be displayed. If
    unspecified, this defaults to en-US.
  • days_before: The number of days before the timestamp that this ad can
    start serving. For example, if it’s 6 days before the specified time, but this
    field is set to 5, the ad won’t serve. If unspecified, no
    restrictions are added.

For example, you could use {=COUNTDOWN(AdCustomizerFeed.Date, 'es', 3)} to
change the language to Spanish, and restrict the ad so it doesn’t appear in
search results until 3 days before the date specified.

The COUNTDOWN function counts down to an event in the timezone of the user
making the query. A variant of COUNTDOWN, called GLOBAL_COUNTDOWN, counts
down to a specific time in your account’s time zone. GLOBAL_COUNTDOWN takes
all the same parameters as COUNTDOWN.

Add an IF function

IF functions let you insert a customized message in your ad based on who is
searching and what device they’re searching on, all without using a feed. The
default text is optional.

Dimension Criteria Syntax Example
device mobile {=IF(device=mobile,text to insert):optional default text} {=IF(device=mobile,"Quick, Easy, Mobile Booking"):"Best price guarantee"}
audience Any valid user list name in your account (if list name matches multiple lists in advertiser account, we will randomly pick any) {=IF(audience IN (userlist1,userlist2),text to insert):optional default text} {=IF(audience IN (returning visitors,cart abandoners),30%):25%}

Code examples

Code examples in each of the supported languages can help you get started with
adding an ad customizer:

Ad parameters

Ad params allow for dynamically updating numerical information
in an ad without having to resubmit the ad for review and approval. It’s
similar to keyword insertion
where markups within the ad are updated when displayed. Ad params are managed
via the API through

An ad parameter is represented by an
AdParam object.
For an AdParam to work properly, it must:

  • Be specified for the Keyword, AdGroup, and paramIndex of that
  • Not cause any text field of the ad to exceed the line length limit after all
    ad parameters have been applied.
  • Be part of an ad being shown on the Google Search Network.

Default values are shown for the ad parameter if there is a problem during
its insertion.

Code examples

Code examples in each of the supported languages can help you get started with
managing ad params:

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button