Create Ads

Add responsive search ad

The best way to set up new ads in the API is to use the Add Responsive Search Ad code example in the Basic Operations folder of your client library. The sample handles all the background authentication tasks for you, and walks you through creating responsive search ads.

Java

This example is not yet available in Java; you can take a look at the other languages.
    

C#

// Copyright 2021 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 CommandLine;
using Google.Ads.Gax.Examples;
using Google.Ads.Gax.Util;
using Google.Ads.GoogleAds.Lib;
using Google.Ads.GoogleAds.V18.Common;
using Google.Ads.GoogleAds.V18.Resources;
using Google.Ads.GoogleAds.V18.Services;
using System.Collections.Generic;
using System.Linq;
using System;
using static Google.Ads.GoogleAds.V18.Enums.AdGroupTypeEnum.Types;
using static Google.Ads.GoogleAds.V18.Enums.AdGroupAdStatusEnum.Types;
using static Google.Ads.GoogleAds.V18.Enums.AdGroupCriterionStatusEnum.Types;
using static Google.Ads.GoogleAds.V18.Enums.AdGroupStatusEnum.Types;
using static Google.Ads.GoogleAds.V18.Enums.AdvertisingChannelTypeEnum.Types;
using static Google.Ads.GoogleAds.V18.Enums.BudgetDeliveryMethodEnum.Types;
using static Google.Ads.GoogleAds.V18.Enums.CampaignStatusEnum.Types;
using static Google.Ads.GoogleAds.V18.Enums.CustomizerAttributeTypeEnum.Types;
using static Google.Ads.GoogleAds.V18.Enums.KeywordMatchTypeEnum.Types;
using static Google.Ads.GoogleAds.V18.Services.SuggestGeoTargetConstantsRequest.Types;
using Google.Ads.GoogleAds.Config;
using Google.Ads.GoogleAds.Extensions.Config;

namespace Google.Ads.GoogleAds.Examples.V18
{
    /// <summary>
    /// Adds a customizer attribute, links the customizer attribute to a customer, and then adds
    /// a responsive search ad with a description using the ad customizer to the specified ad group.
    /// </summary>
    public class AddResponsiveSearchAdFull : ExampleBase
    {
        /// <summary>
        /// </summary>
        public class Options : OptionsBase
        {
            /// <summary>
            /// The Google Ads customer ID.
            /// </summary>
            [Option("customerId", Required = true, HelpText =
                "The Google Ads customer ID.")]
            public long CustomerId { get; set; }

            /// <summary>
            /// The Google Ads customizer attribute name ID.
            /// </summary>
            [Option("customizerAttributeName", Required = false, HelpText =
                "The Google Ads customizer attribute name.", Default = CUSTOMIZER_ATTRIBUTE_NAME)]
            public string CustomizerAttributeName { get; set; }
        }

        /// <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)
        {
            Options options = ExampleUtilities.ParseCommandLine<Options>(args);

            AddResponsiveSearchAdFull codeExample =
                new AddResponsiveSearchAdFull();

            Console.WriteLine(codeExample.Description);

            codeExample.Run(
                new GoogleAdsClient(),
                options.CustomerId,
                options.CustomizerAttributeName
            );
        }

        // The name of the customizer attribute to be used in the ad customizer must be unique for a
        // given client account. To run this example multiple times, change this value or specify
        // its corresponding argument. Note that there is a limit for the number of enabled
        // customizer attributes in one account, so you shouldn't run this example more than
        // necessary.
        //
        // Visit the following link for more details:
        // https://developers.google.com/google-ads/api/docs/ads/customize-responsive-search-ads#rules_and_limitations
        private const string CUSTOMIZER_ATTRIBUTE_NAME = "Price";

        /// <summary>
        /// Returns a description about the code example.
        /// </summary>
        public override string Description =>
            "Adds a customizer attribute, links the customizer attribute to a customer, and then " +
            "adds a responsive search ad with a description using the ad customizer to the " +
            "specified ad group.";

        /// <summary>
        /// Runs the example.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The Google Ads customer ID.</param>
        /// <param name="customizerAttributeName">The customizer attribute name.</param>
        public void Run(
                GoogleAdsClient client,
                long customerId,
                string customizerAttributeName)
        {
            string customizerAttributeResourceName = CreateCustomizerAttribute(
                client,
                customerId,
                customizerAttributeName
            );

            LinkCustomizerAttributeToCustomer(client, customerId, customizerAttributeResourceName);

            string campaignBudgetResourceName = AddCampaignBudget(client, customerId);

            string campaignResourceName = AddCampaign(client, customerId,
                campaignBudgetResourceName);

            string adGroupResourceName = AddAdGroup(client, customerId, campaignResourceName);

            CreateResponsiveSearchAdWithCustomization(
                client,
                customerId,
                adGroupResourceName,
                customizerAttributeName
            );

            AddKeywords(client, customerId, adGroupResourceName);

            AddGeoTargeting(client, customerId, campaignResourceName);
        }

        /// <summary>
        /// Creates a customizer attribute with the specified customizer attribute name.
        /// </summary>
        /// <param name="client">The Google Ads API client.</param>
        /// <param name="customerId">The customer ID.</param>
        /// <param name="customizerAttributeName">The name of the customizer attribute.</param>
        /// <returns>The created customizer attribute resource name.</returns>
        private string CreateCustomizerAttribute(
            GoogleAdsClient client,
            long customerId,
            string customizerAttributeName)
        {
            // Creates a customizer attribute operation for creating a customizer attribute.
            CustomizerAttributeOperation operation = new CustomizerAttributeOperation() {
                // Creates a customizer attribute with the specified name.
                Create = new CustomizerAttribute() {
                    Name = customizerAttributeName,

                    // Specifies the type to be 'PRICE' so that we can dynamically customize the part of
                    // the ad's description that is a price of a product/service we advertise.
                    Type = CustomizerAttributeType.Price
                }
            };

            CustomizerAttributeServiceClient serviceClient =
                client.GetService(Services.V18.CustomizerAttributeService);

            // Issues a mutate request to add the customizer attribute and prints its information.
            MutateCustomizerAttributesResponse response =
                serviceClient.MutateCustomizerAttributes(
                    customerId.ToString(),
                    new [] { operation }.ToList()
                );

            string resourceName = response.Results[0].ResourceName;

            Console.WriteLine($"Added a customizer attribute with resource name '{resourceName}'.");

            return resourceName;
        }

        /// <summary>
        /// Links the customizer attribute to the customer by providing a value to be used in a
        /// responsive search ad that will be created in a later step.
        /// </summary>
        /// <param name="client">The Google Ads API client.</param>
        /// <param name="customerId">The customer ID.</param>
        /// <param name="customizerAttributeResourceName">The resource name of the customizer
        /// attribute.</param>
        private void LinkCustomizerAttributeToCustomer(
            GoogleAdsClient client,
            long customerId,
            string customizerAttributeResourceName)
        {
            // Creates a customer customizer operation.
            CustomerCustomizerOperation operation = new CustomerCustomizerOperation() {
                // Creates a customer customizer with the value to be used in the responsive search
                // ad.
                Create = new CustomerCustomizer() {
                    CustomizerAttribute = customizerAttributeResourceName,

                    Value = new CustomizerValue() {
                        Type = CustomizerAttributeType.Price,

                        // Specify '100USD' as a text value. The ad customizer will dynamically
                        // replace the placeholder with this value when the ad serves.
                        StringValue = "100USD"
                    }
                }
            };

            CustomerCustomizerServiceClient serviceClient =
                client.GetService(Services.V18.CustomerCustomizerService);

            // Issues a mutate request to add the customer customizer and prints its information.
            MutateCustomerCustomizersResponse response =
                serviceClient.MutateCustomerCustomizers(
                    customerId.ToString(),
                    new [] { operation }.ToList()
                );

            string resourceName = response.Results[0].ResourceName;

            Console.WriteLine($"Added a customer customizer with resource name '{resourceName}'.");
        }

