制作广告

添加自适应搜索广告

要在 API 中制作新广告,最佳方法是使用客户端库的“基本操作”文件夹中的“添加自适应搜索广告代码示例”。此示例会为您处理所有后台身份验证任务,并引导您制作自适应搜索广告。

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.V16.Common;
using Google.Ads.GoogleAds.V16.Resources;
using Google.Ads.GoogleAds.V16.Services;
using System.Collections.Generic;
using System.Linq;
using System;
using static Google.Ads.GoogleAds.V16.Enums.AdGroupTypeEnum.Types;
using static Google.Ads.GoogleAds.V16.Enums.AdGroupAdStatusEnum.Types;
using static Google.Ads.GoogleAds.V16.Enums.AdGroupCriterionStatusEnum.Types;
using static Google.Ads.GoogleAds.V16.Enums.AdGroupStatusEnum.Types;
using static Google.Ads.GoogleAds.V16.Enums.AdvertisingChannelTypeEnum.Types;
using static Google.Ads.GoogleAds.V16.Enums.BudgetDeliveryMethodEnum.Types;
using static Google.Ads.GoogleAds.V16.Enums.CampaignStatusEnum.Types;
using static Google.Ads.GoogleAds.V16.Enums.CustomizerAttributeTypeEnum.Types;
using static Google.Ads.GoogleAds.V16.Enums.KeywordMatchTypeEnum.Types;
using static Google.Ads.GoogleAds.V16.Services.SuggestGeoTargetConstantsRequest.Types;
using Google.Ads.GoogleAds.Config;
using Google.Ads.GoogleAds.Extensions.Config;

namespace Google.Ads.GoogleAds.Examples.V16
{
    /// <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.V16.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.V16.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.V16.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.V16.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.V16.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.V16.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.V16.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.V16.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.V16.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__":
    # GoogleAdsClient will read the google-ads.yaml configuration file in the
    # home directory if none is specified.
    googleads_client = GoogleAdsClient.load_from_storage(version="v16")

    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()

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

  # Create a customer customizer operation.
  my $operation =
    Google::Ads::GoogleAds::V16::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::V16::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::V16::Resources::CampaignBudget->new({
      name           => "Campaign budget " . uniqid(),
      amountMicros   => 50000000,
      deliveryMethod => STANDARD
    });

  # Create a campaign budget operation.
  my $campaign_budget_operation =
    Google::Ads::GoogleAds::V16::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::V16::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::V16::Common::TargetSpend->new(),
      # Set the campaign network options
      networkSettings =>
        Google::Ads::GoogleAds::V16::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::V16::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::V16::Resources::AdGroup->new({
    name   => "Testing RSA via API " . uniqid(),
    status => Google::Ads::GoogleAds::V16::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::V16::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::V16::Resources::AdGroupAd->new({
      adGroup => $ad_group_resource_name,
      status  =>
        Google::Ads::GoogleAds::V16::Enums::AdGroupAdStatusEnum::ENABLED,
      ad => Google::Ads::GoogleAds::V16::Resources::Ad->new({
          # Set responsive search ad info.
          # https://developers.google.com/google-ads/api/reference/rpc/latest/ResponsiveSearchAdInfo
          responsiveSearchAd =>
            Google::Ads::GoogleAds::V16::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::V16::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::V16::Common::KeywordInfo->new({
      text      => $keywords->{$keyword},
      matchType => $keyword,
    });

    my $ad_group_criterion =
      Google::Ads::GoogleAds::V16::Resources::AdGroupCriterion->new({
        adGroup => $ad_group_resource_name,
        status  =>
          Google::Ads::GoogleAds::V16::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::V16::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::V16::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::V16::Resources::CampaignCriterion->new({
        location => Google::Ads::GoogleAds::V16::Common::LocationInfo->new({
            geoTargetConstant =>
              $geo_target_constant_suggestion->{geoTargetConstant}{resourceName}
          }
        ),
        campaign => $campaign_resource_name
      });

    push @$operations,
      Google::Ads::GoogleAds::V16::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