        /// <summary>
        /// Adds a campaign budget.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The Google Ads customer ID for which the call is made.</param>
        /// <returns>The campaign budget resource name.</returns>
        private static string AddCampaignBudget(GoogleAdsClient client, long customerId)
        {
            // Get the CampaignBudgetService.
            CampaignBudgetServiceClient campaignBudgetService =
                client.GetService(Services.V18.CampaignBudgetService);

            // Create the budget.
            CampaignBudget campaignBudget = new CampaignBudget()
            {
                Name = "Interplanetary Cruise Budget #" + ExampleUtilities.GetRandomString(),
                AmountMicros = 3_000_000,
                DeliveryMethod = BudgetDeliveryMethod.Standard
            };

            // Create the operation.
            CampaignBudgetOperation operation = new CampaignBudgetOperation()
            {
                Create = campaignBudget
            };

            // Add the campaign budget.
            MutateCampaignBudgetsResponse response =
                campaignBudgetService.MutateCampaignBudgets(customerId.ToString(),
                    new CampaignBudgetOperation[] { operation });
            // Display the result.

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

        /// <summary>
        /// Adds a campaign.
        /// </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="budgetResourceName">The campaign budget resource name.</param>
        /// <returns>The campaign resource name.</returns>
        private static string AddCampaign(GoogleAdsClient client, long customerId,
            string budgetResourceName)
        {
            // Get the CampaignService.
            CampaignServiceClient campaignService = client.GetService(Services.V18.CampaignService);

            // Create the campaign.
            Campaign campaign = new Campaign()
            {
                Name = "Testing RSA via API #" + ExampleUtilities.GetRandomString(),
                AdvertisingChannelType = AdvertisingChannelType.Search,
                Status = CampaignStatus.Paused,
                ManualCpc = new ManualCpc(),
                NetworkSettings = new Campaign.Types.NetworkSettings()
                {
                    TargetGoogleSearch = true,
                    TargetSearchNetwork = true,
                    TargetPartnerSearchNetwork = false,
                    // Enable Display Expansion on Search campaigns. For more details see:
                    // https://support.google.com/google-ads/answer/7193800
                    TargetContentNetwork = true
                },
                CampaignBudget = budgetResourceName,

                StartDate = DateTime.Now.AddDays(1).ToString("yyyyMMdd"),
                EndDate = DateTime.Now.AddDays(30).ToString("yyyyMMdd")
            };

            // Create the operation.
            CampaignOperation operation = new CampaignOperation()
            {
                Create = campaign
            };

            // Add the campaign.
            MutateCampaignsResponse response =
                campaignService.MutateCampaigns(customerId.ToString(),
                    new CampaignOperation[] { operation });

            // Displays the result.
            string campaignResourceName = response.Results[0].ResourceName;
            Console.WriteLine($"Added campaign with resource name '{campaignResourceName}'.");
            return campaignResourceName;
        }

        /// <summary>Adds an 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="campaignResourceName">The campaign resource name.</param>
        /// <returns>The ad group resource name.</returns>
        private static string AddAdGroup(GoogleAdsClient client, long customerId,
            string campaignResourceName)
        {
            // Get the AdGroupService.
            AdGroupServiceClient adGroupService = client.GetService(Services.V18.AdGroupService);

            // Create the ad group.
            AdGroup adGroup = new AdGroup()
            {
                Name = "Testing RSA via API #" + ExampleUtilities.GetRandomString(),
                Campaign = campaignResourceName,
                Type = AdGroupType.SearchStandard,
                Status = AdGroupStatus.Enabled,

                // If you want to set up a max CPC bid, uncomment the line below.
                // CpcBidMicros = 50_000
            };

            // Create the operation.
            AdGroupOperation operation = new AdGroupOperation()
            {
                Create = adGroup
            };

            // Add the ad group.
            MutateAdGroupsResponse response =
                adGroupService.MutateAdGroups(customerId.ToString(),
                    new AdGroupOperation[] { operation });

            // Display the results.
            string adGroupResourceName = response.Results[0].ResourceName;
            Console.WriteLine($"Added ad group with resource name '{adGroupResourceName}'.");

            return adGroupResourceName;
        }

        /// <summary>
        /// Creates a responsive search ad that uses the specified customizer attribute.
        /// </summary>
        /// <param name="client">The Google Ads API client.</param>
        /// <param name="customerId">The customer ID.</param>
        /// <param name="adGroupResourceName">The resource name of the ad group.</param>
        /// <param name="customizerAttributeName">The name of the customizer attribute.</param>
        private void CreateResponsiveSearchAdWithCustomization(
            GoogleAdsClient client,
            long customerId,
            string adGroupResourceName,
            string customizerAttributeName)
        {
            // Creates an ad group ad operation.
            AdGroupAdOperation operation = new AdGroupAdOperation() {

                // Creates an ad group ad to hold the ad.
                Create = new AdGroupAd() {

                    AdGroup = adGroupResourceName,
                    Status = AdGroupAdStatus.Enabled,

                    // Creates an ad and sets responsive search ad info.
                    Ad = new Ad() {

                        ResponsiveSearchAd = new ResponsiveSearchAdInfo() {
                            Headlines =
                            {
                                // Sets a pinning to always choose this asset for HEADLINE_1.
                                // Pinning is optional; if no pinning is set, then headlines and
                                // descriptions will be rotated and the ones that perform best will
                                //be used more often.
                                new AdTextAsset() { Text = "Cruise to Mars" },
                                new AdTextAsset() { Text = "Best Space Cruise Line" },
                                new AdTextAsset() { Text = "Experience the Stars" }
                            },

                            Descriptions =
                            {
                                new AdTextAsset() { Text = "Buy your tickets now" },

                                // Creates this particular description using the ad customizer. For
                                // details about the placeholder format, visit the following:
                                // https://developers.google.com/google-ads/api/docs/ads/customize-responsive-search-ads#ad_customizers_in_responsive_search_ads
                                //
                                // The ad customizer replaces the placeholder with the value we
                                // previously created and linked to the customer using
                                // `CustomerCustomizer`.
                                new AdTextAsset()
                                {
                                    Text = $"Just {{CUSTOMIZER.{customizerAttributeName}:10USD}}"
                                }
                            },

                            Path1 = "all-inclusive",
                            Path2 = "deals"
                        },

                        FinalUrls = { "http://www.example.com" }
                    }
                }
            };

            // Issues a mutate request to add the ad group ad and prints its information.
            AdGroupAdServiceClient serviceClient = client.GetService(Services.V18.AdGroupAdService);

            MutateAdGroupAdsResponse response = serviceClient.MutateAdGroupAds(
                customerId.ToString(),
                new [] { operation }.ToList()
            );

            string resourceName = response.Results[0].ResourceName;

            Console.WriteLine($"Created responsive search ad with resource name '{resourceName}'.");
        }

        /// <summary>
        /// Creates 3 keyword match types: EXACT, PHRASE, and BROAD.
        /// EXACT: ads may show on searches that ARE the same meaning as your keyword.
        /// PHRASE: ads may show on searches that INCLUDE the meaning of your keyword.
        /// BROAD: ads may show on searches that RELATE to your keyword.
        /// For smart bidding, BROAD is the recommended one.
        /// </summary>
        /// <param name="client">The Google Ads API client.</param>
        /// <param name="customerId">The customer ID.</param>
        /// <param name="adGroupResourceName">The resource name of the ad group.</param>
        private void AddKeywords(GoogleAdsClient client, long customerId,
            string adGroupResourceName)
        {
            // Get the AdGroupCriterionService.
            AdGroupCriterionServiceClient adGroupCriterionService =
                client.GetService(Services.V18.AdGroupCriterionService);

            List<AdGroupCriterionOperation> operations = new List<AdGroupCriterionOperation>();

            AdGroupCriterionOperation exactMatchOperation = new AdGroupCriterionOperation()
            {
                Create = new AdGroupCriterion()
                {
                    AdGroup = adGroupResourceName,
                    Status = AdGroupCriterionStatus.Enabled,
                    Keyword = new KeywordInfo()
                    {
                        Text = "example of exact match",
                        MatchType = KeywordMatchType.Exact
                    },
                    // Uncomment the line below if you want to change this keyword to a negative
                    // target.
                    // Negative = true
                }
            };
            // Optional repeated field
            // exactMatchOperation.Create.FinalUrls.Add("https://www.example.com");
            operations.Add(exactMatchOperation);

            AdGroupCriterionOperation phraseMatchOperation = new AdGroupCriterionOperation()
            {
                Create = new AdGroupCriterion()
                {
                    AdGroup = adGroupResourceName,
                    Status = AdGroupCriterionStatus.Enabled,
                    Keyword = new KeywordInfo()
                    {
                        Text = "example of phrase match",
                        MatchType = KeywordMatchType.Phrase
                    },
                    // Uncomment the line below if you want to change this keyword to a negative
                    // target.
                    // Negative = true
                }
            };
            // Optional repeated field
            // phraseMatchOperation.Create.FinalUrls.Add("https://www.example.com");
            operations.Add(phraseMatchOperation);

            AdGroupCriterionOperation broadMatchOperation = new AdGroupCriterionOperation()
            {
                Create = new AdGroupCriterion()
                {
                    AdGroup = adGroupResourceName,
                    Status = AdGroupCriterionStatus.Enabled,
                    Keyword = new KeywordInfo()
                    {
                        Text = "example of broad match",
                        MatchType = KeywordMatchType.Broad
                    },
                    // Uncomment the line below if you want to change this keyword to a negative
                    // target.
                    // Negative = true
                }
            };
            // Optional repeated field
            // broadMatchOperation.Create.FinalUrls.Add("https://www.example.com");
            operations.Add(broadMatchOperation);

            MutateAdGroupCriteriaResponse response =
                adGroupCriterionService.MutateAdGroupCriteria(customerId.ToString(), operations);

             // Display the results.
            foreach (MutateAdGroupCriterionResult newAdGroupCriterion in response.Results)
            {
                Console.WriteLine("Keyword with resource name '{0}' was created.",
                    newAdGroupCriterion.ResourceName);
            }
        }

        /// <summary>
        /// Creates geo targets.
        /// </summary>
        /// <param name="client">The Google Ads API client.</param>
        /// <param name="customerId">The customer ID.</param>
        /// <param name="campaignResourceName">The resource name of the campaign.</param>
        private void AddGeoTargeting(GoogleAdsClient client, long customerId,
            string campaignResourceName)
        {
            GeoTargetConstantServiceClient geoTargetConstantService =
                client.GetService(Services.V18.GeoTargetConstantService);

            SuggestGeoTargetConstantsRequest suggestGeoTargetConstantsRequest =
                new SuggestGeoTargetConstantsRequest()
            {
                // Locale uses the ISO 639-1 format.
                Locale = "es",
                // A list of available country codes can be referenced here:
                // https://developers.google.com/google-ads/api/reference/data/geotargets
                CountryCode = "AR",
                LocationNames = new LocationNames()
                {
                    Names = {"Buenos aires", "San Isidro", "Mar del Plata"}
                }
            };

            SuggestGeoTargetConstantsResponse suggestGeoTargetConstantsResponse =
                geoTargetConstantService.SuggestGeoTargetConstants(
                    suggestGeoTargetConstantsRequest);

            List<CampaignCriterionOperation> operations = new List<CampaignCriterionOperation>();
            foreach (GeoTargetConstantSuggestion suggestion in
                suggestGeoTargetConstantsResponse.GeoTargetConstantSuggestions)
            {
                Console.WriteLine($"Geo target constant: {suggestion.GeoTargetConstant.Name} was " +
                $"found in locale ({suggestion.Locale}) with reach ({suggestion.Reach}) from " +
                $"search term ({suggestion.SearchTerm})");

                CampaignCriterionOperation operation = new CampaignCriterionOperation()
                {
                    Create = new CampaignCriterion()
                    {
                        Campaign = campaignResourceName,
                        Location = new LocationInfo()
                        {
                            GeoTargetConstant = suggestion.GeoTargetConstant.ResourceName
                        }
                    }
                };
                operations.Add(operation);
            }

            CampaignCriterionServiceClient campaignCriterionService =
                client.GetService(Services.V18.CampaignCriterionService);

            MutateCampaignCriteriaResponse mutateCampaignCriteriaResponse =
                campaignCriterionService.MutateCampaignCriteria(customerId.ToString(), operations);

            foreach (MutateCampaignCriterionResult result in mutateCampaignCriteriaResponse.Results)
            {
                Console.WriteLine($"Added campaign criterion {result.ResourceName}");
            }
        }
    }
}

      

PHP

This example is not yet available in PHP; you can take a look at the other languages.
    

Python

#!/usr/bin/env python
# Copyright 2023 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.
"""
This example shows how to create a complete Responsive Search ad.

Includes creation of: budget, campaign, ad group, ad group ad,
keywords, and geo targeting.

More details on Responsive Search ads can be found here:
https://support.google.com/google-ads/answer/7684791
"""

import argparse
import sys
import uuid

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

# Keywords from user.
KEYWORD_TEXT_EXACT = "example of exact match"
KEYWORD_TEXT_PHRASE = "example of phrase match"
KEYWORD_TEXT_BROAD = "example of broad match"

# Geo targeting from user.
GEO_LOCATION_1 = "Buenos aires"
GEO_LOCATION_2 = "San Isidro"
GEO_LOCATION_3 = "Mar del Plata"

# LOCALE and COUNTRY_CODE are used for geo targeting.
# LOCALE is using ISO 639-1 format. If an invalid LOCALE is given,
# 'es' is used by default.
LOCALE = "es"

# A list of country codes can be referenced here:
# https://developers.google.com/google-ads/api/reference/data/geotargets
COUNTRY_CODE = "AR"


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

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID.
        customizer_attribute_name: The name of the customizer attribute to be
            created
    """
    if customizer_attribute_name:
        customizer_attribute_resource_name = create_customizer_attribute(
            client, customer_id, customizer_attribute_name
        )

        link_customizer_attribute_to_customer(
            client, customer_id, customizer_attribute_resource_name
        )

    # Create a budget, which can be shared by multiple campaigns.
    campaign_budget = create_campaign_budget(client, customer_id)

    campaign_resource_name = create_campaign(
        client, customer_id, campaign_budget
    )

    ad_group_resource_name = create_ad_group(
        client, customer_id, campaign_resource_name
    )

    create_ad_group_ad(
        client, customer_id, ad_group_resource_name, customizer_attribute_name
    )

    add_keywords(client, customer_id, ad_group_resource_name)

    add_geo_targeting(client, customer_id, campaign_resource_name)


def create_customizer_attribute(client, customer_id, customizer_attribute_name):
    """Creates a customizer attribute with the given customizer attribute name.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID.
        customizer_attribute_name: the name for the customizer attribute.

    Returns:
        A resource name for a customizer attribute.
    """
    # Create a customizer attribute operation for creating a customizer
    # attribute.
    operation = client.get_type("CustomizerAttributeOperation")
    # Create a customizer attribute with the specified name.
    customizer_attribute = operation.create
    customizer_attribute.name = customizer_attribute_name
    # Specify the type to be 'PRICE' so that we can dynamically customize the
    # part of the ad's description that is a price of a product/service we
    # advertise.
    customizer_attribute.type_ = client.enums.CustomizerAttributeTypeEnum.PRICE

    # Issue a mutate request to add the customizer attribute and prints its
    # information.
    customizer_attribute_service = client.get_service(
        "CustomizerAttributeService"
    )
    response = customizer_attribute_service.mutate_customizer_attributes(
        customer_id=customer_id, operations=[operation]
    )
    resource_name = response.results[0].resource_name

    print(f"Added a customizer attribute with resource name: '{resource_name}'")

    return resource_name


def link_customizer_attribute_to_customer(
    client, customer_id, customizer_attribute_resource_name
):
    """Links the customizer attribute to the customer.

    Args:
        client: an initialized GoogleAdsClient instance.
            customer_id: a client customer ID.
        customizer_attribute_resource_name: a resource name for  customizer
            attribute.
    """
    # Create a customer customizer operation.
    operation = client.get_type("CustomerCustomizerOperation")
    # Create a customer customizer with the value to be used in the responsive
    # search ad.
    customer_customizer = operation.create
    customer_customizer.customizer_attribute = (
        customizer_attribute_resource_name
    )
    customer_customizer.value.type_ = (
        client.enums.CustomizerAttributeTypeEnum.PRICE
    )
    # The ad customizer will dynamically replace the placeholder with this value
    # when the ad serves.
    customer_customizer.value.string_value = "100USD"

    customer_customizer_service = client.get_service(
        "CustomerCustomizerService"
    )
    # Issue a mutate request to create the customer customizer and prints its
    # information.
    response = customer_customizer_service.mutate_customer_customizers(
        customer_id=customer_id, operations=[operation]
    )
    resource_name = response.results[0].resource_name

    print(
        f"Added a customer customizer to the customer with resource name: '{resource_name}'"
    )


def create_ad_text_asset(client, text, pinned_field=None):
    """Create an AdTextAsset.

    Args:
        client: an initialized GoogleAdsClient instance.
        text: text for headlines and descriptions.
        pinned_field: to pin a text asset so it always shows in the ad.

    Returns:
        An AdTextAsset.
    """
    ad_text_asset = client.get_type("AdTextAsset")
    ad_text_asset.text = text
    if pinned_field:
        ad_text_asset.pinned_field = pinned_field
    return ad_text_asset


def create_ad_text_asset_with_customizer(
    client, customizer_attribute_resource_name
):
    """Create an AdTextAsset.
    Args:
        client: an initialized GoogleAdsClient instance.
        customizer_attribute_resource_name: The resource name of the customizer attribute.

    Returns:
        An AdTextAsset.
    """
    ad_text_asset = client.get_type("AdTextAsset")

    # Create this particular description using the ad customizer. Visit
    # https://developers.google.com/google-ads/api/docs/ads/customize-responsive-search-ads#ad_customizers_in_responsive_search_ads
    # for details about the placeholder format. The ad customizer replaces the
    # placeholder with the value we previously created and linked to the
    # customer using CustomerCustomizer.
    ad_text_asset.text = (
        f"Just {{CUSTOMIZER.{customizer_attribute_resource_name}:10USD}}"
    )

    return ad_text_asset


def create_campaign_budget(client, customer_id):
    """Creates campaign budget resource.

    Args:
      client: an initialized GoogleAdsClient instance.
      customer_id: a client customer ID.

    Returns:
      Campaign budget resource name.
    """
    # Create a budget, which can be shared by multiple campaigns.
    campaign_budget_service = client.get_service("CampaignBudgetService")
    campaign_budget_operation = client.get_type("CampaignBudgetOperation")
    campaign_budget = campaign_budget_operation.create
    campaign_budget.name = f"Campaign budget {uuid.uuid4()}"
    campaign_budget.delivery_method = (
        client.enums.BudgetDeliveryMethodEnum.STANDARD
    )
    campaign_budget.amount_micros = 500000

    # Add budget.
    campaign_budget_response = campaign_budget_service.mutate_campaign_budgets(
        customer_id=customer_id, operations=[campaign_budget_operation]
    )

    return campaign_budget_response.results[0].resource_name


def create_campaign(client, customer_id, campaign_budget):
    """Creates campaign resource.

    Args:
      client: an initialized GoogleAdsClient instance.
      customer_id: a client customer ID.
      campaign_budget: a budget resource name.

    Returns:
      Campaign resource name.
    """
    campaign_service = client.get_service("CampaignService")
    campaign_operation = client.get_type("CampaignOperation")
    campaign = campaign_operation.create
    campaign.name = f"Testing RSA via API {uuid.uuid4()}"
    campaign.advertising_channel_type = (
        client.enums.AdvertisingChannelTypeEnum.SEARCH
    )

    # Recommendation: Set the campaign to PAUSED when creating it to prevent
    # the ads from immediately serving. Set to ENABLED once you've added
    # targeting and the ads are ready to serve.
    campaign.status = client.enums.CampaignStatusEnum.PAUSED

    # Set the bidding strategy and budget.
    # The bidding strategy for Maximize Clicks is TargetSpend.
    # The target_spend_micros is deprecated so don't put any value.
    # See other bidding strategies you can select in the link below.
    # https://developers.google.com/google-ads/api/reference/rpc/latest/Campaign#campaign_bidding_strategy
    campaign.target_spend.target_spend_micros = 0
    campaign.campaign_budget = campaign_budget

    # Set the campaign network options.
    campaign.network_settings.target_google_search = True
    campaign.network_settings.target_search_network = True
    campaign.network_settings.target_partner_search_network = False
    # Enable Display Expansion on Search campaigns. For more details see:
    # https://support.google.com/google-ads/answer/7193800
    campaign.network_settings.target_content_network = True

    # # Optional: Set the start date.
    # start_time = datetime.date.today() + datetime.timedelta(days=1)
    # campaign.start_date = datetime.date.strftime(start_time, _DATE_FORMAT)

    # # Optional: Set the end date.
    # end_time = start_time + datetime.timedelta(weeks=4)
    # campaign.end_date = datetime.date.strftime(end_time, _DATE_FORMAT)

    # Add the campaign.
    campaign_response = campaign_service.mutate_campaigns(
        customer_id=customer_id, operations=[campaign_operation]
    )
    resource_name = campaign_response.results[0].resource_name
    print(f"Created campaign {resource_name}.")
    return resource_name


def create_ad_group(client, customer_id, campaign_resource_name):
    """Creates ad group.

    Args:
      client: an initialized GoogleAdsClient instance.
      customer_id: a client customer ID.
      campaign_resource_name: a campaign resource name.

    Returns:
      Ad group ID.
    """
    ad_group_service = client.get_service("AdGroupService")

    ad_group_operation = client.get_type("AdGroupOperation")
    ad_group = ad_group_operation.create
    ad_group.name = f"Testing RSA via API {uuid.uuid4()}"
    ad_group.status = client.enums.AdGroupStatusEnum.ENABLED
    ad_group.campaign = campaign_resource_name
    ad_group.type_ = client.enums.AdGroupTypeEnum.SEARCH_STANDARD

    # If you want to set up a max CPC bid uncomment line below.
    # ad_group.cpc_bid_micros = 10000000

    # Add the ad group.
    ad_group_response = ad_group_service.mutate_ad_groups(
        customer_id=customer_id, operations=[ad_group_operation]
    )
    ad_group_resource_name = ad_group_response.results[0].resource_name
    print(f"Created ad group {ad_group_resource_name}.")
    return ad_group_resource_name


def create_ad_group_ad(
    client, customer_id, ad_group_resource_name, customizer_attribute_name
):
    """Creates ad group ad.

    Args:
      client: an initialized GoogleAdsClient instance.
      customer_id: a client customer ID.
      ad_group_resource_name: an ad group resource name.
      customizer_attribute_name: (optional) If present, indicates the resource
        name of the customizer attribute to use in one of the descriptions

    Returns:
      Ad group ad resource name.
    """
    ad_group_ad_service = client.get_service("AdGroupAdService")

    ad_group_ad_operation = client.get_type("AdGroupAdOperation")
    ad_group_ad = ad_group_ad_operation.create
    ad_group_ad.status = client.enums.AdGroupAdStatusEnum.ENABLED
    ad_group_ad.ad_group = ad_group_resource_name

    # Set responsive search ad info.
    # https://developers.google.com/google-ads/api/reference/rpc/latest/ResponsiveSearchAdInfo

    # The list of possible final URLs after all cross-domain redirects for the ad.
    ad_group_ad.ad.final_urls.append("https://www.example.com/")

    # Set a pinning to always choose this asset for HEADLINE_1. Pinning is
    # optional; if no pinning is set, then headlines and descriptions will be
    # rotated and the ones that perform best will be used more often.

    # Headline 1
    served_asset_enum = client.enums.ServedAssetFieldTypeEnum.HEADLINE_1
    pinned_headline = create_ad_text_asset(
        client, "Headline 1 testing", served_asset_enum
    )

    # Headline 2 and 3
    ad_group_ad.ad.responsive_search_ad.headlines.extend(
        [
            pinned_headline,
            create_ad_text_asset(client, "Headline 2 testing"),
            create_ad_text_asset(client, "Headline 3 testing"),
        ]
    )

    # Description 1 and 2
    description_1 = create_ad_text_asset(client, "Desc 1 testing")
    description_2 = None

    if customizer_attribute_name:
        description_2 = create_ad_text_asset_with_customizer(
            client, customizer_attribute_name
        )
    else:
        description_2 = create_ad_text_asset(client, "Desc 2 testing")

    ad_group_ad.ad.responsive_search_ad.descriptions.extend(
        [description_1, description_2]
    )

    # Paths
    # First and second part of text that can be appended to the URL in the ad.
    # If you use the examples below, the ad will show
    # https://www.example.com/all-inclusive/deals
    ad_group_ad.ad.responsive_search_ad.path1 = "all-inclusive"
    ad_group_ad.ad.responsive_search_ad.path2 = "deals"

    # Send a request to the server to add a responsive search ad.
    ad_group_ad_response = ad_group_ad_service.mutate_ad_group_ads(
        customer_id=customer_id, operations=[ad_group_ad_operation]
    )

    for result in ad_group_ad_response.results:
        print(
            f"Created responsive search ad with resource name "
            f'"{result.resource_name}".'
        )


def add_keywords(client, customer_id, ad_group_resource_name):
    """Creates keywords.

    Creates 3 keyword match types: EXACT, PHRASE, and BROAD.

    EXACT: ads may show on searches that ARE the same meaning as your keyword.
    PHRASE: ads may show on searches that INCLUDE the meaning of your keyword.
    BROAD: ads may show on searches that RELATE to your keyword.
    For smart bidding, BROAD is the recommended one.

    Args:
      client: an initialized GoogleAdsClient instance.
      customer_id: a client customer ID.
      ad_group_resource_name: an ad group resource name.
    """
    ad_group_criterion_service = client.get_service("AdGroupCriterionService")

    operations = []
    # Create keyword 1.
    ad_group_criterion_operation = client.get_type("AdGroupCriterionOperation")
    ad_group_criterion = ad_group_criterion_operation.create
    ad_group_criterion.ad_group = ad_group_resource_name
    ad_group_criterion.status = client.enums.AdGroupCriterionStatusEnum.ENABLED
    ad_group_criterion.keyword.text = KEYWORD_TEXT_EXACT
    ad_group_criterion.keyword.match_type = (
        client.enums.KeywordMatchTypeEnum.EXACT
    )

    # Uncomment the below line if you want to change this keyword to a negative target.
    # ad_group_criterion.negative = True

    # Optional repeated field
    # ad_group_criterion.final_urls.append('https://www.example.com')

    # Add operation
    operations.append(ad_group_criterion_operation)

    # Create keyword 2.
    ad_group_criterion_operation = client.get_type("AdGroupCriterionOperation")
    ad_group_criterion = ad_group_criterion_operation.create
    ad_group_criterion.ad_group = ad_group_resource_name
    ad_group_criterion.status = client.enums.AdGroupCriterionStatusEnum.ENABLED
    ad_group_criterion.keyword.text = KEYWORD_TEXT_PHRASE
    ad_group_criterion.keyword.match_type = (
        client.enums.KeywordMatchTypeEnum.PHRASE
    )

    # Uncomment the below line if you want to change this keyword to a negative target.
    # ad_group_criterion.negative = True

    # Optional repeated field
    # ad_group_criterion.final_urls.append('https://www.example.com')

    # Add operation
    operations.append(ad_group_criterion_operation)

    # Create keyword 3.
    ad_group_criterion_operation = client.get_type("AdGroupCriterionOperation")
    ad_group_criterion = ad_group_criterion_operation.create
    ad_group_criterion.ad_group = ad_group_resource_name
    ad_group_criterion.status = client.enums.AdGroupCriterionStatusEnum.ENABLED
    ad_group_criterion.keyword.text = KEYWORD_TEXT_BROAD
    ad_group_criterion.keyword.match_type = (
        client.enums.KeywordMatchTypeEnum.BROAD
    )

    # Uncomment the below line if you want to change this keyword to a negative target.
    # ad_group_criterion.negative = True

    # Optional repeated field
    # ad_group_criterion.final_urls.append('https://www.example.com')

    # Add operation
    operations.append(ad_group_criterion_operation)

    # Add keywords
    ad_group_criterion_response = (
        ad_group_criterion_service.mutate_ad_group_criteria(
            customer_id=customer_id,
            operations=operations,
        )
    )
    for result in ad_group_criterion_response.results:
        print("Created keyword " f"{result.resource_name}.")


def add_geo_targeting(client, customer_id, campaign_resource_name):
    """Creates geo targets.

    Args:
      client: an initialized GoogleAdsClient instance.
      customer_id: a client customer ID.
      campaign_resource_name: an campaign resource name.

    Returns:
      Geo targets.
    """
    geo_target_constant_service = client.get_service("GeoTargetConstantService")

    # Search by location names from
    # GeoTargetConstantService.suggest_geo_target_constants() and directly
    # apply GeoTargetConstant.resource_name.
    gtc_request = client.get_type("SuggestGeoTargetConstantsRequest")
    gtc_request.locale = LOCALE
    gtc_request.country_code = COUNTRY_CODE

    # The location names to get suggested geo target constants.
    gtc_request.location_names.names.extend(
        [GEO_LOCATION_1, GEO_LOCATION_2, GEO_LOCATION_3]
    )

    results = geo_target_constant_service.suggest_geo_target_constants(
        gtc_request
    )

    operations = []
    for suggestion in results.geo_target_constant_suggestions:
        print(
            "geo_target_constant: "
            f"{suggestion.geo_target_constant.resource_name} "
            f"is found in LOCALE ({suggestion.locale}) "
            f"with reach ({suggestion.reach}) "
            f"from search term ({suggestion.search_term})."
        )
        # Create the campaign criterion for location targeting.
        campaign_criterion_operation = client.get_type(
            "CampaignCriterionOperation"
        )
        campaign_criterion = campaign_criterion_operation.create
        campaign_criterion.campaign = campaign_resource_name
        campaign_criterion.location.geo_target_constant = (
            suggestion.geo_target_constant.resource_name
        )
        operations.append(campaign_criterion_operation)

    campaign_criterion_service = client.get_service("CampaignCriterionService")
    campaign_criterion_response = (
        campaign_criterion_service.mutate_campaign_criteria(
            customer_id=customer_id, operations=[*operations]
        )
    )

    for result in campaign_criterion_response.results:
        print(f'Added campaign criterion "{result.resource_name}".')


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description=("Creates a Responsive Search Ad for specified 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.",
    )

    # The name of the customizer attribute used in the ad customizer, which
    # must be unique for a given customer account. To run this example multiple
    # times, specify a unique value as a command line argument. Note that there is
    # a limit for the number of enabled customizer attributes in one account
    # For more details visit:
    # https://developers.google.com/google-ads/api/docs/ads/customize-responsive-search-ads#rules_and_limitations
    parser.add_argument(
        "-n",
        "--customizer_attribute_name",
        type=str,
        default=None,
        help=(
            "The name of the customizer attribute to be created. The name must "
            "be unique across a client account, so be sure not to use "
            "the same value more than once."
        ),
    )

    args = parser.parse_args()

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

    try:
        main(
            googleads_client,
            args.customer_id,
            args.customizer_attribute_name,
        )
    except GoogleAdsException as ex:
        print(
            f'Request with ID "{ex.request_id}" failed with status '
            f'"{ex.error.code().name}" and includes the following errors:'
        )
        for error in ex.failure.errors:
            print(f'Error 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)

      

Ruby

This example is not yet available in Ruby; you can take a look at the other languages.
    

Perl

#!/usr/bin/perl -w
#
# Copyright 2024, 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.
#
# This example shows how to create a complete Responsive Search ad.
# Includes creation of: budget, campaign, ad group, ad group ad, keywords,
# and geo targeting. More details on Responsive Search ads can be found here:
# https://support.google.com/google-ads/answer/7684791

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::V18::Resources::Campaign;
use Google::Ads::GoogleAds::V18::Resources::CampaignBudget;
use Google::Ads::GoogleAds::V18::Resources::CampaignCriterion;
use Google::Ads::GoogleAds::V18::Resources::CustomizerAttribute;
use Google::Ads::GoogleAds::V18::Resources::CustomerCustomizer;
use Google::Ads::GoogleAds::V18::Resources::Ad;
use Google::Ads::GoogleAds::V18::Resources::AdGroup;
use Google::Ads::GoogleAds::V18::Resources::AdGroupAd;
use Google::Ads::GoogleAds::V18::Resources::AdGroupCriterion;
use Google::Ads::GoogleAds::V18::Resources::NetworkSettings;
use Google::Ads::GoogleAds::V18::Common::AdTextAsset;
use Google::Ads::GoogleAds::V18::Common::CustomizerValue;
use Google::Ads::GoogleAds::V18::Common::ImageDimension;
use Google::Ads::GoogleAds::V18::Common::KeywordInfo;
use Google::Ads::GoogleAds::V18::Common::LocationInfo;
use Google::Ads::GoogleAds::V18::Common::ResponsiveSearchAdInfo;
use Google::Ads::GoogleAds::V18::Common::TargetSpend;
use Google::Ads::GoogleAds::V18::Enums::AdvertisingChannelTypeEnum qw(SEARCH);
use Google::Ads::GoogleAds::V18::Enums::BudgetDeliveryMethodEnum   qw(STANDARD);
use Google::Ads::GoogleAds::V18::Enums::CustomizerAttributeTypeEnum qw(PRICE);
use Google::Ads::GoogleAds::V18::Enums::AdGroupAdStatusEnum;
use Google::Ads::GoogleAds::V18::Enums::AdGroupCriterionStatusEnum;
use Google::Ads::GoogleAds::V18::Enums::AdGroupStatusEnum;
use Google::Ads::GoogleAds::V18::Enums::AdGroupTypeEnum    qw(SEARCH_STANDARD);
use Google::Ads::GoogleAds::V18::Enums::AssetTypeEnum      qw(IMAGE);
use Google::Ads::GoogleAds::V18::Enums::CampaignStatusEnum qw(PAUSED);
use Google::Ads::GoogleAds::V18::Enums::KeywordMatchTypeEnum
  qw(BROAD EXACT PHRASE);
use Google::Ads::GoogleAds::V18::Enums::MimeTypeEnum             qw(IMAGE_PNG);
use Google::Ads::GoogleAds::V18::Enums::ServedAssetFieldTypeEnum qw(HEADLINE_1);
use Google::Ads::GoogleAds::V18::Services::AdGroupService::AdGroupOperation;
use Google::Ads::GoogleAds::V18::Services::AdGroupAdService::AdGroupAdOperation;
use
  Google::Ads::GoogleAds::V18::Services::AdGroupCriterionService::AdGroupCriterionOperation;
use Google::Ads::GoogleAds::V18::Services::AssetService::AssetOperation;
use
  Google::Ads::GoogleAds::V18::Services::CampaignBudgetService::CampaignBudgetOperation;
use
  Google::Ads::GoogleAds::V18::Services::CampaignCriterionService::CampaignCriterionOperation;
use Google::Ads::GoogleAds::V18::Services::CampaignService::CampaignOperation;
use
  Google::Ads::GoogleAds::V18::Services::CustomizerAttributeService::CustomizerAttributeOperation;
use
  Google::Ads::GoogleAds::V18::Services::CustomerCustomizerService::CustomerCustomizerOperation;
use
  Google::Ads::GoogleAds::V18::Services::GeoTargetConstantService::LocationNames;
use Google::Ads::GoogleAds::V18::Utils::ResourceNames;

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

# Keywords from the user.
use constant KEYWORD_TEXT_EXACT  => "example of exact match";
use constant KEYWORD_TEXT_PHRASE => "example of phrase match";
use constant KEYWORD_TEXT_BROAD  => "example of broad match";

# Geo targeting from the user.
use constant GEO_LOCATION_1 => "Buenos Aires";
use constant GEO_LOCATION_2 => "San Isidro";
use constant GEO_LOCATION_3 => "Mar del Plata";

# LOCALE and COUNTRY_CODE are used for geo targeting.
# LOCALE is using ISO 639-1 format. If an invalid LOCALE is given,
# 'es' is used by default.
use constant LOCALE => "es";
# A list of country codes can be referenced here:
# https://developers.google.com/google-ads/api/reference/data/geotargets
use constant COUNTRY_CODE => "AR";

use constant IMAGE_URL => "https://gaagl.page.link/bjYi";

sub add_responsive_search_ad_full {
  my ($api_client, $customer_id, $customizer_attribute_name) = @_;

  # If a customizer attribute name is provided, create the customizer
  # attribute and link it to the customer.
  # For more information on customizer attributes, visit:
  # https://developers.google.com/google-ads/api/docs/ads/customize-responsive-search-ads
  if (defined $customizer_attribute_name) {
    my $customizer_attribute_resource_name =
      create_customizer_attribute($api_client, $customer_id,
      $customizer_attribute_name);

    link_customizer_attribute_to_customer($api_client, $customer_id,
      $customizer_attribute_resource_name);
  }

  # Create a budget, which can be shared by multiple campaigns.
  my $campaign_budget = create_campaign_budget($api_client, $customer_id);

  # Create a search campaign.
  my $campaign_resource_name =
    create_campaign($api_client, $customer_id, $campaign_budget);

  # Create an empty ad group.
  my $ad_group_resource_name =
    create_ad_group($api_client, $customer_id, $campaign_resource_name);

  # Create a responsive search ad within the ad group we just created.
  create_ad_group_ad($api_client, $customer_id, $ad_group_resource_name,
    $customizer_attribute_name);

  # Create 3 keywords of match type EXACT, PHRASE, and BROAD, and add them
  # as criteria on our ad group.
  add_keywords($api_client, $customer_id, $ad_group_resource_name);

  # Create geo targets and add them as criteria on our campaign.
  add_geo_targeting($api_client, $customer_id, $campaign_resource_name);

  return 1;
}

# Creates a customizer attribute with the given customizer attribute name.
sub create_customizer_attribute {
  my ($api_client, $customer_id, $customizer_attribute_name) = @_;

  my $customizer_attribute =
    Google::Ads::GoogleAds::V18::Resources::CustomizerAttribute->new({
      name => $customizer_attribute_name,
      # Specify the type to be 'PRICE' so that we can dynamically customize the part
      # of the ad's description that is a price of a product/service we advertise.
      type => PRICE
    });

  # Create a customizer attribute operation for creating a customizer attribute.
  my $operation =
    Google::Ads::GoogleAds::V18::Services::CustomizerAttributeService::CustomizerAttributeOperation
    ->new({
      create => $customizer_attribute
    });

  my $response = $api_client->CustomizerAttributeService()->mutate({
      customerId => $customer_id,
      operations => [$operation]});
  my $resource_name =
    $response->{results}[0]{resourceName};
  printf "Added a customizer attribute with resource name '%s'.\n",
    $resource_name;

  return $resource_name;
}

# Links the customizer attribute to the customer.
sub link_customizer_attribute_to_customer {
  my ($api_client, $customer_id, $customizer_attribute_resource_name) = @_;

  # Create a customer customizer with the value to be used in the responsive search ad.
  my $customer_customizer =
    Google::Ads::GoogleAds::V18::Resources::CustomerCustomizer->new({
      customizerAttribute => $customizer_attribute_resource_name,
      # Specify '100USD' as a text value. The ad customizer will dynamically replace
      # the placeholder with this value when the ad serves.
      value => Google::Ads::GoogleAds::V18::Common::CustomizerValue->new({
          type        => PRICE,
          stringValue => "100USD"
        })});

  # Create a customer customizer operation.
  my $operation =
    Google::Ads::GoogleAds::V18::Services::CustomerCustomizerService::CustomerCustomizerOperation
    ->new({
      create => $customer_customizer
    });

  # Issue a mutate request to add the customer customizer and print its information.
  my $response = $api_client->CustomerCustomizerService()->mutate({
      customerId => $customer_id,
      operations => [$operation]});
  printf "Added a customer customizer with resource name '%s'.\n",
    $response->{results}[0]{resourceName};
}

# Creates an AdTextAsset.
sub create_ad_text_asset {
  my ($api_client, $text, $pinned_field) = @_;

  my $ad_text_asset = Google::Ads::GoogleAds::V18::Common::AdTextAsset->new({
    text => $text
  });

  if (defined $pinned_field) {
    $ad_text_asset->{pinnedField} = $pinned_field;
  }

  return $ad_text_asset;
}

# Creates an AdTextAsset with a customizer in the text.
sub create_ad_text_asset_with_customizer {
  my ($api_client, $customizer_attribute_resource_name) = @_;

  my $ad_text_asset = create_ad_text_asset($api_client,
    "Just {CUSTOMIZER.$customizer_attribute_resource_name:10USD}");

  return $ad_text_asset;
}

# Creates a campaign budget.
sub create_campaign_budget {
  my ($api_client, $customer_id) = @_;

  # Create a campaign budget.
  my $campaign_budget =
    Google::Ads::GoogleAds::V18::Resources::CampaignBudget->new({
      name           => "Campaign budget " . uniqid(),
      amountMicros   => 50000000,
      deliveryMethod => STANDARD
    });

  # Create a campaign budget operation.
  my $campaign_budget_operation =
    Google::Ads::GoogleAds::V18::Services::CampaignBudgetService::CampaignBudgetOperation
    ->new({
      create => $campaign_budget
    });

  # Issue a mutate request to add the campaign budget.
  my $campaign_budgets_response = $api_client->CampaignBudgetService()->mutate({
      customerId => $customer_id,
      operations => [$campaign_budget_operation]});

  my $campaign_budget_resource_name =
    $campaign_budgets_response->{results}[0]{resourceName};

  return $campaign_budget_resource_name;
}

# Creates a campaign.
sub create_campaign {
  my ($api_client, $customer_id, $campaign_budget) = @_;

  # Create a campaign.
  my $campaign = Google::Ads::GoogleAds::V18::Resources::Campaign->new({
      name           => "Testing RSA via API " . uniqid(),
      campaignBudget => $campaign_budget,
      # Recommendation: Set the campaign to PAUSED when creating it to prevent
      # the ads from immediately serving. Set to ENABLED once you've added
      # targeting and the ads are ready to serve.
      status                 => PAUSED,
      advertisingChannelType => SEARCH,
      # Set the bidding strategy and budget.
      # The bidding strategy for Maximize Clicks is TargetSpend.
      # The target_spend_micros is deprecated so don't put any value.
      # See other bidding strategies you can select in the link below.
      # https://developers.google.com/google-ads/api/reference/rpc/latest/Campaign#campaign_bidding_strategy
      targetSpend => Google::Ads::GoogleAds::V18::Common::TargetSpend->new(),
      # Set the campaign network options
      networkSettings =>
        Google::Ads::GoogleAds::V18::Resources::NetworkSettings->new({
          targetGoogleSearch  => "true",
          targetSearchNetwork => "true",
          # Enable Display Expansion on Search campaigns. See
          # https://support.google.com/google-ads/answer/7193800 to learn more.
          targetContentNetwork       => "true",
          targetPartnerSearchNetwork => "false"
        }
        ),
      # Optional: Set the start date. The campaign starts tomorrow.
      # startDate => strftime("%Y%m%d", localtime(time + 60 * 60 * 24)),
      # Optional: Set the end date. The campaign runs for 30 days.
      # endDate => strftime("%Y%m%d", localtime(time + 60 * 60 * 24 * 30)),
    });

  # Create a campaign operation.
  my $campaign_operation =
    Google::Ads::GoogleAds::V18::Services::CampaignService::CampaignOperation->
    new({
      create => $campaign
    });

  # Issue a mutate request to add the campaign.
  my $campaigns_response = $api_client->CampaignService()->mutate({
      customerId => $customer_id,
      operations => [$campaign_operation]});

  my $resource_name =
    $campaigns_response->{results}[0]{resourceName};
  printf "Created App campaign with resource name: '%s'.\n", $resource_name;

  return $resource_name;
}

# Creates an ad group.
sub create_ad_group {
  my ($api_client, $customer_id, $campaign_resource_name) = @_;

  # Create an ad group, setting an optional CPC value.
  my $ad_group = Google::Ads::GoogleAds::V18::Resources::AdGroup->new({
    name   => "Testing RSA via API " . uniqid(),
    status => Google::Ads::GoogleAds::V18::Enums::AdGroupStatusEnum::ENABLED,
    campaign => $campaign_resource_name,
    type     => SEARCH_STANDARD,
    # If you want to set up a max CPC bid, uncomment the line below.
    # cpcBidMicros => 10000000
  });

  # Create an ad group operation.
  my $ad_group_operation =
    Google::Ads::GoogleAds::V18::Services::AdGroupService::AdGroupOperation->
    new({create => $ad_group});

  # Add the ad group.
  my $ad_groups_response = $api_client->AdGroupService()->mutate({
      customerId => $customer_id,
      operations => [$ad_group_operation]});

  my $ad_group_resource_name = $ad_groups_response->{results}[0]{resourceName};
  printf "Created ad group '%s'.\n", $ad_group_resource_name;
  return $ad_group_resource_name;
}

# Creates an ad group ad.
sub create_ad_group_ad {
  my ($api_client, $customer_id, $ad_group_resource_name,
    $customizer_attribute_name)
    = @_;

  # Set a pinning to always choose this asset for HEADLINE_1. Pinning is optional; if no
  # pinning is set, then headlines and descriptions will be rotated and the ones that perform
  # best will be used more often.
  my $pinned_headline =
    create_ad_text_asset($api_client, "Headline 1 testing", HEADLINE_1);

  my $ad_group_ad = Google::Ads::GoogleAds::V18::Resources::AdGroupAd->new({
      adGroup => $ad_group_resource_name,
      status  =>
        Google::Ads::GoogleAds::V18::Enums::AdGroupAdStatusEnum::ENABLED,
      ad => Google::Ads::GoogleAds::V18::Resources::Ad->new({
          # Set responsive search ad info.
          # https://developers.google.com/google-ads/api/reference/rpc/latest/ResponsiveSearchAdInfo
          responsiveSearchAd =>
            Google::Ads::GoogleAds::V18::Common::ResponsiveSearchAdInfo->new({
              headlines => [
                $pinned_headline,
                create_ad_text_asset($api_client, "Headline 2 testing"),
                create_ad_text_asset($api_client, "Headline 3 testing"),
              ],
              descriptions => [
                create_ad_text_asset($api_client, "Desc 1 testing"),
                defined $customizer_attribute_name
                ? create_ad_text_asset_with_customizer($api_client,
                  $customizer_attribute_name)
                : create_ad_text_asset($api_client, "Desc 2 testing"),
              ],
              # First and second part of text that can be appended to the URL in the ad.
              # If you use the examples below, the ad will show
              # https://www.example.com/all-inclusive/deals
              path1 => "all-inclusive",
              path2 => "deals"
            }
            ),
          finalUrls => ["https://www.example.com"]})});

  # Create an ad group ad operation.
  my $operation =
    Google::Ads::GoogleAds::V18::Services::AdGroupAdService::AdGroupAdOperation
    ->new({
      create => $ad_group_ad
    });

  # Issue a mutate request to add the ad group ad and print its information.
  my $response = $api_client->AdGroupAdService()->mutate({
      customerId => $customer_id,
      operations => [$operation]});
  printf "Created responsive search ad with resource name '%s'.\n",
    $response->{results}[0]{resourceName};
}

# Creates keywords of 3 keyword match types: EXACT, PHRASE, and BROAD.
# EXACT: ads may show on searches that ARE the same meaning as your keyword.
# PHRASE: ads may show on searches that INCLUDE the meaning of your keyword.
# BROAD: ads may show on searches that RELATE to your keyword.
# For smart bidding, BROAD is the recommended one.
sub add_keywords {
  my ($api_client, $customer_id, $ad_group_resource_name) = @_;

  my $operations = [];

  # Create a hash of keyword match types to keyword text to simplify ad group
  # criteria construction.
  my $keywords = {
    EXACT()  => KEYWORD_TEXT_EXACT,
    BROAD()  => KEYWORD_TEXT_BROAD,
    PHRASE() => KEYWORD_TEXT_PHRASE,
  };

  foreach my $keyword (keys %$keywords) {
    my $keyword_info = Google::Ads::GoogleAds::V18::Common::KeywordInfo->new({
      text      => $keywords->{$keyword},
      matchType => $keyword,
    });

    my $ad_group_criterion =
      Google::Ads::GoogleAds::V18::Resources::AdGroupCriterion->new({
        adGroup => $ad_group_resource_name,
        status  =>
          Google::Ads::GoogleAds::V18::Enums::AdGroupCriterionStatusEnum::ENABLED,
        keyword => $keyword_info,
        # Uncomment the below line if you want to change this keyword to a negative target.
        # negative => "true",

        # Optional repeated field.
        # finalUrls => ["https://www.example.com"],
      });

    my $ad_group_criterion_operation =
      Google::Ads::GoogleAds::V18::Services::AdGroupCriterionService::AdGroupCriterionOperation
      ->new({create => $ad_group_criterion});

    push @$operations, $ad_group_criterion_operation;
  }

  my $response = $api_client->AdGroupCriterionService()->mutate({
    customerId => $customer_id,
    operations => $operations
  });

  foreach my $result (@{$response->{results}}) {
    printf "Created keyword with resource name: '%s'.\n",
      $result->{resourceName};
  }
}

# Creates geo targets.
sub add_geo_targeting {
  my ($api_client, $customer_id, $campaign_resource_name) = @_;

  my $suggest_response = $api_client->GeoTargetConstantService()->suggest({
      locale        => LOCALE,
      countryCode   => COUNTRY_CODE,
      locationNames =>
        Google::Ads::GoogleAds::V18::Services::GeoTargetConstantService::LocationNames
        ->new({
          names => [GEO_LOCATION_1, GEO_LOCATION_2, GEO_LOCATION_3]})});

  my $operations = [];
  foreach my $geo_target_constant_suggestion (
    @{$suggest_response->{geoTargetConstantSuggestions}})
  {
    printf "geo target constant: '%s' is found in locale '%s' with reach %d" .
      " for the search term '%s'.\n",
      $geo_target_constant_suggestion->{geoTargetConstant}{resourceName},
      $geo_target_constant_suggestion->{locale},
      $geo_target_constant_suggestion->{reach},
      $geo_target_constant_suggestion->{searchTerm};

    # Create the campaign criterion for location targeting.
    my $campaign_criterion =
      Google::Ads::GoogleAds::V18::Resources::CampaignCriterion->new({
        location => Google::Ads::GoogleAds::V18::Common::LocationInfo->new({
            geoTargetConstant =>
              $geo_target_constant_suggestion->{geoTargetConstant}{resourceName}
          }
        ),
        campaign => $campaign_resource_name
      });

    push @$operations,
      Google::Ads::GoogleAds::V18::Services::CampaignCriterionService::CampaignCriterionOperation
      ->new({
        create => $campaign_criterion
      });
  }

  # Return if operations is empty.
  if (scalar @$operations == 0) {
    return;
  }
  my $campaign_criterion_response =
    $api_client->CampaignCriterionService()->mutate({
      customerId => $customer_id,
      operations => $operations
    });
  my $campaign_criterion_results = $campaign_criterion_response->{results};
  printf "Added %d campaign criteria:\n", scalar @$campaign_criterion_results;

  foreach my $campaign_criterion_result (@$campaign_criterion_results) {
    printf "\t%s\n", $campaign_criterion_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);

my $customer_id;
my $customizer_attribute_name;

# Parameters passed on the command line will override any parameters set in code.
GetOptions(
  "customer_id=s"               => \$customer_id,
  "customizer_attribute_name=s" => \$customizer_attribute_name,
);

# 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);

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

=pod

=head1 NAME

add_responsive_search_ad_full

=head1 DESCRIPTION

This example shows how to create a complete Responsive Search ad.
Includes creation of: budget, campaign, ad group, ad group ad, keywords,
and geo targeting. More details on Responsive Search ads can be found here:
https://support.google.com/google-ads/answer/7684791

=head1 SYNOPSIS

add_responsive_search_ad_full.pl [options]

    -help                           Show the help message.
    -customer_id                    The Google Ads customer ID.
    -customizer_attribute_name      [optional] The name of the customizer attribute.

=cut