Add Performance Max Retail Campaign

Java

 // 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 
 // 
 //     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. 
 package 
  
 com.google.ads.googleads.examples.shoppingads 
 ; 
 import static 
  
 com.google.ads.googleads.examples.utils.CodeSampleHelper.getPrintableDateTime 
 ; 
 import static 
  
 com.google.ads.googleads.v21.enums.EuPoliticalAdvertisingStatusEnum.EuPoliticalAdvertisingStatus.DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING 
 ; 
 import 
  
 com.beust.jcommander.Parameter 
 ; 
 import 
  
 com.google.ads.googleads.examples.utils.ArgumentNames 
 ; 
 import 
  
 com.google.ads.googleads.examples.utils.CodeSampleParams 
 ; 
 import 
  
 com.google.ads.googleads.lib.GoogleAdsClient 
 ; 
 import 
  
 com.google.ads.googleads.lib.utils.FieldMasks 
 ; 
 import 
  
 com.google.ads.googleads.v21.common.ImageAsset 
 ; 
 import 
  
 com.google.ads.googleads.v21.common.LanguageInfo 
 ; 
 import 
  
 com.google.ads.googleads.v21.common.LocationInfo 
 ; 
 import 
  
 com.google.ads.googleads.v21.common.MaximizeConversionValue 
 ; 
 import 
  
 com.google.ads.googleads.v21.common.TextAsset 
 ; 
 import 
  
 com.google.ads.googleads.v21.enums.AdvertisingChannelTypeEnum.AdvertisingChannelType 
 ; 
 import 
  
 com.google.ads.googleads.v21.enums.AssetFieldTypeEnum.AssetFieldType 
 ; 
 import 
  
 com.google.ads.googleads.v21.enums.AssetGroupStatusEnum.AssetGroupStatus 
 ; 
 import 
  
 com.google.ads.googleads.v21.enums.BudgetDeliveryMethodEnum.BudgetDeliveryMethod 
 ; 
 import 
  
 com.google.ads.googleads.v21.enums.CampaignStatusEnum.CampaignStatus 
 ; 
 import 
  
 com.google.ads.googleads.v21.enums.ConversionActionCategoryEnum.ConversionActionCategory 
 ; 
 import 
  
 com.google.ads.googleads.v21.enums.ConversionOriginEnum.ConversionOrigin 
 ; 
 import 
  
 com.google.ads.googleads.v21.enums.ListingGroupFilterListingSourceEnum.ListingGroupFilterListingSource 
 ; 
 import 
  
 com.google.ads.googleads.v21.enums.ListingGroupFilterTypeEnum.ListingGroupFilterType 
 ; 
 import 
  
 com.google.ads.googleads.v21.errors.GoogleAdsError 
 ; 
 import 
  
 com.google.ads.googleads.v21.errors.GoogleAdsException 
 ; 
 import 
  
 com.google.ads.googleads.v21.resources.Asset 
 ; 
 import 
  
 com.google.ads.googleads.v21.resources.AssetGroup 
 ; 
 import 
  
 com.google.ads.googleads.v21.resources.AssetGroupAsset 
 ; 
 import 
  
 com.google.ads.googleads.v21.resources.AssetGroupListingGroupFilter 
 ; 
 import 
  
 com.google.ads.googleads.v21.resources.Campaign 
 ; 
 import 
  
 com.google.ads.googleads.v21.resources.Campaign.ShoppingSetting 
 ; 
 import 
  
 com.google.ads.googleads.v21.resources.CampaignAsset 
 ; 
 import 
  
 com.google.ads.googleads.v21.resources.CampaignBudget 
 ; 
 import 
  
 com.google.ads.googleads.v21.resources.CampaignConversionGoal 
 ; 
 import 
  
 com.google.ads.googleads.v21.resources.CampaignCriterion 
 ; 
 import 
  
 com.google.ads.googleads.v21.resources.CustomerConversionGoal 
 ; 
 import 
  
 com.google.ads.googleads.v21.services.AssetGroupAssetOperation 
 ; 
 import 
  
 com.google.ads.googleads.v21.services.AssetGroupListingGroupFilterOperation 
 ; 
 import 
  
 com.google.ads.googleads.v21.services.AssetGroupOperation 
 ; 
 import 
  
 com.google.ads.googleads.v21.services.AssetOperation 
 ; 
 import 
  
 com.google.ads.googleads.v21.services.CampaignAssetOperation 
 ; 
 import 
  
 com.google.ads.googleads.v21.services.CampaignBudgetOperation 
 ; 
 import 
  
 com.google.ads.googleads.v21.services.CampaignConversionGoalOperation 
 ; 
 import 
  
 com.google.ads.googleads.v21.services.CampaignCriterionOperation 
 ; 
 import 
  
 com.google.ads.googleads.v21.services.CampaignOperation 
 ; 
 import 
  
 com.google.ads.googleads.v21.services.GoogleAdsRow 
 ; 
 import 
  
 com.google.ads.googleads.v21.services.GoogleAdsServiceClient 
 ; 
 import 
  
 com.google.ads.googleads.v21.services.GoogleAdsServiceClient.SearchPagedResponse 
 ; 
 import 
  
 com.google.ads.googleads.v21.services.MutateGoogleAdsResponse 
 ; 
 import 
  
 com.google.ads.googleads.v21.services.MutateOperation 
 ; 
 import 
  
 com.google.ads.googleads.v21.services.MutateOperationResponse 
 ; 
 import 
  
 com.google.ads.googleads.v21.utils.ResourceNames 
 ; 
 import 
  
 com.google.common.collect.ImmutableList 
 ; 
 import 
  
 com.google.common.io.ByteStreams 
 ; 
 import 
  
 com.google.protobuf.ByteString 
 ; 
 import 
  
 com.google.protobuf.Descriptors.FieldDescriptor 
 ; 
 import 
  
 java.io.FileNotFoundException 
 ; 
 import 
  
 java.io.IOException 
 ; 
 import 
  
 java.net.URL 
 ; 
 import 
  
 java.util.ArrayList 
 ; 
 import 
  
 java.util.List 
 ; 
 import 
  
 java.util.Map.Entry 
 ; 
 import 
  
 java.util.stream.Collectors 
 ; 
 import 
  
 org.joda.time.DateTime 
 ; 
 /** 
 * This example shows how to create a Performance Max ret<a>il campaign. 
 * 
 * pThis will be created for &q<u>ot;All products". 
 * 
 * pFor more information about Performance Max retail campaigns, see 
 * https://developers.google.com/google-ads/api/docs</>performance-max/retail 
 * 
 * pPrerequisites: - You need to have access to a Merchant Center account. You can find 
 * instructions to create a Merchant Center account here: 
 * https://support.google.com/merchants/answer/188924. This account must be linked to your Google 
 * Ads account. The integration instructions can be found at: 
 * https://developers.google.com/google-ads/api/docs/shopping-ads/merchant-center - You need your 
 * Google Ads account to track conversions. The different ways to track conversions can be found 
 * here: https://support.google.com/google-ads/answer/1722054. - You must have at least one 
 * conversion action in the account. For more about conversion actions, see 
 * https://developers.google.com/google-ads/api/docs/conversions/overview#conversion_actions 
 */ 
 public 
  
 class 
 AddPerformanceMaxRetailCampaign 
  
 { 
  
 // We specify temporary IDs that are specific to a single mutate request. Temporary IDs are always 
  
 // negative and unique within <o>ne mutate request. 
  
 // 
  
 // pSee https://developers.google.com/google-ads/api/docs/mutating/best-practices for fu<r>ther 
  
 // details. 
  
 // 
  
 // pThese temporary IDs are fixed because they are used in multiple places. 
  
 private 
  
 static 
  
 final 
  
 int 
  
 BUDGET_TEMPORARY_ID 
  
 = 
  
 - 
 1 
 ; 
  
 private 
  
 static 
  
 final 
  
 int 
  
 PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
  
 = 
  
 - 
 2 
 ; 
  
 private 
  
 static 
  
 final 
  
 int 
  
 ASSET_GROUP_TEMPORARY_ID 
  
 = 
  
 - 
 3 
 ; 
  
 // There are also entities that will be created in the same request but do not 
  
 // need to be fixed temporary IDs because they are referenced only once. 
  
 private 
  
 static 
  
 long 
  
 temporaryId 
  
 = 
  
 ASSET_GROUP_TEMPORARY_ID 
  
 - 
  
 1 
 ; 
  
 private 
  
 static 
  
 class 
 AddPerformanceMaxRetailCampaignParams 
  
 extends 
  
 CodeSampleParams 
  
 { 
  
 @Parameter 
 ( 
 names 
  
 = 
  
 ArgumentNames 
 . 
 CUSTOMER_ID 
 , 
  
 required 
  
 = 
  
 true 
 ) 
  
 private 
  
 Long 
  
 customerId 
 ; 
  
 @Parameter 
 ( 
  
 names 
  
 = 
  
 ArgumentNames 
 . 
 MERCHANT_CENTER_ACCOUNT_ID 
 , 
  
 required 
  
 = 
  
 true 
 , 
  
 description 
  
 = 
  
 "The Merchant Center account ID." 
 ) 
  
 private 
  
 long 
  
 merchantCenterAccountId 
 ; 
  
 @Parameter 
 ( 
  
 names 
  
 = 
  
 ArgumentNames 
 . 
 SALES_COUNTRY 
 , 
  
 description 
  
 = 
  
 "The sales country of products to include in the campaign." 
 ) 
  
 private 
  
 String 
  
 salesCountry 
  
 = 
  
 "US" 
 ; 
  
 @Parameter 
 ( 
  
 names 
  
 = 
  
 ArgumentNames 
 . 
 FINAL_URL 
 , 
  
 required 
  
 = 
  
 true 
 , 
  
 description 
  
 = 
  
 "The final url for the generated ads. Must have the same domain as the Merchant Center" 
  
 + 
  
 " account." 
 ) 
  
 private 
  
 String 
  
 finalUrl 
 ; 
  
 @Parameter 
 ( 
  
 names 
  
 = 
  
 "--brandGuidelinesEnabled" 
 , 
  
 arity 
  
 = 
  
 1 
 , 
  
 description 
  
 = 
  
 "A boolean value indicating if the created campaign is enabled for brand guidelines" 
 ) 
  
 private 
  
 boolean 
  
 brandGuidelinesEnabled 
  
 = 
  
 false 
 ; 
  
 } 
  
 public 
  
 static 
  
 void 
  
 main 
 ( 
 String 
 [] 
  
 args 
 ) 
  
 throws 
  
 IOException 
  
 { 
  
 AddPerformanceMaxRetailCampaignParams 
  
 params 
  
 = 
  
 new 
  
 AddPerformanceMaxRetailCampaignParams 
 (); 
  
 if 
  
 ( 
 ! 
 params 
 . 
 parseArguments 
 ( 
 args 
 )) 
  
 { 
  
 // Either pass the required parameters for this example on the command line, or insert them 
  
 // into the code here. See the parameter class definition above for descriptions. 
  
 params 
 . 
 customerId 
  
 = 
  
 Long 
 . 
 parseLong 
 ( 
 "INSERT_CUSTOMER_ID_HERE" 
 ); 
  
 params 
 . 
 merchantCenterAccountId 
  
 = 
  
 Long 
 . 
 parseLong 
 ( 
 "INSERT_MERCHANT_CENTER_ACCOUNT_ID_HERE" 
 ); 
  
 params 
 . 
 finalUrl 
  
 = 
  
 "INSERT_FINAL_URL_HERE" 
 ; 
  
 // Optionally set the sales country. 
  
 // params.salesCountry = "INSERT_SALES_COUNTRY_HERE"; 
  
 } 
  
 GoogleAdsClient 
  
 googleAdsClient 
  
 = 
  
 null 
 ; 
  
 try 
  
 { 
  
 googleAdsClient 
  
 = 
  
 GoogleAdsClient 
 . 
 newBuilder 
 (). 
 fromPropertiesFile 
 (). 
 build 
 (); 
  
 } 
  
 catch 
  
 ( 
 FileNotFoundException 
  
 fnfe 
 ) 
  
 { 
  
 System 
 . 
 err 
 . 
 printf 
 ( 
  
 "Failed to load GoogleAdsClient configuration from file. Exception: %s%n" 
 , 
  
 fnfe 
 ); 
  
 System 
 . 
 exit 
 ( 
 1 
 ); 
  
 } 
  
 catch 
  
 ( 
 IOException 
  
 ioe 
 ) 
  
 { 
  
 System 
 . 
 err 
 . 
 printf 
 ( 
 "Failed to create GoogleAdsClient. Exception: %s%n" 
 , 
  
 ioe 
 ); 
  
 System 
 . 
 exit 
 ( 
 1 
 ); 
  
 } 
  
 try 
  
 { 
  
 new 
  
 AddPerformanceMaxRetailCampaign 
 () 
  
 . 
 runExample 
 ( 
  
 googleAdsClient 
 , 
  
 params 
 . 
 customerId 
 , 
  
 params 
 . 
 merchantCenterAccountId 
 , 
  
 params 
 . 
 salesCountry 
 , 
  
 params 
 . 
 finalUrl 
 , 
  
 params 
 . 
 brandGuidelinesEnabled 
 ); 
  
 } 
  
 catch 
  
 ( 
 GoogleAdsException 
  
 gae 
 ) 
  
 { 
  
 // GoogleAdsException is the base class for most exceptions thrown by an API request. 
  
 // Instances of this exception have a message and a GoogleAdsFailure that contains a 
  
 // collection of GoogleAdsErrors that indicate the underlying causes of the 
  
 // GoogleAdsException. 
  
 System 
 . 
 err 
 . 
 printf 
 ( 
  
 "Request ID %s failed due to GoogleAdsException. Underlying errors:%n" 
 , 
  
 gae 
 . 
 getRequestId 
 ()); 
  
 int 
  
 i 
  
 = 
  
 0 
 ; 
  
 for 
  
 ( 
 GoogleAdsError 
  
 googleAdsError 
  
 : 
  
 gae 
 . 
 getGoogleAdsFailure 
 (). 
 getErrorsList 
 ()) 
  
 { 
  
 System 
 . 
 err 
 . 
 printf 
 ( 
 "  Error %d: %s%n" 
 , 
  
 i 
 ++ 
 , 
  
 googleAdsError 
 ); 
  
 } 
  
 System 
 . 
 exit 
 ( 
 1 
 ); 
  
 } 
  
 } 
  
 /** 
 * Runs the example. 
 * 
 * @param googleAdsClient the Google Ads API client. 
 * @param customerId the client customer ID. 
 * @param merchantCenterAccountId the Merchant Center account ID. 
 * @param salesCountry sales country of products to include in the campaign. 
 * @param finalUrl final URL for the asset group of the campaign. 
 * @param brandGuidelinesEnabled indicates if the campaign is enabled for brand guidelines. 
 */ 
  
 private 
  
 void 
  
 runExample 
 ( 
  
 GoogleAdsClient 
  
 googleAdsClient 
 , 
  
 long 
  
 customerId 
 , 
  
 long 
  
 merchantCenterAccountId 
 , 
  
 String 
  
 salesCountry 
 , 
  
 String 
  
 finalUrl 
 , 
  
 boolean 
  
 brandGuidelinesEnabled 
 ) 
  
 throws 
  
 IOException 
  
 { 
  
 // This campaign will override the customer conversion goals. For mor<e information see 
  
> // https://developers.google.com/google-ads/api/docs/conversions/goals/campaign-goals. 
  
 // Retrieve the current list of customer conversion goals. 
  
 ListCustomerConversionGoal 
  
 customerConversionGoals 
  
 = 
  
 getCustomerConversionGoals 
 ( 
 googleAdsClient 
 , 
  
 customerId 
 ); 
  
 // Performance Max campaigns require that repeated assets such as headlines 
  
 // and descriptions be created before the campaign. 
  
 // For the list <of req>uired assets for a Performance Max campaign, see 
  
 // https://developers.google.<com/go>ogle-ads/api/docs/performance-max/assets 
  
 // 
  
 // Creates the headlines. 
  
 ListString 
  
 headlines 
  
 = 
  
 ImmutableList 
 . 
 of 
 ( 
 "Travel" 
 , 
  
 &qu<ot;Tra>vel Reviews" 
 , 
  
 "Book travel" 
 ); 
  
 ListString 
  
 headlineAssetResource<Names 
  
> = 
  
 createMultipleTextAssets 
 ( 
 googleAdsClient 
 , 
  
 customerId 
 , 
  
 headlines 
 ); 
  
 // Creates the descriptions. 
  
 ListString 
  
 descriptions 
  
 = 
  
 ImmutableList 
 . 
 of 
 ( 
 "Take to the air!" 
 , 
  
 "Fly to the sky!" 
 ); 
  
 ListString 
  
 descriptionAssetResourceNames 
  
 = 
  
 createMultipleTextAssets 
 ( 
 googleAdsClient 
 , 
  
 customerId 
 , 
  
 descriptions 
 ); 
  
 // The below methods create and return MutateOperations that we later 
  
 // provide to the GoogleAdsService.Mutate method in order to create the 
  
 // entities in a single request. Since the entities for a Performance Max 
  
 // campaign are closely tied to one-another, it's considered a best pr<actice 
  
 // t>o create them in a single Mutate <>request, so they all complete 
  
 // successfully or fail entirely, leaving no orphaned entities. See: 
  
 // https://developers.google.com/google-ads/api/docs/mutating/overview 
  
 ListMutateOperation 
  
 mutateOperations 
  
 = 
  
 new 
  
 ArrayList 
 (); 
  
 mutateOperations 
 . 
 add 
 ( 
 createCampaignBudgetOperation 
 ( 
 customerId 
 )); 
  
 mutateOperations 
 . 
 add 
 ( 
  
 createPerformanceMaxCampaignOperation 
 ( 
  
 customerId 
 , 
  
 merchantCenterAccountId 
 , 
  
 salesCountry 
 , 
  
 brandGuidelinesEnabled 
 )); 
  
 mutateOperations 
 . 
 addAll 
 ( 
 createCampaignCriterionOperations 
 ( 
 customerId 
 )); 
  
 String 
  
 assetGroupResourceName 
  
 = 
  
 ResourceNames 
 . 
 assetGroup 
 ( 
 customerId 
 , 
  
 ASSET_GROUP_TEMPORARY_ID 
 ); 
  
 mutateOperations 
 . 
 add 
 ( 
 createAssetGroupOperation 
 ( 
 customerId 
 , 
  
 assetGroupResourceName 
 , 
  
 finalUrl 
 )); 
  
 // Retail Performance Max campaigns require listing groups, which are created via the 
  
 // AssetGroupListingGroupFilter resource. 
  
 mutateOperations 
 . 
 add 
 ( 
 createAssetGroupListingGroupFilterOperation 
 ( 
 assetGroupResourceName 
 )); 
  
 mutateOperations 
 . 
 addAll 
 ( 
  
 createAssetAndAssetGroupAssetOperations 
 ( 
  
 customerId 
 , 
  
 assetGroupResourceName 
 , 
  
 headlineAssetResourceNames 
 , 
  
 descriptionAssetResourceNames 
 , 
  
 brandGuidelinesEnabled 
 )); 
  
 mutateOperations 
 . 
 addAll 
 ( 
 createConversionGoalOperations 
 ( 
 customerId 
 , 
  
 customerConversionGoals 
 )); 
  
 try 
  
 ( 
 GoogleAdsServiceClient 
  
 googleAdsServiceClient 
  
 = 
  
 googleAdsClient 
 . 
 getLatestVersion 
 (). 
 createGoogleAdsServiceClient 
 ()) 
  
 { 
  
 MutateGoogleAdsResponse 
  
 response 
  
 = 
  
 googleAdsServiceClient 
 . 
 mutate 
 ( 
 Long 
 . 
 toString 
 ( 
 customerId 
 ), 
  
 mutateOperations 
 ); 
  
 printResponseDetails 
 ( 
 response 
 ); 
  
 } 
  
 } 
  
 /** Creates a MutateOperation that creates a new CampaignBudget. */ 
  
 private 
  
 MutateOperation 
  
 createCampaignBudgetOperation 
 ( 
 long 
  
 customerId 
 ) 
  
 { 
  
 CampaignBudget 
  
 campaignBudget 
  
 = 
  
 CampaignBudget 
 . 
 newBuilder 
 () 
  
 . 
 setName 
 ( 
 "Performance Max retail campaign budget #" 
  
 + 
  
 getPrintableDateTime 
 ()) 
  
 // The budget period already defaults to DAILY. 
  
 . 
 setAmountMicros 
 ( 
 50_000_000 
 ) 
  
 . 
 setDeliveryMethod 
 ( 
 BudgetDeliveryMethod 
 . 
 STANDARD 
 ) 
  
 // A Performance Max campaign cannot use a shared campaign budget. 
  
 . 
 setExplicitlyShared 
 ( 
 false 
 ) 
  
 // Set a temporary ID in the budget's resource name, so it can be referenced 
  
 // by the campaign in later steps. 
  
 . 
 setResourceName 
 ( 
 ResourceNames 
 . 
 campaignBudget 
 ( 
 customerId 
 , 
  
 BUDGET_TEMPORARY_ID 
 )) 
  
 . 
 build 
 (); 
  
 return 
  
 MutateOperation 
 . 
 newBuilder 
 () 
  
 . 
 setCampaignBudgetOperation 
 ( 
  
 CampaignBudgetOperation 
 . 
 newBuilder 
 (). 
 setCreate 
 ( 
 campaignBudget 
 ). 
 build 
 ()) 
  
 . 
 build 
 (); 
  
 } 
  
 /** Creates a MutateOperation that creates a new Performance Max campaign. */ 
  
 private 
  
 MutateOperation 
  
 createPerformanceMaxCampaignOperation 
 ( 
  
 long 
  
 customerId 
 , 
  
 long 
  
 merchantCenterAccountId 
 , 
  
 String 
  
 salesCountry 
 , 
  
 boolean 
  
 brandGuidelinesEnabled 
 ) 
  
 { 
  
 Campaign 
  
 performanceMaxCampaign 
  
 = 
  
 Campaign 
 . 
 newBuilder 
 () 
  
 . 
 setName 
 ( 
 "Performance Max retail campaign #" 
  
 + 
  
 getPrintableDateTime 
 ()) 
  
 // Sets the campaign status as PAUSED. The campaign is the only entity in 
  
 // the mutate request that should have its status set. 
  
 . 
 setStatus 
 ( 
 CampaignStatus 
 . 
 PAUSED 
 ) 
  
 // All Performance Max campaigns have an advertising_channel_type of 
  
 // PERFORMANCE_MAX. The advertising_channel_sub_type should not be set. 
  
 . 
 setAdvertisingChannelType 
 ( 
 AdvertisingChannelType 
 . 
 PERFORMANCE_MAX 
 ) 
  
 // Bidding strategy must be set directly on the campaign. 
  
 // Setting a portfolio bidding strategy by resource name is not supported. 
  
 // Max Conversion and Maximize Conversion Value are the only strategies 
  
 // supported for Performance Max campaigns. 
  
 // An optional ROAS (Return on Advertising Spend) can be set for 
  
 // maximize_conversion_value. The ROAS value must be specified as a ratio in 
  
 // the API. It is calculated by dividing "total value" by "total spend". 
  
 // For more information on Maximize Conversion Value, see the support 
  
 // article: http://support.google.com/google-ads/answer/7684216. 
  
 // A targetRoas of 3.5 corresponds to a 350% return on ad spend. 
  
 // For first time users, it's recommended not to set a target ROAS value. Although 
  
 // the target ROAS value is optional, you still need to define the enclosing 
  
 // maximize_conversion_value. 
  
 . 
 setMaximizeConversionValue 
 ( 
  
 MaximizeConversionValue 
 . 
 newBuilder 
 () 
  
 // .setTargetRoas(3.5) 
  
 . 
 build 
 ()) 
  
 // Below is what you would use if you want to maximize conversions: 
  
 // .setMaximizeConversions( 
  
 //     MaximizeConversions.newBuilder() 
  
 //         // The target CPA is optional. This is the average amount that you would like 
  
 //         // to spend per conversion action. 
  
 //         // .setTargetCpaMicros(1_000_000) 
  
 //         .build()) 
  
 // Sets the shopping settings. 
  
 . 
 setShoppingSetting 
 ( 
  
 ShoppingSetting 
 . 
 newBuilder 
 () 
  
 . 
 setMerchantId 
 ( 
 merchantCenterAccountId 
 ) 
  
 // Optional: To use products only from a specific feed, set FeedLabel to the 
  
 // feed label used in Merchant Center. See: 
  
 // https://support.google.com/merchants/answer/12453549. 
  
 // Removing the feedLabel field will use products from all feeds. 
  
 // .setFeedLabel("INSERT_FEED_LABEL_HERE") 
  
 . 
 build 
 ()) 
  
 // Sets the Final URL expansion opt out. This flag is specific to 
  
 // Performance Max campaigns. If opted out (true), only the final URLs in 
  
 // the asset group or URLs specified in the advertiser's Google Merchant 
  
 // Center or business data feeds are targeted. 
  
 // 
  
 // If opted in (false), the entire domain will be targeted. For best 
  
 // results, set this value to false to opt in and allow URL expansions. You 
  
 // can optionally add exclusions to limit traffic to parts of your website. 
  
 // 
  
 // Sets to true for this Retail campaign so the final URLs will be limited to those 
  
 // explicitly surfaced via Google Merchant Center. 
  
 . 
 setUrlExpansionOptOut 
 ( 
 true 
 ) 
  
 // Sets if the campaign is enabled for brand guidelines. For more information on brand 
  
 // guidelines, see https://support.google.com/google-ads/answer/14934472. 
  
 . 
 setBrandGuidelinesEnabled 
 ( 
 brandGuidelinesEnabled 
 ) 
  
 // Assigns the resource name with a temporary ID. 
  
 . 
 setResourceName 
 ( 
  
 ResourceNames 
 . 
 campaign 
 ( 
 customerId 
 , 
  
 PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 )) 
  
 // Sets the budget using the given budget resource name. 
  
 . 
 setCampaignBudget 
 ( 
 ResourceNames 
 . 
 campaignBudget 
 ( 
 customerId 
 , 
  
 BUDGET_TEMPORARY_ID 
 )) 
  
 // Declares whether this campaign serves political ads targeting the EU. 
  
 . 
 setContainsEuPoliticalAdvertising 
 ( 
 DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING 
 ) 
  
 // Optional fields. 
  
 . 
 setStartDate 
 ( 
 new 
  
 DateTime 
 (). 
 plusDays 
 ( 
 1 
 ). 
 toString 
 ( 
 "yyyyMMdd" 
 )) 
  
 . 
 setEndDate 
 ( 
 new 
  
 DateTime 
 (). 
 plusDays 
 ( 
 365 
 ). 
 toString 
 ( 
 &quo<t;yyyyMMdd">; 
 )) 
  
 . 
 build 
 (); 
  
 return 
  
 MutateOperation 
 . 
 newBuilder 
 () 
  
 . 
 setCampaignOperation 
 ( 
  
 CampaignOperation 
 . 
 newBuilder 
 (). 
 setCreate 
 ( 
 performanceMaxCampaign 
 ). 
 buil<d 
 ()) 
  
 . 
 bui>ld 
 (); 
  
 } 
  
 /** Creates a list <>of MutateOperations that create new campaign criteria. */ 
  
 private 
  
 ListMutateOperation 
  
 createCampaignCriterionOperations 
 ( 
 long 
  
 customerId 
 ) 
  
 { 
  
 String 
  
 campaignResourceName 
  
 = 
  
 ResourceNames 
 . 
 campaign 
 ( 
 customerId 
 , 
  
 PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 ); 
  
 ListCampaignCriterion 
  
 campaignCriteria 
  
 = 
  
 new 
  
 ArrayList 
 (); 
  
 // Sets the LOCATION campaign criteria. 
  
 // Targets all of New York City except Brooklyn. 
  
 // Location IDs are listed here: 
  
 // https://developers.google.com/google-ads/api/reference/data/geotargets 
  
 // and they can also be retrieved using the GeoTargetConstantService as shown 
  
 // here: https://developers.google.com/google-ads/api/docs/targeting/location-targeting 
  
 campaignCriteria 
 . 
 add 
 ( 
  
 CampaignCriterion 
 . 
 newBuilder 
 () 
  
 . 
 setCampaign 
 ( 
 campaignResourceName 
 ) 
  
 // Adds one positive location target for New York City (ID=1023191), specifically adding 
  
 // the positive criteria before the negative one. 
  
 . 
 setLocation 
 ( 
  
 LocationInfo 
 . 
 newBuilder 
 () 
  
 . 
 setGeoTargetConstant 
 ( 
 ResourceNames 
 . 
 geoTargetConstant 
 ( 
 1023191 
 )) 
  
 . 
 build 
 ()) 
  
 . 
 setNegative 
 ( 
 false 
 ) 
  
 . 
 build 
 ()); 
  
 // Next adds the negative target for Brooklyn (ID=1022762). 
  
 campaignCriteria 
 . 
 add 
 ( 
  
 CampaignCriterion 
 . 
 newBuilder 
 () 
  
 . 
 setCampaign 
 ( 
 campaignResourceName 
 ) 
  
 . 
 setLocation 
 ( 
  
 LocationInfo 
 . 
 newBuilder 
 () 
  
 . 
 setGeoTargetConstant 
 ( 
 ResourceNames 
 . 
 geoTargetConstant 
 ( 
 1022762 
 )) 
  
 . 
 build 
 ()) 
  
 . 
 setNegative 
 ( 
 true 
 ) 
  
 . 
 build 
 ()); 
  
 // Sets the LANGUAGE campaign criterion. 
  
 campaignCriteria 
 . 
 add 
 ( 
  
 CampaignCriterion 
 . 
 newBuilder 
 () 
  
 . 
 setCampaign 
 ( 
 campaignResourceName 
 ) 
  
 // Sets the language. 
  
 // For a list of all language codes, see: 
  
 // https://developers.google.com/google-ads/api/reference/data/codes-formats#expandable-7 
  
 . 
 setLanguage 
 ( 
  
 Lang>uageInfo 
 . 
 newBuilder 
 () 
  
 . 
 setLanguageConstant 
 ( 
 ResourceNames 
 . 
 languageConstant 
 ( 
 1000 
 )) 
  
 // English 
  
 . 
 build 
 ()) 
  
 . 
 build 
 ()); 
  
 // Returns a list of mutate operations with one operation per criterion. 
  
 return 
  
 campaignCriteria 
 . 
 stream 
 () 
  
 . 
 map 
 ( 
  
 criterion 
  
 - 
  
 MutateOperation 
 . 
 newBuild<e>r 
 () 
  
 . 
 setCampaignCriterionOperation 
 ( 
  
 CampaignCriterionOperation 
 . 
 newBu<ilder 
 (>). 
 setCreate 
 ( 
 criterion 
 ). 
 build 
 ()) 
  
 . 
 build 
 ()) 
  
 . 
 collect 
 ( 
 Collecto<rs 
 . 
 toL>ist 
 ()); 
  
 } 
  
 /*<* 
 * Creates >multiple text assets and returns <>the list of resource names. 
 * 
 * pThese repeated assets must be created in a separate request prior to creating the campaign. 
 */ 
  
 private 
  
 ListString 
  
 createMultipleTextAssets 
 ( 
  
 GoogleAdsClient 
  
 googleAdsClient 
 , 
  
 long 
  
 customerId 
 , 
  
 ListString 
  
 texts 
 ) 
  
 { 
  
 ListMutateOperation 
  
 mutateOperations 
  
 = 
  
 new 
  
 ArrayList 
 (); 
  
 for 
  
 ( 
 String 
  
 text 
  
 : 
<  
 texts 
> ) 
  
 { 
  
 Asset 
  
 asset 
  
 = 
  
 Asset 
 . 
 newBu<>ilder 
 (). 
 setTextAsset 
 ( 
 TextAsset 
 . 
 newBuilder 
 (). 
 setText 
 ( 
 text 
 )). 
 build 
 (); 
  
 AssetOperation 
  
 assetOperation 
  
 = 
  
 AssetOperation 
 . 
 newBuilder 
 (). 
 setCreate 
 ( 
 asset 
 ). 
 build 
 (); 
  
 mutateOperations 
 . 
 add 
 ( 
 MutateOperation 
 . 
 newBuilder 
 (). 
 setAssetOperation 
 ( 
 assetOperation 
 ). 
 build 
 ()); 
  
 } 
  
 ListString 
  
 assetResourceNames 
  
 = 
  
 new 
  
 ArrayList 
 (); 
  
 // Creates the service client. 
  
 try 
  
 ( 
 GoogleAdsServiceClient 
  
 googleAdsServiceClient 
  
 = 
  
 googleAdsClient 
 . 
 getLatestVersion 
 (). 
 createGoogleAdsServiceClient 
 ()) 
  
 { 
  
 // Sends the operations in a single Mutate request. 
  
 MutateGoogleAdsResponse 
  
 response 
  
 = 
  
 googleAdsServiceClient 
 . 
 mutate 
 ( 
 Long 
 . 
 toString 
 ( 
 customerId 
 ), 
  
 mutateOperations 
 ); 
  
 for 
  
 ( 
 MutateOperationResponse 
  
 result 
  
 : 
  
 response 
 . 
 getMutateOperationResponsesList 
 ()) 
  
 { 
  
 if 
  
 ( 
 result 
 . 
 hasAssetResult 
 ()) 
  
 { 
  
 assetResourceNames 
 . 
 add 
 ( 
 result 
 . 
 getAssetResult 
 (). 
 ge<tResourceName 
 ()>); 
  
 } 
  
 } 
  
 printR<>esponseDetails 
 ( 
 response 
 ); 
  
 } 
  
 return 
  
 assetResourceNames 
 ; 
  
 } 
  
 /** Creates a MutateOperation that create a new AssetGroup. */ 
  
 private 
  
 MutateOperation 
  
 createAssetGroupOperation 
 ( 
  
 long 
  
 customerId 
 , 
  
 String 
  
 assetGroupResourceName 
 , 
  
 String 
  
 finalUrl 
 ) 
  
 { 
  
 ListMutateOperation 
  
 mutateOperations 
  
 = 
  
 new 
  
 ArrayList 
 (); 
  
 String 
  
 campaignResourceName 
  
 = 
  
 ResourceNames 
 . 
 campaign 
 ( 
 customerId 
 , 
  
 PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 ); 
  
 // Creates the AssetGroup. 
  
 AssetGroup 
  
 assetGroup 
  
 = 
  
 AssetGroup 
 . 
 newBuilder 
 () 
  
 . 
 setName 
 ( 
 "Performance Max retail asset group #" 
  
 + 
  
 getPrintableDateTime 
 ()) 
  
 . 
 setCampaign 
 ( 
 campaignResourceName 
 ) 
  
 . 
 addFinalUrls 
 ( 
 finalUrl 
 ) 
  
 . 
 addFinalMobileUrls 
 ( 
 finalUrl 
 ) 
  
 . 
 setStatus 
 ( 
 AssetGroupStatus 
 . 
 PAUSED 
 ) 
  
 . 
 setResourceName 
 ( 
 assetGroupResourceName 
 ) 
 < 
 . 
 bui>ld 
 (); 
  
 AssetGroupOperation 
  
 assetGroupOperation 
  
 = 
  
 AssetGroupOperation 
 . 
 newBuilder 
 (). 
 setCreate 
 ( 
 assetGrou<p 
 ). 
 bui>ld 
 (); 
  
 return 
  
 MutateOperation 
 . 
 newBui<lder 
 ()>. 
 setAssetGroupOperation 
 ( 
 assetGroupOperation 
 ). 
 build 
 (); 
  
 } 
  
 /** Creates a list of MutateOperations that< create a new A>ssetGroup. */ 
  
 private 
  
 ListMutat<>eOperation 
  
 createAssetAndAssetGroupAssetOperations 
 ( 
  
 long 
  
 customerId 
 , 
  
 String 
  
 assetGroupResourceName 
 , 
  
 ListString 
  
 headlineAssetResourceNames 
 , 
  
 ListString 
  
 descriptionAssetResourceNames 
 , 
  
 boolean 
  
 brandGuidelinesEnabled 
 ) 
  
 throws 
  
 IOException 
  
 { 
  
 ListMutateOperation 
  
 mutateOperations 
  
 = 
  
 new 
  
 ArrayList 
 (); 
  
 // For the list of required assets for a Performance Max campaign, see 
  
 // https://developers.google.com/google-ads/api/docs/performance-max/assets 
  
 // An AssetGroup is linked to an Asset by creating a new AssetGroupAsset 
  
 // and providing: 
  
 //   the resource name of the AssetGroup 
  
 //   the resource name of the Asset 
  
 //   the field_type of the Asset in this AssetGroup. 
  
 // To learn more about AssetGroups, see 
  
 // https://developers.google.com/google-ads/api/docs/performance-max/asset-groups 
  
 // Links the previously created multiple text assets. 
  
 // Links the headline assets. 
  
 for 
  
 ( 
 String 
  
 resourceName 
  
 : 
  
 headlineAssetResourceNames 
 ) 
  
 { 
  
 mutateOperations 
 . 
 add 
 ( 
  
 createAssetGroupAssetMutateOperation 
 ( 
  
 AssetFieldType 
 . 
 HEADLINE 
 , 
  
 resourceName 
 , 
  
 assetGroupResourceName 
 )); 
  
 } 
  
 // Links the description assets. 
  
 for 
  
 ( 
 String 
  
 resourceName 
  
 : 
  
 descriptionAssetResourceNames 
 ) 
  
 { 
  
 mutateOperations 
 . 
 add 
 ( 
  
 createAssetGroupAssetMutateOperation 
 ( 
  
 AssetFieldType 
 . 
 DESCRIPTION 
 , 
  
 resourceName 
 , 
  
 assetGroupResourceName 
 )); 
  
 } 
  
 // Creates and links the long headline text asset. 
  
 mutateOperations 
 . 
 addAll 
 ( 
  
 createAndLinkTextAsset 
 ( 
  
 customerId 
 , 
  
 assetGroupResourceName 
 , 
  
 "Travel the World" 
 , 
  
 AssetFieldType 
 . 
 LONG_HEADLINE 
 )); 
  
 // Creates and links the business name and logo assets. 
  
 mutateOperations 
 . 
 addAll 
 ( 
  
 createAndLinkBrandAssets 
 ( 
  
 customerId 
 , 
  
 brandGuidelinesEnabled 
 , 
  
 "Interplanetary Cruises" 
 , 
  
 "https://gaagl.page.link/1Crm" 
 , 
  
 "Logo Image" 
 )); 
  
 // Creates and links the image assets. 
  
 // Creates and links the Marketing Image Asset. 
  
 mutateOperations 
 . 
 addAll 
 ( 
  
 createAndLinkImageAsset 
 ( 
  
 customerId 
 , 
  
 assetGroupResourceName 
 , 
  
 "https://gaagl.page.link/Eit5" 
 , 
  
 AssetFieldType 
 . 
 MARKETING_IMAGE 
 , 
  
 "Marketing Image" 
 )); 
  
 // Creates and links the Square Marketing Image Asset. 
  
 mutateOperat<ions 
 . 
 addAll 
 ( 
 > 
 createAndLinkImageAsset 
 ( 
  
 customerId 
 , 
  
 assetGroupResourceName 
 , 
  
 "https://gaagl.page.link/<bjYi" 
 , 
 > 
 AssetFieldType 
 . 
 SQUARE_MA<>RKETING_IMAGE 
 , 
  
 "Square Marketing Image" 
 )); 
  
 return 
  
 sortMutateOperations 
 ( 
 mutateOperations 
 ); 
  
 } 
  
 /** Creates a list of MutateOperations that create a new linked text asset. */ 
  
 ListMutateOperation 
  
 createAndLinkTextAsset 
 ( 
  
 long 
  
 customerId 
 , 
  
 String 
  
 assetGroupResourceName 
 , 
  
 String 
  
 text 
 , 
  
 AssetFieldType 
  
 assetFieldType 
 ) 
  
 { 
  
 ListMutateOperation 
  
 mutateOperations 
  
 = 
  
 new 
  
 ArrayList 
 (); 
  
 String 
  
 assetResourceName 
  
 = 
  
 ResourceNames 
 . 
 asset 
 ( 
 customerId 
 , 
  
 getNextTemporaryId 
 ()); 
  
 // Creates the Text Asset. 
  
 Asset 
  
 asset 
  
 = 
  
 Asset 
 . 
 newBuilder 
 () 
  
 . 
 setResourceName 
 ( 
 assetResourceName 
 ) 
  
 . 
 setTextAsset 
 ( 
 TextAsset 
 . 
 newBuilder 
 (). 
 setText 
 ( 
 text 
 ). 
 build 
 ()) 
  
 . 
 build 
 (); 
  
 AssetOperation 
  
 assetOperation 
  
 = 
  
 AssetOperation 
 . 
 newBuilder 
 (). 
 setCreate 
 ( 
 asset 
 ). 
 build 
 (); 
  
 mutateOperations 
 . 
 add 
 ( 
 MutateOp<eration 
 . 
 newBuil>der 
 (). 
 setAssetOperation 
 ( 
 assetOperation 
 ). 
 build 
 ()); 
  
 // Creates an AssetGroupAsset to link the Asset to the AssetGroup. 
  
 mutateOperations 
 . 
 add 
 ( 
  
 createAssetGroupAssetMutateOperation 
 ( 
 < 
 assetFiel>dType 
 , 
  
 assetResourceName 
 , 
  
 assetGr<>oupResourceName 
 )); 
  
 return 
  
 mutateOperations 
 ; 
  
 } 
  
 /** Creates a list of MutateOperations that create a new linked image asset. */ 
  
 ListMutateOperation 
  
 createAndLinkImageAsset 
 ( 
  
 long 
  
 customerId 
 , 
  
 String 
  
 assetGroupResourceName 
 , 
  
 String 
  
 url 
 , 
  
 AssetFieldType 
  
 assetFieldType 
 , 
  
 String 
  
 assetName 
 ) 
  
 throws 
  
 IOException 
  
 { 
  
 ListMutateOperation 
  
 mutateOperations 
  
 = 
  
 new 
  
 ArrayList 
 (); 
  
 String 
  
 assetResourceName 
  
 = 
  
 ResourceNames 
 . 
 asset 
 ( 
 customerId 
 , 
  
 getNextTemporaryId 
 ()); 
  
 // Creates a media file. 
  
 byte 
 [] 
  
 assetBytes 
  
 = 
  
 ByteStreams 
 . 
 toByteArray 
 ( 
 new 
  
 URL 
 ( 
 url 
 ). 
 openStream 
 ()); 
  
 // Creates the Image Asset. 
  
 Asset 
  
 asset 
  
 = 
  
 Asset 
 . 
 newBuilder 
 () 
  
 . 
 setResourceName 
 ( 
 assetResourceName 
 ) 
  
 . 
 setImageAsset 
 ( 
 ImageAsset 
 . 
 newBuilder 
 (). 
 setData 
 ( 
 ByteString 
 . 
 copyFrom 
 ( 
 assetBytes 
 )). 
 build 
 ()) 
  
 // Provides a unique friendly name to identify your asset. When there is an existing 
  
 // image asset with the same content but a different name, the new name will be dropped 
  
 // silently. 
  
 . 
 setName 
 ( 
 assetName 
 ) 
  
 . 
 build 
 (); 
  
 AssetOperation 
  
 assetOperation 
  
 = 
  
 AssetOperation 
 . 
 newBuilder 
 (). 
 setCreate 
 ( 
 asset 
 ). 
 build 
 (); 
  
 mutateOperations 
 . 
 add 
 ( 
 Mu<tateOperation 
 . 
 n>ewBuilder 
 (). 
 setAssetOperation 
 ( 
 assetOperation 
 ). 
 build 
 ()); 
  
 // Creates an AssetGroupAsset to link the Asset to the AssetGroup. 
  
 mutateOperations 
 . 
 add 
 ( 
  
 createAssetGroupAssetMutateOperat<ion 
 ( 
 > 
 assetFieldType 
 , 
  
 assetResourceNa<>me 
 , 
  
 assetGroupResourceName 
 )); 
  
 return 
  
 mutateOperations 
 ; 
  
 } 
  
 /** Creates a list of MutateOperations that create linked brand assets. */ 
  
 ListMutateOperation 
  
 createAndLinkBrandAssets 
 ( 
  
 long 
  
 customerId 
 , 
  
 boolean 
  
 brandGuidelinesEnabled 
 , 
  
 String 
  
 businessName 
 , 
  
 String 
  
 logoUrl 
 , 
  
 String 
  
 logoName 
 ) 
  
 throws 
  
 IOException 
  
 { 
  
 ListMutateOperation 
  
 mutateOperations 
  
 = 
  
 new 
  
 ArrayList 
 (); 
  
 // Creates the brand name text asset. 
  
 String 
  
 businessNameAssetResourceName 
  
 = 
  
 ResourceNames 
 . 
 asset 
 ( 
 customerId 
 , 
  
 getNextTemporaryId 
 ()); 
  
 Asset 
  
 businessNameAsset 
  
 = 
  
 Asset 
 . 
 newBuilder 
 () 
  
 . 
 setResourceName 
 ( 
 businessNameAssetResourceName 
 ) 
  
 . 
 setTextAsset 
 ( 
 TextAsset 
 . 
 newBuilder 
 (). 
 setText 
 ( 
 businessName 
 ). 
 build 
 ()) 
  
 . 
 build 
 (); 
  
 AssetOperation 
  
 businessNameAssetOperation 
  
 = 
  
 AssetOperation 
 . 
 newBuilder 
 (). 
 setCreate 
 ( 
 businessNameAsset 
 ). 
 build 
 (); 
  
 mutateOperations 
 . 
 add 
 ( 
  
 MutateOperation 
 . 
 newBuilder 
 (). 
 setAssetOperation 
 ( 
 businessNameAssetOperation 
 ). 
 build 
 ()); 
  
 // Creates the logo image asset. 
  
 String 
  
 logoAssetResourceName 
  
 = 
  
 ResourceNames 
 . 
 asset 
 ( 
 customerId 
 , 
  
 getNextTemporaryId 
 ()); 
  
 // Creates a media file. 
  
 byte 
 [] 
  
 logoBytes 
  
 = 
  
 ByteStreams 
 . 
 toByteArray 
 ( 
 new 
  
 URL 
 ( 
 logoUrl 
 ). 
 openStream 
 ()); 
  
 Asset 
  
 logoAsset 
  
 = 
  
 Asset 
 . 
 newBuilder 
 () 
  
 . 
 setResourceName 
 ( 
 logoAssetResourceName 
 ) 
  
 . 
 setImageAsset 
 ( 
 ImageAsset 
 . 
 newBuilder 
 (). 
 setData 
 ( 
 ByteString 
 . 
 copyFrom 
 ( 
 logoBytes 
 )). 
 build 
 ()) 
  
 // Provides a unique friendly name to identify your asset. When there is an existing 
  
 // image asset with the same content but a different name, the new name will be dropped 
  
 // silently. 
  
 . 
 setName 
 ( 
 logoName 
 ) 
  
 . 
 build 
 (); 
  
 AssetOperation 
  
 logoImageAssetOperation 
  
 = 
  
 AssetOperation 
 . 
 newBuilder 
 (). 
 setCreate 
 ( 
 logoAsset 
 ). 
 build 
 (); 
  
 mutateOperations 
 . 
 add 
 ( 
  
 MutateOperation 
 . 
 newBuilder 
 (). 
 setAssetOperation 
 ( 
 logoImageAssetOperation 
 ). 
 build 
 ()); 
  
 if 
  
 ( 
 brandGuidelinesEnabled 
 ) 
  
 { 
  
 // Creates CampaignAsset resources to link the Asset resources to the Campaign. 
  
 mutateOperations 
 . 
 add 
 ( 
  
 createCampaignAssetMutateOperation 
 ( 
  
 customerId 
 , 
  
 AssetFieldType 
 . 
 BUSINESS_NAME 
 , 
  
 businessNameAssetResourceName 
 )); 
  
 mutateOperations 
 . 
 add 
 ( 
  
 createCampaignAssetMutateOperation 
 ( 
  
 customerId 
 , 
  
 AssetFieldType 
 . 
 LOGO 
 , 
  
 logoAssetResourceName 
 )); 
  
 } 
  
 else 
  
 { 
  
 // Creates an AssetGroupAsset to link the Asset to the AssetGroup. 
  
 mutateOperations 
 . 
 add 
 ( 
  
 createAssetGroupAssetMutateOperation 
 ( 
  
 AssetFieldType 
 . 
 BUSINESS_NAME 
 , 
  
 businessNameAssetResourceName 
 , 
  
 ResourceNames 
 . 
 assetGroup 
 ( 
 customerId 
 , 
  
 ASSET_GROUP_TEMPORARY_ID 
 ))); 
  
 mutateOperations 
 . 
 add 
 ( 
  
 createAssetGroupAssetMutateOperation 
 ( 
  
 AssetFieldType 
 . 
 LOGO 
 , 
  
 logoAssetResourceName 
 , 
  
 ResourceNames 
 . 
 assetGroup 
 ( 
 customerId 
 , 
  
 ASSET_GROUP_TEMPORARY_ID 
 ))); 
  
 } 
  
 return 
  
 mutateOperations 
 ; 
  
 } 
  
 /** Creates a MutateOperation to add an AssetGroupAsset. */ 
  
 MutateOperation 
  
 createAssetGroupAssetMutateOperation 
 ( 
  
 AssetFieldType 
  
 fieldType 
 , 
  
 String 
  
 assetResourceName 
 , 
  
 String 
  
 assetGroupResourceName 
 ) 
  
 { 
  
 AssetGroupAsset 
  
 assetGroupAsset 
  
 = 
  
 AssetGroupAsset 
 . 
 newBuilder 
 () 
  
 . 
 setFieldType 
 ( 
 fieldType 
 ) 
  
 . 
 setAssetGroup 
 ( 
 assetGroupResourceName 
 ) 
  
 . 
 setAsset 
 ( 
 assetResourceName 
 ) 
  
 . 
 build 
 (); 
  
 AssetGroupAssetOperation 
  
 assetGroupAssetOperation 
  
 = 
  
 AssetGroupAssetOperation 
 . 
 newBuilder 
 (). 
 setCreate 
 ( 
 assetGroupAsset 
 ). 
 build 
 (); 
  
 return 
  
 MutateOperation 
 . 
 newBuilder 
 () 
  
 . 
 setAssetGroupAssetOperation 
 ( 
 assetGroupAssetOperation 
 ) 
  
 . 
 build 
 (); 
  
 } 
  
 /** Creates a MutateOperation to add a CampaignAsset. */ 
  
 MutateOperation 
  
 createCampaignAssetMutateOperation 
 ( 
  
 long 
  
 customerId 
 , 
  
 AssetFieldType 
  
 fieldType 
 , 
  
 String 
  
 assetResourceName 
 ) 
  
 { 
  
 CampaignAsset 
  
 campaignAsset 
  
 = 
  
 CampaignAsset 
 . 
 newBuilder 
 () 
  
 . 
 setFieldType 
 ( 
 fieldType 
 ) 
  
 . 
 setCampaign 
 ( 
 ResourceNames 
 . 
 campaign 
 ( 
< c>ustomerId 
 , 
  
 PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 )) 
  
 . 
 setAsset 
 ( 
 assetResourceName 
 ) 
  
 . 
 build 
 (); 
  
 CampaignAssetOperation 
  
 campaignAssetOperation 
  
 = 
  
 CampaignAssetOperation 
 . 
 newBuilder 
 (). 
 setCreate 
 ( 
 campaignAsset 
< ). 
 build 
 (); 
  
> return 
  
 MutateOperation 
 . 
 new<Builder 
 (). 
 setCa>mpaignAssetOperation 
 ( 
 ca<mpaignAssetOper>ation 
 ). 
 build 
 (); 
  
 } 
  
 /** 
 * <>Sorts a list of mutate operations. 
 * 
 * pThis sorts the list such >that all asset operations precede all asset group asset and 
 * campaign asset operations. If asset group assets are created before as>sets then an error will 
 * be returned by the API. 
 */ 
  
 private 
  
 ListMutateOperation 
  
 sortMutateOperations 
 ( 
 ListMutateOperation 
  
 operations 
 ) 
  
 { 
  
 ListMutate>Operation 
  
 sortedOperations 
  
 = 
  
 new 
  
 ArrayList 
 (); 
  
 sortedOperations 
 . 
 addAll 
 ( 
  
 operations 
 . 
 stream 
 (). 
 filter 
 ( 
 o 
  
 - 
  
 o 
 . 
 hasAssetOperation 
 ()). 
 collect 
 ( 
 Collectors 
 . 
 toList 
 ())); 
  
 sortedOperations 
 . 
 a<ddAll 
 ( 
  
 operati>ons 
 . 
 stream 
 () 
  
 . 
 filter 
 ( 
 o 
  
 - 
  
 o 
 . 
 hasAssetGroupAssetOperation 
 ()) 
  
 . 
 collect 
 ( 
 Collectors 
 . 
 toList 
 ())); 
  
 sortedOperations 
 . 
 addAll 
 ( 
  
 operations 
 . 
 stream 
 () 
  
 . 
 filter 
 ( 
 o 
  
 - 
  
 o 
 . 
 hasCampaignAssetOperation 
 ()) 
  
 . 
 collect 
 ( 
< Collectors 
 . 
 toList 
 ())); 
>  
 return 
  
 sortedOperations 
 ; 
  
 } 
  
 /*<>* Retrieves the list of customer conversion goals. */ 
  
 private 
  
 static 
  
 ListCustomerConversionGoal 
  
 getCustomerConversionGoals 
 ( 
  
 GoogleAdsClient 
  
 googleAdsClient 
 , 
  
 long 
  
 customerId 
 ) 
  
 { 
  
 String 
  
 query 
  
 = 
  
 "SELECT customer_conversion_goal.category, customer_conversion_goal.origin " 
  
 + 
  
 "FROM customer_conversion_goal" 
 ; 
  
 ListCustomerConversionGoal 
  
 customerConversionGoals 
  
 = 
  
 new 
  
 ArrayList 
 (); 
  
 try 
  
 ( 
 GoogleAdsServiceClient 
  
 googleAdsServiceClient 
  
 = 
  
 googleAdsClient 
 . 
 getLatestVersion 
 (). 
 createGoogleAdsServiceClient 
 ()) 
  
 { 
  
 // The number of conversion goals is typically less than 50, so we use 
  
 // GoogleAdsService.search instead of search<_stream. 
  
> SearchPagedResponse 
  
 response 
  
 = 
  
 googleAdsServiceCli<ent 
 . 
 search 
 ( 
 Long 
 . 
 toStri>ng 
 ( 
 customerId 
 ), 
  
 query 
 ); 
  
 for 
  
 ( 
 G<oogleAdsRow 
  
 goo>gleAdsRow 
  
 : 
  
 response 
 . 
 iterateAll 
 ()<>) 
  
 { 
  
 customerConversionGoals 
 . 
 add 
 ( 
 googleAdsRow 
 . 
 getCustomerConversionGoal 
 ()); 
  
 } 
  
 } 
  
 return 
  
 customerConversionGoals 
 ; 
  
 } 
  
 /** Creates a list of MutateOperations that override customer conversion goals. */ 
  
 private 
  
 static 
  
 ListMutateOperation 
  
 createConversionGoalOperations 
 ( 
  
 long 
  
 customerId 
 , 
  
 ListCustomerConversionGoal 
  
 customerConversionGoals 
 ) 
  
 { 
  
 ListMutateOperation 
  
 mutateOperations 
  
 = 
  
 new 
  
 ArrayList 
 (); 
  
 // To override the customer conversion goals, we will change the 
  
 // biddability of each of the customer conversion goals so that only 
  
 // the desired conversion goal is biddable in this campaign. 
  
 for 
  
 ( 
 CustomerConversionGoal 
  
 customerConversionGoal 
  
 : 
  
 customerConversionGoals 
 ) 
  
 { 
  
 ConversionActionCategory 
  
 category 
  
 = 
  
 customerConversionGoal 
 . 
 getCategory 
 (); 
  
 ConversionOrigin 
  
 origin 
  
 = 
  
 customerConversionGoal 
 . 
 getOrigin 
 (); 
  
 String 
  
 campaignConversionGoalResourceName 
  
 = 
  
 ResourceNames 
 . 
 campaignConversionGoal 
 ( 
  
 customerId 
 , 
  
 PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 , 
  
 category 
 , 
  
 origin 
 ); 
  
 CampaignConversionGoal 
 . 
 Builder 
  
 campaignConversionGoalBuilder 
  
 = 
  
 CampaignConversionGoal 
 . 
 newBuilder 
 (). 
 setResourceName 
 ( 
 campaignConversionGoalResourceName 
 ); 
  
 // Change the biddability for the campaign conversion goal. 
  
 // S&&et biddability to True for the desired (category, origin). 
  
 // Set biddability to False for all other conversion goals. 
  
 // Note: 
  
 //  1- It is assumed that this Conversion Action 
  
 //     (category=PURCHASE, origin=WEBSITE) exists in this account. 
  
 //  2- More than one goal can be biddable if desired. This example 
  
 //     shows only one. 
  
 if 
  
 ( 
 category 
  
 == 
  
 ConversionActionCategory 
 . 
 PURCHASE 
  
 origin 
  
 == 
  
 ConversionOrigin 
 . 
 WEBSITE 
 ) 
  
 { 
  
 campaignConversionGoalBuilder 
 . 
 setBiddable 
 ( 
 true 
 ); 
  
 } 
  
 else 
  
 { 
  
 campaignConversionGoalBuilder 
 . 
 setBiddable 
 ( 
 false 
 ); 
  
 } 
  
 CampaignConversionGoal 
  
 campaignConversionGoal 
  
 = 
  
 campaignConversionGoalBuilder 
 . 
 build 
 (); 
  
 CampaignConversionGoalOperation 
  
 campaignConversionGoalOperation 
  
 = 
  
 CampaignConversionGoalOperation 
 . 
 newBuilder 
 () 
  
 . 
 setUpdate 
 ( 
 campaignConversionGoal 
 ) 
  
 . 
 setUpdateMask 
 ( 
 FieldMasks 
 . 
 allSetFieldsOf 
 ( 
 campaignConversionGoal 
 )) 
  
 . 
 build 
 (); 
  
 mutateOperations 
 . 
 add 
 ( 
  
 MutateOperation 
 . 
 newBuilder 
 () 
  
 . 
 setCampaignConversionGoalOperation 
 ( 
 campaignConversionGoalOperation 
 ) 
  
 . 
 build 
 ()); 
  
 } 
  
 return 
  
 mutateOperations 
 ; 
  
 } 
  
 /** Creates a MutateOperation that creates a new asset group listing group filter. */ 
  
 private 
  
 MutateOperation 
  
 createAssetGroupListingGroupFilterOperation 
 ( 
  
 String 
  
 assetGroupResourceName 
 ) 
  
 { 
  
 // Creates a new asset group listing group filter containing the "defa<ult" listing group (Al>l 
  
 // products). 
  
 AssetGroupListingGroupFilter 
  
 listingGroupFilter 
  
 = 
  
 AssetGroupListingGroupFilter 
 . 
 newBuilder 
 () 
  
 . 
 setAssetGroup 
 ( 
 assetGroupResourceName 
 ) 
  
 // Does not set the parentListingGroupFilter since this is the root node. For all other 
  
 // nodes, this would refer to the parent listing group filter resource name. 
  
 // .setParentListingGroupFilter("PARENT FILTER RESOURCE NAME") 
  
 // Sets the type to UNIT_INCLUDED since this node has no children. 
  
 . 
 setType 
 ( 
 ListingGroupFilterType 
 . 
 UNIT_INCLUDED 
 ) 
  
 // Specifies that this uses the SHOPPING listing source, as required for a Performance 
  
 // Max retail campaign. 
 < > 
 . 
 setListingSource 
 ( 
 ListingGroupFilterListingSource 
 . 
 SHOPPING 
 ) 
  
 . 
 build 
 (); 
  
 // Returns an operation to the list to create the listing group filter. 
  
 return 
  
 MutateOperation 
 . 
 newBuilder 
 () 
  
 . 
 setAssetGroupListingGroupFilterOperation 
 ( 
  
 AssetGroupListingGroupFilterOperation 
 . 
 newBuilder 
 (). 
 setCreate 
 ( 
 listingGroupFilter 
 )) 
  
 . 
 build 
 (); 
  
 } 
  
 /** 
 * Prints the details of a MutateGoogleAdsRespons<e. 
 * 
 * pParses th>e "response" oneof field name and uses it to extract the new entity's name and 
 * resource name. 
 */ 
  
 private 
  
 void 
  
 printResponseDetails 
 ( 
 MutateGoogleAdsResponse 
  
 response 
 ) 
  
 { 
  
 // Parses the Mutate response to print details about the entities that were created by the 
  
 // request. 
  
 String 
  
 suffix 
  
 = 
  
 "_result" 
 ; 
  
 for 
  
 ( 
 MutateOperationResponse 
  
 result 
  
 : 
  
 response 
 . 
 getMutateOperationResponsesList 
 ()) 
  
 { 
  
 for 
  
 ( 
 EntryFieldDescriptor 
 , 
  
 Object 
  
 responseFields 
  
 : 
  
 result 
 . 
 getAllFields 
 (). 
 entrySet 
 ()) 
  
 { 
  
 String 
  
 fieldName 
  
;  
 String 
  
 value 
  
 = 
  
 responseFields 
 . 
 getValue 
 (). 
 toString 
 (). 
 trim 
 (); 
  
 if 
  
 ( 
 fieldName 
 . 
 endsWith 
 ( 
 suffix 
 )) 
  
 { 
  
 fieldName 
  
 = 
  
 fieldName 
 . 
 substring 
 ( 
 0 
 , 
  
 fieldName 
 . 
 length 
 () 
  
 - 
  
 suffix 
 . 
 length 
 ()); 
  
 } 
  
 System 
 . 
 out 
 . 
 printf 
 ( 
 "Created a(n) %s with %s.%n" 
 , 
  
 fieldName 
 , 
  
 value 
 ); 
  
 } 
  
 } 
  
 } 
  
 /** Returns the next temporary ID and decreases it by one. */ 
  
 private 
  
 long 
  
 getNextTemporaryId 
 () 
  
 { 
  
 return 
  
 temporaryId 
 -- 
 ; 
  
 } 
 } 
 AddPerformanceMaxRetailCampaign 
 . 
 java 
  

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.Config 
 ; 
 using 
  
 Google.Ads.GoogleAds.Lib 
 ; 
 using 
  
 Google.Ads.GoogleAds.V21.Common 
 ; 
 using 
  
 Google.Ads.GoogleAds.V21.Errors 
 ; 
 using 
  
 Google.Ads.GoogleAds.V21.Resources 
 ; 
 using 
  
 Google.Ads.GoogleAds.V21.Services 
 ; 
 using 
  
 Google.Api.Gax 
 ; 
 using 
  
 Google.Protobuf 
 ; 
 using 
  
 System 
 ; 
 using 
  
 System.Collections.Generic 
 ; 
 using 
  
 System.Threading 
 ; 
 using 
  
 static 
  
 Google 
 . 
 Ads 
 . 
 GoogleAds 
 . 
 V21 
 . 
 Enums 
 . 
 AdvertisingChannelTypeEnum 
 . 
 Types 
 ; 
 using 
  
 static 
  
 Google 
 . 
 Ads 
 . 
 GoogleAds 
 . 
 V21 
 . 
 Enums 
 . 
 AssetFieldTypeEnum 
 . 
 Types 
 ; 
 using 
  
 static 
  
 Google 
 . 
 Ads 
 . 
 GoogleAds 
 . 
 V21 
 . 
 Enums 
 . 
 AssetGroupStatusEnum 
 . 
 Types 
 ; 
 using 
  
 static 
  
 Google 
 . 
 Ads 
 . 
 GoogleAds 
 . 
 V21 
 . 
 Enums 
 . 
 BudgetDeliveryMethodEnum 
 . 
 Types 
 ; 
 using 
  
 static 
  
 Google 
 . 
 Ads 
 . 
 GoogleAds 
 . 
 V21 
 . 
 Enums 
 . 
 CampaignStatusEnum 
 . 
 Types 
 ; 
 using 
  
 static 
  
 Google 
 . 
 Ads 
 . 
 GoogleAds 
 . 
 V21 
 . 
 Enums 
 . 
 ConversionActionCategoryEnum 
 . 
 Types 
 ; 
 using 
  
 static 
  
 Google 
 . 
 Ads 
 . 
 GoogleAds 
 . 
 V21 
 . 
 Enums 
 . 
 ConversionOriginEnum 
 . 
 Types 
 ; 
 using 
  
 static 
  
 Google 
 . 
 Ads 
 . 
 GoogleAds 
 . 
 V21 
 . 
 Enums 
 . 
 EuPoliticalAdvertisingStatusEnum 
 . 
 Types 
 ; 
 using 
  
 static 
  
 Google 
 . 
 Ads 
 . 
 GoogleAds 
 . 
 V21 
 . 
 Enums 
 . 
 ListingGroupFilterListingSourceEnum 
 . 
 Types 
 ; 
 using 
  
 static 
  
 Google 
 . 
 Ads 
 . 
 GoogleAds 
 . 
 V21 
 . 
 Enums 
 . 
 ListingGroupFilterTypeEnum 
 . 
 Types 
 ; 
 using 
  
 static 
  
 Google 
 . 
 Ads 
 . 
 GoogleAds 
 . 
 V21 
 . 
 Resources 
 . 
 Campaign 
 . 
 Types 
 ; 
 namespace 
  
 Google.Ads.GoogleAds.Exa<mples.V>21 
 { 
  
 /// summary 
  
 /// This example shows how to create a Performance Max retail campaign. 
  
 /// 
  
 /// This will be created for "All products". 
  
 /// 
  
 /// For more information about Performance Max retail campaigns, see 
  
 /// https://developers.google.com/google-ads/api/docs/performance-max/retail 
  
 /// 
  
 /// Prerequisites: 
  
 /// - You need to have access to a Merchant Center account. You can find 
  
 ///   instructions to create a Merchant Center account here: 
  
 ///   https://support.google.com/merchants/answer/188924. 
  
 ///   This account must be linked to your Google Ads account. The integration 
  
 ///   instructions can be found at: 
  
 ///   https://developers.google.com/google-ads/api/docs/shopping-ads/merchant-center 
  
 /// - You need your Google Ads account to track conversions. The different ways 
  
 ///   to track conversions can be found here: 
  
 ///   https://support.google.com/google-ads/answer/1722054. 
  
 /// - You must have at least one conversion action in the account. For 
  
 ///   more about conversion actions, see 
  
 ///   https://developers.google.com/google-ads/api/docs/conversions/overvi<ew#conve>rsion_actions 
  
 /// /summary 
  
 public 
  
 class 
  
 AddPerformanceMaxRetailCampaign 
  
 : 
  
< Example>Base 
  
 { 
  
 /// summary 
  
 /// Command< line options for running the see cref=&quo>t;AddPerformanceMaxRetailCampaign&<quot;/ 
 > 
 /// example. 
  
 /// /summary 
  
 public 
  
 class 
  
 Options 
  
< : 
  
 Optio>nsBase 
  
 { 
  
 /// summary 
  
 /// The <Google A>ds customer ID. 
  
 /// /summary 
  
 [Option("customerId", Required = true, HelpText = 
 "The Google Ads customer ID.")] 
 < 
 p>ublic 
  
 long 
  
 CustomerId 
  
 { 
  
 get 
 ; 
  
 set 
 ; 
  
 } 
  
 /// summary 
 <        > 
 /// The Merchant Center account ID. 
  
 /// /summary 
  
 [Option("merchantCenterAccountId", Required = true, HelpText = 
 "The Merchant Center account ID.")] 
< > 
 public 
  
 long 
  
 MerchantCenterAccountId 
  
 { 
  
 get 
 ; 
  
 set 
 ; 
  
 } 
  
 /// summary 
  
 /// The final url for the generated ads. Must have <the same> domain as the Merchant 
  
 /// Center account. 
  
 /// /summary 
  
 [Option("finalUrl", Required = true, HelpText = 
 "The final url for the generated ads." + 
 "Must have the same dom<ain as >the Merchant Center account.")] 
  
 public 
  
 string 
  
 FinalUrl 
  
 { 
  
 get 
 ; 
  
 set 
 ; 
  
 } 
  
 /// summary 
  
 /// Optional<: A bool>ean value indicating if the campaign is enabled for brand 
  
 /// guidelines. 
  
 /// /summary 
  
 [Option("brandGuidelinesEnabled", Required = false, HelpText = 
 "A boolean value indicating if the camp<aign is> enabled for brand guidelines.")] 
  
 public 
  
 bool 
  
 BrandGuidelinesEnabled 
  
 { 
  
 get 
 ; 
<  
 set 
 ; 
  
 } 
>  
 } 
 < 
 /// summary 
>  
 /// Main method, t<o run >this code example as a standalone application. 
  
 /// /summary 
  
 /// param name="args"The command li<ne argu>ments./param 
  
 public 
  
 static 
  
 void 
  
 Main 
 ( 
 string 
 [] 
  
 args 
 ) 
  
 { 
  
 Options 
  
 options 
  
 = 
  
 ExampleUtilities 
 . 
 ParseCommandLineOptions 
 ( 
 args 
 ); 
  
 AddPerformanceMaxRetailCampaign 
  
 codeExample 
  
 = 
  
 new 
  
 AddPerformanceMaxRetailCampaign 
 (); 
  
 Console 
 . 
 WriteLine 
 ( 
 codeExample 
 . 
 Description 
 ); 
  
 codeExample 
 . 
 Run 
 ( 
  
 new 
  
 GoogleAdsClient 
 (), 
  
 options 
 . 
 CustomerId 
 , 
  
 options 
 . 
 MerchantCenterAccountId 
 , 
  
 options 
 . 
 FinalUrl 
 , 
  
 options 
 . 
 BrandGuidelinesEnabled 
  
 ); 
  
 } 
  
 // We specify temporary IDs that are specific to a single mutate request. Temporary IDs are 
  
 // always negative and unique within one mutate request. 
  
 // 
  
 // See https://developers.google.com/google-ads/api/docs/mutating/best-practices for further 
  
 // details. 
  
 // 
  
 // These temporary IDs are fixed because they are used in multiple places. 
  
 private 
  
 const 
  
 int 
  
 TEMPORARY_ID_BUDGET 
  
 = 
  
 - 
 1 
 ; 
  
 private 
  
 const 
  
 int 
  
 TEMPORARY_ID_CAMPAIGN 
  
 = 
  
 - 
 2 
 ; 
  
 private 
  
 const 
  
 int 
  
 TEMPORARY_ID_ASSET_GROUP 
  
 = 
  
 - 
 3 
 ; 
  
 // There are also entities that will be created in the same request but do not need to be 
  
 // fixed temporary IDs because they are referenced only once. 
  
 private 
  
 class 
  
 AssetTemporaryResourceNameGenerator 
  
 { 
  
 private 
  
 long 
  
 customerId 
 ; 
  
 private 
  
 long 
  
 next 
 ; 
  
 public 
  
 AssetTemporaryResourceNameGenerator 
 ( 
 long 
  
 customerId 
 , 
  
 long 
  
 assetGroupId 
 ) 
  
 { 
  
 this 
 . 
 customerId 
  
 = 
  
 customerId 
 ; 
  
 this 
 . 
 next 
  
 = 
  
 assetGroupId 
  
 - 
  
 1 
 ; 
  
 } 
  
 public 
  
 string 
  
 Next 
 () 
  
 { 
  
 long 
  
 i 
  
 = 
  
 next 
 ; 
 <       > 
 Interlocked 
 . 
 Decrement 
 ( 
 ref 
  
 next 
 ); 
  
 return 
  
 ResourceNam<es 
 . 
 Asset 
> ( 
 customerId 
 , 
  
 i 
 ); 
  
 } 
  
 } 
 > 
 /// summary 
  
 /// Returns a description about the code example. 
  
 /// /summary 
 <       > 
 public 
  
 override 
  
 string 
  
 Description 
  
 = 
 < 
 "T>his example s<hows how to create >a Performance Max reta<il cam>paign." 
 ; 
<  
 /// summary 
 > 
 /// Runs the code ex<ample.> 
  
 /// </summary 
  
 /// param name=&quo>t;client"The Google Ads cl<ient./>param 
 < 
 /// param name=">;customerId&qu<ot;The> Google Ads c<ustomer ID./param 
  
 /// param> name="merchantCenterAccountId"T<he Mer>chant Center account ID./param 
  
 /// param name="finalUrl"The final URL./param 
  
 /// param name="brandGuidelinesEnabled"Whether or not to enable brand guidelines./param 
  
 public 
  
 void 
  
 Run 
 ( 
  
 GoogleAdsClient 
  
 client 
 , 
  
 long 
  
 customerId 
 , 
  
 long 
  
 merchantCenterAccountId 
 , 
  
 string 
  
 finalUrl 
 , 
  
 bool 
  
 brandGuidelinesEnabled 
 ) 
  
 { 
  
 try 
  
 { 
  
 GoogleAdsServiceClient 
  
 googleAdsServiceClient 
  
 = 
  
 client 
 . 
 GetService 
 ( 
 Servic<es 
 . 
 V21 
 . 
 GoogleAdsServic>e 
 ); 
  
 // This campaign will override the customer conversion goals. 
  
 // Retrieve the current list of customer conversion goals. 
  
 ListCustomerConversionGoal 
  
 customerConversionGoals 
  
 = 
  
 GetCustomerConversionGoals 
 ( 
 client 
 , 
  
 customerId 
 ); 
  
 // Performance Max campaigns require that repeated assets such as headlines and 
  
 // descriptions be created before the campaign. 
  
 // 
  
 // For the list of required assets for a Pe<rforma>nce Max campaign, see 
  
 // https://developers.google.com/google-ads/api/docs/performance-max/assets 
  
 // 
  
 // Create the headlines. 
  
 Liststring 
  
 headlineAssetResourceNames 
  
 = 
  
 CreateMultipleTextAssets 
 ( 
  
 client 
 , 
  
 customerId 
 , 
  
 new 
 [] 
  
 { 
 <      > 
 "Travel" 
 , 
  
 "Travel Reviews" 
 , 
  
 "Book travel" 
  
 } 
  
 ); 
  
 // Create the descriptions. 
  
 Liststring 
  
 descriptionAssetResourceNames 
  
 = 
  
 CreateMultipleTextAssets 
 ( 
  
 client 
 , 
  
 customerId 
 , 
  
 new 
 [] 
  
 { 
  
 "Take to the air!" 
 , 
  
 "Fly to the sky!" 
  
 } 
  
 ); 
  
 string 
  
 tempResourceNameCampaignBudget 
  
 = 
  
 ResourceNames 
 . 
 CampaignBudget 
 ( 
  
 customerId 
 , 
  
 TEMPORARY_ID_BUDGET 
  
 ); 
  
 string 
  
 assetGroupResourceName 
  
 = 
  
 ResourceNames 
 . 
 AssetGroup 
 ( 
  
 customerId 
 , 
  
 TEMPORARY_ID_ASSET_GROUP 
  
 ); 
  
 // The below methods create and return MutateOperations that we later provide to the 
  
 // GoogleAdsService.Mutate method in order to create the entities in a single request. 
  
 // Since the entities for a Performance Max campaign are closely tied to one-another, 
  
 // it's considered a best practice to create them in a single Mutate request so they all 
  
 // complete successfully or fail entirely, leaving no orphaned entities. 
  
 // 
  
 // See: https://developers.google.com/google-ads/api/docs/mutating/overview 
  
 MutateOperation 
  
 campaignBudgetOperation 
  
 = 
  
 CreateCampaignBudgetOperation 
 ( 
  
 tempResourceNameCampaignBudget 
  
 ); 
  
 string 
  
 tempResourceNameCampaign 
  
 = 
  
 ResourceNames 
 . 
 Campaign 
 ( 
  
 customerId 
 , 
  
 TEMPORARY_ID_CAMPAIGN 
  
 ); 
  
 MutateOperation 
  
 performanceMaxCampaignOperation 
  
 = 
  
 CreatePerformanceMaxCampaignOperation 
 ( 
 <               > 
 tempResourceNameCampaign 
 , 
  
 tempResourceNameCampaignBudget 
 , 
  
 merchantCenterAcco<untId 
 , 
 > 
 brandGuidelinesEnabled 
  
 ); 
  
 ListMutateOperation 
  
 campaignCriterionOperations 
  
 = 
  
 CreateCampaignCriterionOperations 
 ( 
 tempResourceNameCampaign 
 ); 
  
 ListMutateOperation 
  
 assetGroupOperations 
  
 = 
  
 CreateAssetGroupOperations 
 ( 
  
 tempResourceNameCampaign 
 , 
  
 assetGroupResourceName 
 , 
  
 finalUrl 
 , 
  
 headlineAssetResourceNames 
 , 
  
 descriptionAssetResourceNames 
 , 
  
 new 
  
 AssetTemporaryResourceNameGenerat<or 
 ( 
 > 
 customerId 
 , 
  
 TEMPORARY_ID_ASSET_GROUP 
  
 ), 
  
 client 
 . 
 Config 
 , 
  
 brandGuidelinesEnabled 
  
 ); 
  
 ListMutateOperation 
  
 conversionGoalOperations 
  
 = 
  
 CreateCustomerConversionGoalOperations 
 ( 
  
 customerId 
< , 
 > 
 customerConversionGoals 
  
 ); 
  
 // Retail Performance Max campaigns require listing groups, which are created via the 
  
 // AssetGroupListingGroupFilter resource. 
  
 ListMutateOperation 
  
 assetGroupListingGroupOperations 
  
 = 
  
 CreateAssetGroupListingGroupOperations 
 ( 
  
 assetGroupResourceName 
  
 ); 
  
 MutateGoogleAdsRequest 
  
 request 
  
 = 
  
 new 
  
 MutateGoogleAdsRequest 
  
 { 
  
 CustomerId 
  
 = 
  
 customerId 
 . 
 ToString 
 () 
  
 }; 
  
 // It's important to create these entities in this order because they depend on 
  
 // each other. 
  
 // 
  
 // Additionally, we take several lists of operations and flatten them into one 
  
 // large list. 
  
 request 
 . 
 MutateOperations 
 . 
 Add 
 ( 
 campaignBudgetOperation 
 ); 
  
 request 
 . 
 MutateOperations 
 . 
 Add 
 ( 
 performanceMaxCampaignOperation 
 ); 
  
 request 
 . 
 MutateOperations 
 . 
 AddRange 
 ( 
 campaignCriterionOperations 
 ); 
  
 request 
 . 
 MutateOperations 
 . 
 AddRange 
 ( 
 assetGroupOperations 
 ); 
  
 request 
 . 
 MutateOperations 
 . 
 AddRange 
 ( 
 conversionGoalOperations 
 ); 
  
 request 
 . 
 MutateOperations 
 . 
 AddRange 
 ( 
 assetGroupListingGroupOperations 
 ); 
  
 MutateGoogleAdsResponse 
  
 response 
  
 = 
  
 googleAdsServiceClient 
 . 
 Mutate 
 ( 
 request 
 ); 
  
 PrintResponseDetails 
 ( 
 response 
 ); 
  
 } 
  
 catch 
  
 ( 
 GoogleAdsException 
  
 e 
 ) 
  
 { 
  
 Console 
 . 
 WriteLine 
 ( 
< "F>ailure:" 
 ); 
  
 Console 
 . 
 WriteLine 
 ( 
 $"Message: {e.Message}" 
 ); 
  
 Console 
 . 
 WriteLine 
 ( 
 $"Failure: {e.Failure}" 
 ); 
  
 Console 
 . 
 WriteLine 
 ( 
 $"Request ID: {e.RequestId}" 
 ); 
  
 throw 
 ; 
  
< } 
 > 
 } 
  
< /// summary 
  
 /// Creates> a MutateOperation that creates a new CampaignBudget. 
  
 //</ 
 > 
 /// A tem<porary >ID will be assigned to this campaign budget so t<hat it c>an be 
  
 /// referenced by other objects being created in the same Mutate request. 
  
 /// /summary 
  
 /// param name="budgetResourceName"The temporary resource name of the budget to 
  
 /// create./param 
  
 /// returnsA MutateOperation that creates a CampaignBudget./returns 
  
 private 
  
 MutateOperation 
  
 CreateCampaignBudgetOperation 
 ( 
  
 string 
  
 budgetResourceName 
 ) 
  
 { 
  
 MutateOperation 
  
 operation 
  
 = 
  
 new 
  
 MutateOperation 
  
 { 
  
 CampaignBudgetOperation 
  
 = 
  
 new 
  
 CampaignBudgetOperation 
  
 { 
  
 Create 
  
 = 
  
 new 
  
 CampaignBudget 
  
 { 
  
 Name 
  
 = 
  
 "Performance Max campaign budget #" 
  
 + 
  
 ExampleUtilities 
 . 
 GetRandomString 
 (), 
  
 // The budget period already defaults to Daily. 
  
 AmountMicros 
  
 = 
  
 50000000 
 , 
  
 DeliveryMethod 
  
 = 
  
 BudgetDeliveryMethod 
 . 
 Standard 
 , 
  
 // A Performance Max campaign cannot use a shared campaign budget. 
  
 ExplicitlyShared 
  
 = 
  
 false 
 , 
  
 // Set a temporary ID in the budget's resource name so it can be< referenced 
 > 
 // by the campaign in la<ter st>eps. 
 < 
 ResourceName 
  
 = 
  
 budgetRe>sourceName 
  
 } 
 <      > 
 } 
 < 
 }; 
  
 return 
  
 ope>ration 
 ; 
  
 } 
  
 ///< Creat>es a MutateOp<eration that creates a new Performa>nce Max campaign. 
  
 /// param name=&<quot;c>ampaignResour<ceName&>quot;The campaign resource name./param 
  
 /// par<am name=>"campaignBudgetResourceName"The campaign budget resource name./param 
  
 /// param name="merchantCenterAccountId"The Merchant Center account ID./param 
  
 /// param name="brandGuidelinesEnabled"Whether or not to enable brand guidelines./param 
  
 /// returnsA MutateOperations that will create this new campaign./returns 
  
 private 
  
 MutateOperation 
  
 CreatePerformanceMaxCampaignOperation 
 ( 
  
 string 
  
 campaignResourceName 
 , 
  
 string 
  
 campaignBudgetResourceName 
 , 
  
 long 
  
 merchantCenterAccountId 
 , 
  
 bool 
  
 brandGuidelinesEnabled 
 ) 
  
 { 
  
 MutateOperation 
  
 operation 
  
 = 
  
 new 
  
 MutateOperation 
 () 
  
 { 
  
 CampaignOperation 
  
 = 
  
 new 
  
 CampaignOperation 
 () 
  
 { 
  
 Create 
  
 = 
  
 new 
  
 Campaign 
 () 
  
 { 
  
 Name 
  
 = 
  
 "Performance Max campaign #" 
  
 + 
  
 ExampleUtilities 
 . 
 GetRandomString 
 (), 
  
 // Set the campaign status as PAUSED. The campaign is the only entity in 
  
 // the mutate request that should have its status set. 
  
 Status 
  
 = 
  
 CampaignStatus 
 . 
 Paused 
 , 
  
 // All Performance Max campaigns have an advertising_channel_type of 
  
 // PERFORMANCE_MAX. The advertising_channel_sub_type should not be set. 
  
 AdvertisingChannelType 
  
 = 
  
 AdvertisingChannelType 
 . 
 PerformanceMax 
 , 
  
 // Bidding strategy must be set directly on the campaign. Setting a 
  
 // portfolio bidding strategy by resource name is not supported. Max 
  
 // Conversion and Maximize Conversion Value are the only strategies 
  
 // supported for Performance Max campaigns. BiddingStrategyTYpe is 
  
 // read-only and cannot be set by the API. An optional ROAS (Return on 
  
 // Advertising Spend) can be set to enable the MaximizeConversionValue 
  
 // bidding strategy. The ROAS value must be specified as a ratio in the API. 
  
 // It is calculated by dividing "total value" by "total spend". 
  
 // 
  
 // For more information on Maximize Conversion Value, see the support 
  
 // article: 
  
 // http://support.google.com/google-ads/answer/7684216. 
  
 // 
  
 // A target_roas of 3.5 corresponds to a 350% return on ad spend. 
  
 MaximizeConversionValue 
  
 = 
  
 new 
  
 MaximizeConversionValue 
 () 
  
 { 
  
 TargetRoas 
  
 = 
  
 3.5 
  
 }, 
  
 ShoppingSetting 
  
 = 
  
 new 
  
 ShoppingSetting 
 () 
  
 { 
  
 MerchantId 
  
 = 
  
 merchantCenterAccountId 
 , 
  
 // Optional: To use products only from a specific feed, set FeedLabel 
  
 // to the feed label used in Merchant Center. 
  
 // See: https://support.google.com/merchants/answer/12453549. 
  
 // Omitting the FeedLabel field will use products from all feeds. 
  
 // FeedLabel = "INSERT_FEED_LABEL_HERE" 
  
 }, 
  
 // Set the Final URL expansion opt out. This flag is specific to 
  
 // Performance Max campaigns. If opted out (True), only the final URLs in 
  
 // the asset group or URLs specified in the advertiser's Google Merchant 
  
 // Center or business data feeds are targeted. 
  
 // 
  
 // If opted in (False), the entire domain will be targeted. For best 
  
 // results, set this value to false to opt in and allow URL expansions. You 
  
 // can optionally add exclusions to limit traffic to parts of your website. 
  
 // 
  
 // For a Retail campaign, we want the final URL's to be limited to those 
  
 // explicitly surfaced via GMC. 
  
 UrlExpansionOptOut 
  
 = 
  
 true 
 , 
  
 // Use the temporary resource name created earlier 
  
 ResourceName 
  
 = 
  
 campaignResourceName 
 , 
  
 // Set the budget using the given budget resource name. 
  
 CampaignBudget 
  
 = 
  
 campaignBudgetResourceName 
 , 
  
 // Set if the campaign is enabled for brand guidelines. For more information 
  
 // on brand guidelines, see https://support.google.com/google-ads/answer/14934472. 
  
 BrandGuidelinesEnabled 
  
 = 
  
 brandGuidelinesEnabled 
 , 
  
 // Declare whether or not this campaign contains political ads targeting the EU. 
  
 Contain<sEuPoli>ticalAdvertising 
  
 = 
  
 EuPoliticalAdvertisingStatus 
 . 
 DoesNotContainEuPoliticalAdvertising 
 , 
 <        > 
 // Op<tional fields 
 > 
 StartDate 
  
 = 
  
 DateTime 
 . 
 N<ow 
 . 
 Add>Days 
 ( 
 1 
 ). 
 ToStr<ing 
 ( 
 &qu>ot;yyyyMMdd" 
 ), 
  
 EndDate 
  
 = 
  
 DateTim<e 
 . 
 Now 
 . 
 Ad>dDays 
 ( 
 365 
 ). 
 ToString 
 ( 
 &<quot;yyyyMMdd&q>uot; 
 ) 
  
 } 
  
 } 
  
 }; 
  
 return 
  
 operation 
 ; 
  
 } 
<  
 /// su>mmary 
  
 /// Crea<tes a list of M>utateOperations that create new campaign criteria. 
  
 /// /summary 
  
 /// param name="campaignResourceName"The campaign resource name./param 
  
 /// returnsA list of MutateOperations that create new campaign criteria./returns 
  
 private 
  
 ListMutateOperation 
  
 CreateCampaignCriterionOperations 
 ( 
  
 string 
  
 campaignResourceName 
 ) 
  
 { 
  
 ListMutateOperation 
  
 operations 
  
 = 
  
 new 
  
 ListMutateOperation 
 (); 
  
 // Set the LOCATION campaign criteria. 
  
 // Target all of New York City except Brooklyn. 
  
 // Location IDs are listed here: 
  
 // https://developers.google.com/google-ads/api/reference/data/geotargets 
  
 // and they can also be retrieved using the GeoTargetConstantService as shown 
  
 // here: https://developers.google.com/google-ads/api/docs/targeting/location-targeting 
  
 // 
  
 // We will add one positive location target for New York City (ID=1023191) 
  
 // and one negative location target for Brooklyn (ID=1022762). 
  
 // First, add the positive (negative = False) for New York City. 
  
 MutateOperation 
  
 operation1 
  
 = 
  
 new 
  
 MutateOperation 
 () 
  
 { 
  
 CampaignCriterionOperation 
  
 = 
  
 new 
  
 CampaignCriterionOperation 
 () 
  
 { 
  
 Create 
  
 = 
  
 new 
  
 CampaignCriterion 
 () 
  
 { 
  
 Campaign 
  
 = 
  
 campaignResourceName 
 , 
  
 Location 
  
 = 
  
 new 
  
 LocationInfo 
 () 
  
 { 
  
 GeoTargetConstant 
  
 = 
  
 ResourceNames 
 . 
 GeoTargetConstant 
 ( 
 1023191 
 ) 
  
 }, 
  
 Negative 
  
 = 
  
 false 
  
 } 
  
 } 
  
 }; 
  
 operations 
 . 
 Add 
 ( 
 operation1 
 ); 
  
 // Next add the negative target for Brooklyn. 
  
 MutateOperation 
  
 operation2 
  
 = 
  
 new 
  
 MutateOperation 
 () 
  
 { 
  
 CampaignCriterionOperation 
  
 = 
  
 new 
  
 CampaignCriterionOperation 
 () 
  
 { 
  
 Create 
  
 = 
  
 new 
  
 CampaignCriterion 
 () 
  
 { 
  
 Campaign 
  
 = 
  
 campaignResourceName 
 , 
  
 Location 
  
 = 
  
 new 
  
 LocationInfo 
 () 
  
 { 
  
 GeoTargetConstant 
  
 = 
  
 ResourceNames 
 . 
 GeoTargetConstant 
 ( 
 1022762 
 ) 
  
 }, 
  
 Negative 
  
 = 
  
 true 
  
 } 
  
 } 
  
 }; 
  
 operations 
 . 
 Add 
 ( 
 operation2 
 ); 
  
 // Set the LANGUAGE campaign criterion. 
  
 MutateOperation 
  
 operation3 
  
 = 
  
 new 
  
 MutateOperation 
 () 
  
 { 
  
 CampaignCriterionOperation 
  
 = 
  
 new 
  
 CampaignCriterionOperation 
 () 
  
 { 
  
 Create 
  
 = 
  
 new 
  
 CampaignCriterion 
 () 
  
 { 
  
 Campaign 
  
 = 
  
 campaignResourceName 
 , 
  
 // Set the language. 
  
 // For a list of all language codes, see: 
  
 // h<ttps://>developers.google.com/google-ads/api/reference/data/codes-formats#expandable-7 
  
 Language 
  
 = 
  
 new 
  
 LanguageInfo 
 () 
  
 { 
  
 LanguageConstant 
  
 = 
  
 Reso<urceName>s 
 . 
 LanguageCon<stant 
 ( 
 1000 
 ) 
  
 // Engl>ish 
 <      > 
 }, 
 < 
 } 
 > 
 } 
 < 
 }; 
 > 
 op<erations 
 . 
 Add 
 ( 
 opera>tion3 
 ); 
 < 
 re>turn 
  
 operatio<ns 
 ; 
 > 
 } 
  
 /// summary 
 < 
 //>/ Creates multiple te<xt ass>ets and returns the list of resource names. 
  
 /// These repeated assets must be created in a separate request prior to 
  
 /// creating the campaign. 
  
 /// /summary 
  
 /// param name="client"The Google Ads Client./param 
  
 /// param name="customerId"The customer's ID./param 
  
 /// param name="texts"The texts to add./param 
  
 /// returnsA list of asset resource names./returns 
  
 private 
  
 Liststring 
  
 CreateMultipleTextAssets 
 ( 
  
 GoogleAdsClient 
  
 client 
 , 
  
 long 
  
 customerId 
 , 
  
 string 
 [] 
  
 texts 
 ) 
  
 { 
  
 // Get the GoogleAdsService. 
  
 GoogleAdsServiceClient 
  
 googleAdsServiceClient 
  
 = 
  
 client 
 . 
 GetService 
 ( 
 Services 
 . 
 V21 
 . 
 GoogleAdsService 
 ); 
  
 MutateGoogleAdsRequest 
  
 request 
  
 = 
  
 new 
  
 MutateGoogleAdsRequest 
 () 
  
 { 
  
 CustomerId 
  
 = 
  
 customerId 
 . 
 ToString 
 () 
  
 }; 
  
 foreach 
  
 ( 
 string 
  
 text 
  
 in 
  
 texts 
 ) 
  
 { 
  
 request 
 . 
 MutateOperations 
 . 
 Add 
 ( 
  
 new 
  
 MutateOperation 
 () 
  
 { 
  
 AssetOperation 
  
 = 
  
 new 
  
 AssetOperation 
 () 
  
 { 
  
 Create 
  
 = 
  
 new 
  
 Asset 
 () 
 <      > 
 { 
 <      > 
 TextAsset 
  
 = 
  
 new 
  
 TextAsset 
 () 
  
 { 
  
 Text 
  
 = 
  
 text 
  
 } 
  
 } 
  
 } 
  
 } 
  
 ); 
  
 } 
  
 // Send the operations in a single Mutate request. 
  
 MutateGoogleAdsResponse 
  
 response 
  
 = 
  
 googleAdsServ<iceClie>nt 
 . 
 Mutate 
 ( 
 request 
 ); 
  
 Liststring 
  
 assetResourceNames 
  
 = 
  
 new 
  
 Liststring 
 (); 
 < 
 for>each 
  
 ( 
 MutateO<perationResponse 
  
 operationRespons>e 
  
 in 
  
 response 
 . 
 MutateOperati<onResp>onses 
 ) 
 < 
 { 
  
 MutateAsset>Result 
  
 assetResult 
  
 = 
  
 operation<Respon>se 
 . 
 AssetResul<t 
 ; 
  
 as>setResourceNam<es 
 . 
 Add 
> ( 
 assetResult 
 . 
< ResourceName 
 ); 
  
 } 
 > 
 PrintResponseDetails 
 ( 
 response 
 ); 
< > 
 retur<n 
  
 assetResourceNames 
 ; 
  
 } 
  
> /// summary 
  
 /// Creates a list of MutateO<perati>ons that crea<te a new asset_group. 
  
 /// >/summary 
  
 /// param name="<campai>gnResourceNam<e"The campaign> resource name./param 
< > 
 /// param n<ame="assetGroupResourceName&qu>ot;The asset group resource name./param 
 <      > 
 /// param nam<e=">;finalUrl"The final url./param 
  
 /// param name=<"he>adlineAssetResourceNa<mes"The he>adline asset resource names./param 
  
 /// param name="descriptionAssetResourceNames"The description asset resource 
  
 /// names./param 
 < 
 />// param name="resourceNameGenerator&quo<t;A ge>nerator for unique temporary ID's./param 
  
 /// param name="config"The Google Ads config./param 
  
 /// param name="brandGuidelinesEnabled"Whether or not to enable brand gui<delines./param<>/span>  
 /// returnsA l<ist of MutateOp>erations that create the new asset group./returns 
  
 private 
  
 ListMutateOperation 
  
 CreateAssetGroupOperations 
 ( 
  
 string 
  
 campaignResourceName 
 , 
  
 string 
  
 assetGroupResourceName 
 , 
  
 string 
  
 finalUrl 
 , 
  
 Liststring 
  
 headlineAssetResourceNames 
 , 
  
 Liststring 
  
 descriptionAssetResourceNames 
 , 
  
 AssetTemporaryResourceNameGenerator 
  
 resourceNameGenerator 
 , 
  
 GoogleAdsConfig 
  
 config 
 , 
  
 bool 
  
 brandGuidelinesEnabled 
 ) 
  
 { 
  
 ListMutateOperation 
  
 operations 
  
 = 
  
 new 
  
 ListMutateOperation 
 (); 
  
 // For the list of required assets for a Performance Max campaign, see 
  
 // https://developers.google.com/google-ads/api/docs/performance-max/assets 
  
 // Create and link the long headline text asset. 
  
 string 
  
 longHeadlineResourceName 
  
 = 
  
 resourceNameGenerator 
 . 
 Next 
 (); 
  
 operations 
 . 
 Add 
 ( 
  
 CreateTextAssetOperation 
 ( 
  
 longHeadlineResourceName 
 , 
  
 "Travel the World" 
  
 ) 
  
 ); 
  
 // Create the business name text asset. 
  
 string 
  
 businessNameResourceName 
  
 = 
  
 resourceNameGenerator 
 . 
 Next 
 (); 
  
 operations 
 . 
 Add 
 ( 
  
 CreateTextAssetOperation 
 ( 
  
 businessNameResourceName 
 , 
  
 "Interplanetary Cruises" 
  
 ) 
  
 ); 
  
 // Create the Logo Asset. 
  
 string 
  
 logoResourceName 
  
 = 
  
 resourceNameGenerator 
 . 
 Next 
 (); 
  
 operations 
 . 
 Add 
 ( 
  
 CreateImageAssetOperation 
 ( 
  
 logoResourceName 
 , 
  
 "https://gaagl.page.link/1Crm" 
 , 
  
 "Logo Image" 
 , 
  
 config 
  
 ) 
  
 ); 
  
 // Create the Marketing Image Asset. 
  
 string 
  
 marketingImageResourceName 
  
 = 
  
 resourceNameGenerator 
 . 
 Next 
 (); 
  
 operations 
 . 
 Add 
 ( 
  
 CreateImageAssetOperation 
 ( 
  
 marketingImageResourceName 
 , 
  
 "https://gaagl.page.link/Eit5" 
 , 
  
 "Marketing Image" 
 , 
  
 config 
  
 ) 
  
 ); 
  
 // Create the Square Marketing Image Asset. 
  
 string 
  
 squareMarketingImageResourceName 
  
 = 
  
 resourceNameGenerator 
 . 
 Next 
 (); 
  
 operations 
 . 
 Add 
 ( 
  
 CreateImageAssetOperation 
 ( 
  
 squareMarketingImageResourceName 
 , 
  
 "https://gaagl.page.link/bjYi" 
 , 
  
 "Square Marketing Image" 
 , 
  
 config 
  
 ) 
  
 ); 
  
 // An AssetGroup is linked to an Asset by creating a new AssetGroupAsset 
  
 // and providing: 
  
 //   the resource name of the AssetGroup 
  
 //   the resource name of the Asset 
  
 //   the field_type of the Asset in this AssetGroup. 
  
 // 
  
 // To learn more about AssetGroups, see 
  
 // https://developers.google.com/google-ads/api/docs/performance-max/asset-groups 
  
 // 
  
 // Also, note that all asset creation operations must be before the 
  
 // asset group creation operation and the asset group linking operations. 
  
 // Create the AssetGroup 
  
 operations 
 . 
 Add 
 ( 
  
 new 
  
 MutateOperation 
 () 
  
 { 
  
 AssetGroupOperation 
  
 = 
  
 new 
  
 AssetGroupOperation 
 () 
  
 { 
  
 Create 
  
 = 
  
 new 
  
 AssetGroup 
 () 
  
 { 
  
 Name 
  
 = 
  
 "Performance Max asset group #" 
  
 + 
  
 ExampleUtilities 
 . 
 GetRandomString 
 (), 
  
 Campaign 
  
 = 
  
 campaignResourceName 
 , 
  
 FinalUrls 
  
 = 
  
 { 
  
 finalUrl 
  
 }, 
  
 FinalMobileUrls 
  
 = 
  
 { 
  
 finalUrl 
  
 }, 
  
 Status 
  
 = 
  
 AssetGroupStatus 
 . 
 Paused 
 , 
  
 ResourceName 
  
 = 
  
 assetGroupResourceName 
  
 } 
  
 } 
  
 } 
  
 ); 
  
 // Link the previously created assets. 
  
 // Link the headline assets. 
  
 foreach 
  
 ( 
 string 
  
 resourceName 
  
 in 
  
 headlineAssetResourceNames 
 ) 
  
 { 
  
 operations 
 . 
 Add 
 ( 
  
 new 
  
 MutateOperation 
 () 
  
 { 
  
 AssetGroupAssetOperation 
  
 = 
  
 new 
  
 AssetGroupAssetOperation 
 () 
  
 { 
  
 Create 
  
 = 
  
 new 
  
 AssetGroupAsset 
 () 
  
 { 
  
 FieldType 
  
 = 
  
 AssetFieldType 
 . 
 Headline 
 , 
  
 AssetGroup 
  
 = 
  
 assetGroupResourceName 
 , 
  
 Asset 
  
 = 
  
 resourceName 
  
 } 
  
 } 
  
 } 
  
 ); 
  
 } 
  
 // Link the description assets. 
  
 foreach 
  
 ( 
 string 
  
 resourceName 
  
 in 
  
 descriptionAssetResourceNames 
 ) 
  
 { 
  
 operations 
 . 
 Add 
 ( 
  
 new 
  
 MutateOperation 
 () 
  
 { 
  
 AssetGroupAssetOperation 
  
 = 
  
 new 
  
 AssetGroupAssetOperation 
 () 
  
 { 
  
 Create 
  
 = 
  
 new 
  
 AssetGroupAsset 
 () 
  
 { 
  
 FieldType 
  
 = 
  
 AssetFieldType 
 . 
 Description 
 , 
  
 AssetGroup 
  
 = 
  
 assetGroupResourceName 
 , 
  
 Asset 
  
 = 
  
 resourceName 
  
 } 
  
 } 
  
 } 
  
 ); 
  
 } 
  
 operations 
 . 
 Add 
 ( 
  
 CreateLinkAssetOperation 
 ( 
  
 AssetFieldType 
 . 
 LongHeadline 
 , 
  
 assetGroupResourceName 
 , 
  
 longHeadlineResourceName 
  
 ) 
  
 ); 
  
 operations 
 . 
 Add 
 ( 
  
 CreateLinkAssetOperation 
 ( 
  
 AssetFieldType 
 . 
 BusinessName 
 , 
  
 assetGroupResourceName 
 , 
  
 businessNameResourceName 
 , 
  
 brandGuidelinesEnabled 
  
 ) 
  
 ); 
  
 operations 
 . 
 Add 
 ( 
  
 CreateLinkAssetOperation 
 ( 
  
 AssetFieldType 
 . 
 Logo 
 , 
  
 assetGroupResourceName 
 , 
  
 logoRe<sourceN>ame 
 , 
  
 brandGuidelinesEnabled 
  
 ) 
  
 ); 
< > 
 operation<s 
 . 
 Add 
 ( 
  
 CreateL>inkAssetOperation 
 ( 
  
 AssetFieldType 
 . 
 Marketin<gImage> 
 , 
 < 
 assetGro>upResourceName 
 , 
  
< market>ingImageResou<rceName> 
  
 ) 
  
 ); 
  
 ope<rations 
 . 
> Add 
 ( 
  
 CreateLinkAssetOperation 
 ( 
  
 AssetFieldType 
 . 
 SquareMarketingImage 
 , 
 > 
 assetGroupResourceName 
 , 
  
 squareMarketingImageResourceName 
  
 ) 
  
 ); 
  
 return 
  
 operations 
 ; 
  
 } 
  
 /// summary 
  
 /// Creates a MutateOperation that creates a new text asset. 
  
 /// /summary 
  
 /// param name="assetResourceName"The resource name of the text asset to be 
  
 /// created./param 
  
 /// param name="text"The text of the as<set to >be created./param 
  
 /// returnsA MutateOperation that creates the new text as<set./ret>urns 
  
< private 
  
 MutateOperation 
  
 Create>TextAssetOperation 
 ( 
  
 string 
  
 assetResourceName 
 , 
 <      > 
 string 
  
 text 
< ) 
  
 = 
  
 new 
  
 MutateOp>eration 
 () 
  
 { 
  
 AssetOperation 
  
 = 
  
 ne<w 
  
 Asse>tOperation 
 () 
<  
 { 
 >               < 
 Creat>e 
  
 = 
  
 new 
  
 Asset 
< () 
 > 
 { 
 <      > 
 ResourceNam<e 
  
 = 
  
 ass>etResourceName 
 , 
  
 TextAsset 
<  
 = 
  
 new 
  
 T>extAsset 
 () 
  
 { 
  
 Text 
  
 = 
  
 text 
  
 } 
  
 } 
  
 } 
  
 }; 
  
 /// summary 
  
 />// Creates a MutateOperation that creates a new image asset. 
  
 /// /summary 
  
 /// param name="assetResourceName"The resource name of the text asset to be 
  
 /// created./param 
  
 /// param name="url"The url of the image to be retrieved and put into an asset./param 
  
 /// param name="assetName"The asset name./param 
  
 /// param name="config"The Google Ads config./param 
  
 /// returnsA MutateOperation that creates a new image asset./returns 
  
 private 
  
 MutateOperation 
  
 CreateImageAssetOperation 
 ( 
  
 string 
  
 assetResourceName 
 , 
  
 string 
  
 url 
 , 
  
 string 
  
 assetName 
 , 
  
 GoogleAdsConfig 
  
 config 
 ) 
  
 = 
  
 new 
  
 MutateOperation 
 () 
  
 { 
  
 AssetOperation 
  
 = 
  
 new 
  
 AssetOperation 
 () 
  
 { 
  
 Create 
  
 = 
  
 new 
  
 Asset 
 () 
  
 { 
 < 
 R>esourceName 
  
 = 
  
 assetResourceName 
 , 
  
 ImageAsset 
  
 = 
  
 new 
  
 ImageAsset 
 () 
 <        > 
< { 
 > 
 Data 
  
 = 
 < 
 Byte>String 
 . 
 CopyFr<om 
 ( 
  
 M>ediaUtilities 
 . 
 GetAssetDataFromUrl 
 ( 
 url 
 , 
  
 config 
 ) 
  
 ) 
 <      > 
 }, 
 < 
 // Provide a> unique friendly name to identify your asset. 
 <      > 
 // When th<ere is an existing image asset with> the same content but a 
 <      > 
 // different <name, t>he new name will be dropped silently. 
 < 
 Na>me 
  
 = 
  
 assetName 
  
 } 
  
 } 
  
 }; 
  
 /// summary 
  
 /// Creates a MutateOperation that links an asset to an asset group. 
  
 /// /summary 
  
 /// param name="fieldType"The field type of the asset to be linked./param 
  
 /// param name="linkedEntityResourceName"The resource name of the entity (asset group or 
  
 /// campaign) to link the asset to./param 
  
 /// param name="assetResourceName"The resource name of the text asset to be 
  
 /// linked./param 
  
 /// param name="brandGuidelinesEnabled"Whether or not to enable brand guidelines./param 
  
 /// returnsA MutateOperation that links an asset to an asset group./returns 
  
 private 
  
 MutateOperation 
  
 CreateLinkAssetOperation 
 ( 
  
 AssetFieldType 
  
 fieldType 
 , 
  
 string 
  
 linkedEntityResourceName 
 , 
  
 string 
  
 assetResourceName 
 , 
  
 bool 
  
 brandGuidelinesEnabled 
  
 = 
  
 false 
 ) 
  
 { 
  
 if 
  
 ( 
 brandGuidelinesEnabled 
 ) 
  
 { 
  
 return 
  
 new 
  
 MutateOperation 
 () 
  
 { 
  
 CampaignAssetOperation 
  
 = 
  
 new 
  
 CampaignAssetOperation 
 () 
  
 { 
  
 Create 
  
 = 
  
 new 
  
 CampaignAsset 
 () 
  
 { 
  
 F<ieldTyp>e 
  
 = 
  
 fieldType 
 , 
  
 Campaign 
  
 = 
  
 linkedEntityResource<Name 
 , 
 >             < 
 Asset 
  
> = 
  
 assetResourceName 
 <      >             < 
 } 
 > 
 } 
 < 
 }; 
 > 
 } 
  
< else 
 > 
 { 
  
 return 
  
 new 
  
 MutateOp<eration 
 (>) 
  
 { 
 < 
 Ass>etGroupAssetOperation 
  
 = 
  
 new 
  
 AssetGroupAssetOperation 
 () 
  
 { 
  
 Create 
  
 = 
  
 new 
  
 AssetGroupAsset 
 () 
  
 { 
  
 FieldType 
  
 = 
  
 fieldType 
 , 
  
 AssetGroup 
  
 = 
  
 linkedEntityResourceName 
 , 
 < 
 Asset 
  
> = 
  
 assetResourceName 
 < 
 } 
 > 
 } 
  
 }; 
  
 } 
  
 } 
  
 /// summary 
  
 /// Retrieves the list of customer conversion goals. 
  
 /// /summary 
  
 /// param name="client"The Google Ads Client./param 
  
 /// param name="customerId"The customer's id./param 
  
 /// returnsA list customer conversion goals./returns 
  
 private 
  
 ListCustomerConversionGoal 
  
 GetCustomerConversionGoals 
 ( 
  
 GoogleAdsClient 
  
 client 
 , 
  
 long 
  
 customerId 
 ) 
  
 { 
  
 // Get the GoogleAdsService. 
  
 GoogleAd<sServiceClient 
  
 googleAdsServiceClient 
>  
 = 
  
 client 
 . 
 GetService 
 ( 
 Services 
 . 
 V21 
 . 
 GoogleAdsService 
 ); 
  
 ListCustomerConversionGoal 
  
 conversionGoals 
  
 = 
  
 new 
  
 ListCustomerConversionGoal 
 (); 
  
 SearchGoogleAdsRequest 
  
 request 
  
 = 
  
 new 
  
 SearchGoogleAdsRequest 
 () 
  
 { 
  
 CustomerId 
  
 = 
  
 customerId 
 . 
 ToString 
 (), 
  
 Query 
  
 = 
  
 @"SELECT 
 <       >  customer_conversion_goal.category, 
 customer_conversion_goal.origin 
 <        >    FROM 
 <                    cus>tomer_conversion_g<oal&qu>ot; 
 < 
 }; 
  
 // The nu>mber of conversion goals is typic<ally l>ess than 50 s<o we us>e 
  
 // GoogleAdsService.search in<stead of> search_stream. 
 < 
 PagedEnu>merableSearchGoogleAdsResponse 
 , 
  
 GoogleAdsRow 
  
 searchPagedResponse 
  
 = 
  
 goo<gleAdsServiceClient 
 . 
 Se>arch 
 ( 
 request 
 ); 
  
 // Iterate over <the results and> build the list of conversion goals. 
 < 
 fore>ach 
  
 ( 
 GoogleAdsRow 
  
 row 
  
 in 
  
 searchPagedResponse 
 ) 
  
 { 
  
 conversionGoals 
 . 
 Add 
 ( 
 row 
 . 
 CustomerConversionGoal 
 ); 
  
 } 
  
 return 
  
 conversionGoals 
 ; 
  
 } 
  
 /// summary 
  
 /// Creates a list of MutateOperations that override customer conversion goals. 
  
 /// /summary 
  
 /// param name="customerId"The customer's id./param 
  
 /// param name="conversionGoals"A list customer conversion goals./param 
  
 /// returnsA list customer conversion goal operations./returns 
  
 private 
  
 ListMutateOperation 
  
 CreateCustomerConversionGoalOperations 
 ( 
  
 long 
  
 customerId 
 , 
  
 ListCustomerConversionGoal 
  
 conversionGoals 
 ) 
  
 { 
  
 ListMutateOperation 
  
 operations 
  
 = 
  
 new 
  
 ListMutateOperation 
 (); 
  
 foreach 
  
 ( 
 CustomerConversionGoal 
  
 conversionGoal 
  
 in 
  
 conversionGoals 
 ) 
  
 { 
  
 CustomerConversionGoal 
  
 newConversionGoal 
  
 = 
  
 new 
  
 CustomerConversionGoal 
 () 
  
 { 
  
 ResourceName 
  
 = 
  
 ResourceNames 
 . 
 CustomerConversionGoal 
 ( 
 && 
 customerId 
 , 
  
 conversionGoal 
 . 
 Category 
 , 
  
 conversionGoal 
 . 
 Origin 
  
 ), 
  
 }; 
  
 // Change the biddability for the campaign conversion goal. 
  
 // Set biddability to True for the desired (category, origin). 
  
 // Set biddability to False for all other conversion goals. 
  
 // Note: 
  
 //  1- It is assumed that this Conversion Action 
  
 //     (category=PURCHASE, origin=WEBSITE) exists in this account. 
 < 
 // > 2- More than one goal can be biddable if desired. This example 
  
 //     shows only one. 
  
 newCo<nversion>Goal 
 . 
 Biddable 
<  
 = 
  
 conversionGo>al 
 . 
 Category 
  
 == 
  
 ConversionActionCatego<ry 
 . 
 Pur>chase 
  
 <       > 
 conversionGoal 
 . 
 Origin 
<  
 == 
  
 Conv>ersionOrigin 
 . 
 Website 
 ; 
< > 
 operations 
 . 
 Add 
 ( 
  
 new 
  
 MutateOperation 
 () 
  
 { 
  
 Cus<tomerConversion>GoalOperation 
  
 = 
  
 new 
  
 Cu<stomerConversio>nGoalOperation 
 () 
  
 { 
  
 Update 
  
 = 
  
 newConversionGoal 
 , 
  
 UpdateMask 
  
 = 
  
 FieldMasks 
 . 
 AllSetFieldsOf 
 ( 
 newConversionGoal 
 ) 
  
 } 
  
 } 
  
 ); 
  
 } 
  
 return 
  
 operations 
 ; 
  
 } 
  
 /// summary 
  
 /// Creates a list of MutateOperations that create a new asset group 
  
 /// listing group filter. 
  
 /// /summary 
  
 /// param name="assetGroupResourceName"The resource< name of the asset> group./param 
  
 /// returnsA list of mutate operations./returns 
  
 private 
  
 ListMutateOperation 
  
 CreateAssetGroupListingGroupOperations 
 ( 
  
 string 
  
 assetGroupResourceName 
 ) 
  
 { 
  
 ListMutateOperation 
  
 operations 
  
 = 
  
 new 
  
 ListMutateOperation 
 (); 
  
 // Creates a new ad group criterion containing the "default" listing group (All 
  
 // products). 
  
 AssetGroupListingGroupFilter 
  
 listingGroupFilter 
  
 = 
  
 new 
  
 AssetGroupListingGroupFilter 
 () 
  
 { 
  
 AssetGroup 
  
 = 
  
 assetGroupResourceName 
 , 
  
 // Since this is the root node, do not set the ParentListingGroupFilter. For all 
  
 // other nodes, this would refer to the parent listing group filter resource name. 
  
 // ParentListingGroupFilter = "PARENT FILTER NAM<E"> 
  
 // The UnitIncluded means this node has no children. 
  
 Type 
  
 = 
  
 ListingGroupFilterType 
 . 
 UnitIncluded 
 , 
  
 // Because this is a Performance Max camp<aign for> retail, we n<eed to specify that 
 > 
 // this is in the sh<opping> listing source. 
  
 ListingSource 
  
 = 
  
 ListingGroupFilterListingSource 
 . 
 Shopping 
  
 }; 
  
 AssetGroupListingGroupFilterOperation 
  
 operation 
  
 = 
  
 new 
  
 AssetGroupListingGroupFilterOperation 
 () 
  
 { 
  
 Create 
  
 = 
  
 listingGroupFilter 
  
 }; 
  
 operations 
 . 
 Add 
 ( 
  
 new 
  
 MutateOperation 
 () 
  
 { 
  
 AssetGroupListingGroupFilterOperation 
  
 = 
  
 operation 
  
 } 
  
 ); 
  
 return 
  
 operations 
 ; 
  
 } 
  
 /// summary 
  
 /// Prints the details of a MutateGoogleAdsResponse. Parses the "response" oneof field name 
  
 /// and uses it to extract the new entity's name and resource name. 
  
 /// /summary 
  
 /// param name="response"A MutateGoogleAdsResponse instance./param 
  
 private 
  
 void 
  
 PrintResponseDetails 
 ( 
 MutateGoogleAdsResponse 
  
 response 
 ) 
  
 { 
  
 // Parse the Mutate response to print details about the entities that were created 
  
 // in the request. 
  
 foreach 
  
 ( 
 MutateOperationResponse 
  
 operationResponse 
  
 in 
  
 response 
 . 
 MutateOperationResponses 
 ) 
  
 { 
  
 string 
  
 resourceName 
 ; 
  
 string 
  
 entityName 
  
 = 
  
 operationResponse 
 . 
 ResponseCase 
 . 
 ToString 
 (); 
  
 // Trim the substring "Result" from the end of the entity name. 
  
 entityName 
  
 = 
  
 entityName 
 . 
 Remove 
 ( 
 entityName 
 . 
 Length 
  
 - 
  
 6 
 ); 
  
 switch 
  
 ( 
 operationResponse 
 . 
 ResponseCase 
 ) 
  
 { 
  
 case 
  
 MutateOperationResponse 
 . 
 ResponseOneofCase 
 . 
 AdGroupResult 
 : 
  
 resourceName 
  
 = 
  
 operationResponse 
 . 
 AdGroupResult 
 . 
 ResourceName 
 ; 
  
 break 
 ; 
  
 case 
  
 MutateOperationResponse 
 . 
 ResponseOneofCase 
 . 
 AdGroupAdResult 
 : 
  
 resourceName 
  
 = 
  
 operationResponse 
 . 
 AdGroupAdResult 
 . 
 ResourceName 
 ; 
  
 break 
 ; 
  
 case 
  
 MutateOperationResponse 
 . 
 ResponseOneofCase 
 . 
 CampaignResult 
 : 
  
 resourceName 
  
 = 
  
 operationResponse 
 . 
 CampaignResult 
 . 
 ResourceName 
 ; 
  
 break 
 ; 
  
 case 
  
 MutateOperationResponse 
 . 
 ResponseOneofCase 
 . 
 CampaignBudgetResult 
 : 
  
 resourceName 
  
 = 
  
 operationResponse 
 . 
 CampaignBudgetResult 
 . 
 ResourceName 
 ; 
  
 break 
 ; 
  
 case 
  
 MutateOperationResponse 
 . 
 ResponseOneofCase 
 . 
 CampaignCriterionResult 
 : 
  
 resourceName 
  
 = 
  
 operationResponse 
 . 
 CampaignCriterionResult 
 . 
 ResourceName 
 ; 
  
 break 
 ; 
  
 case 
  
 MutateOperationResponse 
 . 
 ResponseOneofCase 
 . 
 SmartCampaignSettingResult 
 : 
  
 resourceName 
  
 = 
  
 operationResponse 
 . 
 SmartCampaignSettingResult 
 . 
 ResourceName 
 ; 
  
 break 
 ; 
  
 case 
  
 MutateOperationResponse 
 . 
 ResponseOneofCase 
 . 
 AssetResult 
 : 
  
 resourceName 
  
 = 
  
 operationResponse 
 . 
 AssetResult 
 . 
 ResourceName 
 ; 
  
 break 
 ; 
  
 case 
  
 MutateOperationResponse 
 . 
 ResponseOneofCase 
 . 
 AssetGroupAssetResult 
 : 
  
 resourceName 
  
 = 
  
 operationResponse 
 . 
 AssetGroupAssetResult 
 . 
 ResourceName 
 ; 
  
 break 
 ; 
  
 case 
  
 MutateOperationResponse 
 . 
 ResponseOneofCase 
 . 
 AssetGroupResult 
 : 
 < 
 res>ourceName 
  
 = 
  
 operationResponse 
 . 
 AssetGroupResult 
 . 
 ResourceName 
 ; 
  
 break 
 ; 
  
 case 
  
 MutateOperationResponse 
 . 
 ResponseOneofCase 
 . 
 AssetGroupListingGroupFilterResult 
 : 
   
 
 resourceName 
  
 = 
  
 operatio 
 
nResponse . AssetGroupListingGroupFilterResult . ResourceName ; break ; case MutateOperationResponse . ResponseOneofCase . CampaignConversionGoalResult : resourceName = operationResponse . CampaignConversionGoalResult . ResourceName ; break ; case MutateOperationResponse . ResponseOneofCase . CustomerConversionGoalResult : resourceName = operationResponse . CustomerConversionGoalResult . ResourceName ; break ; default : resourceName = "not found" ; break ; } Console . WriteLine ( $"Created a(n) {entityName} with resource name: '{resourceName}'." ); } } } } AddPerformanceMaxRetailCampaign . cs

PHP

< ?php 
 /** 
 * 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 
 * 
 *     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. 
 */ 
 namespace Google\Ads\GoogleAds\Examples\ShoppingAds; 
 require __DIR__ . '/../../vendor/autoload.php'; 
 use GetOpt\GetOpt; 
 use Google\Ads\GoogleAds\Examples\Utils\ArgumentNames; 
 use Google\Ads\GoogleAds\Examples\Utils\ArgumentParser; 
 use Google\Ads\GoogleAds\Examples\Utils\Helper; 
 use Google\Ads\GoogleAds\Lib\OAuth2TokenBuilder; 
 use Google\Ads\GoogleAds\Lib\V21\GoogleAdsClient; 
 use Google\Ads\GoogleAds\Lib\V21\GoogleAdsClientBuilder; 
 use Google\Ads\GoogleAds\Lib\V21\GoogleAdsException; 
 use Google\Ads\GoogleAds\Util\FieldMasks; 
 use Google\Ads\GoogleAds\Util\V21\ResourceNames; 
 use Google\Ads\GoogleAds\V21\Common\ImageAsset; 
 use Google\Ads\GoogleAds\V21\Common\LanguageInfo; 
 use Google\Ads\GoogleAds\V21\Common\LocationInfo; 
 use Google\Ads\GoogleAds\V21\Common\MaximizeConversionValue; 
 use Google\Ads\GoogleAds\V21\Common\TextAsset; 
 use Google\Ads\GoogleAds\V21\Enums\AdvertisingChannelTypeEnum\AdvertisingChannelType; 
 use Google\Ads\GoogleAds\V21\Enums\AssetFieldTypeEnum\AssetFieldType; 
 use Google\Ads\GoogleAds\V21\Enums\AssetGroupStatusEnum\AssetGroupStatus; 
 use Google\Ads\GoogleAds\V21\Enums\BudgetDeliveryMethodEnum\BudgetDeliveryMethod; 
 use Google\Ads\GoogleAds\V21\Enums\CampaignStatusEnum\CampaignStatus; 
 use Google\Ads\GoogleAds\V21\Enums\ConversionActionCategoryEnum\ConversionActionCategory; 
 use Google\Ads\GoogleAds\V21\Enums\ConversionOriginEnum\ConversionOrigin; 
 use Google\Ads\GoogleAds\V21\Enums\EuPoliticalAdvertisingStatusEnum\EuPoliticalAdvertisingStatus; 
 use Google\Ads\GoogleAds\V21\Enums\ListingGroupFilterListingSourceEnum\ListingGroupFilterListingSource; 
 use Google\Ads\GoogleAds\V21\Enums\ListingGroupFilterTypeEnum\ListingGroupFilterType; 
 use Google\Ads\GoogleAds\V21\Errors\GoogleAdsError; 
 use Google\Ads\GoogleAds\V21\Resources\Asset; 
 use Google\Ads\GoogleAds\V21\Resources\AssetGroup; 
 use Google\Ads\GoogleAds\V21\Resources\AssetGroupAsset; 
 use Google\Ads\GoogleAds\V21\Resources\AssetGroupListingGroupFilter; 
 use Google\Ads\GoogleAds\V21\Resources\Campaign; 
 use Google\Ads\GoogleAds\V21\Resources\Campaign\ShoppingSetting; 
 use Google\Ads\GoogleAds\V21\Resources\CampaignAsset; 
 use Google\Ads\GoogleAds\V21\Resources\CampaignBudget; 
 use Google\Ads\GoogleAds\V21\Resources\CampaignConversionGoal; 
 use Google\Ads\GoogleAds\V21\Resources\CampaignCriterion; 
 use Google\Ads\GoogleAds\V21\Services\AssetGroupAssetOperation; 
 use Google\Ads\GoogleAds\V21\Services\AssetGroupListingGroupFilterOperation; 
 use Google\Ads\GoogleAds\V21\Services\AssetGroupOperation; 
 use Google\Ads\GoogleAds\V21\Services\AssetOperation; 
 use Google\Ads\GoogleAds\V21\Services\CampaignAssetOperation; 
 use Google\Ads\GoogleAds\V21\Services\CampaignBudgetOperation; 
 use Google\Ads\GoogleAds\V21\Services\CampaignConversionGoalOperation; 
 use Google\Ads\GoogleAds\V21\Services\CampaignCriterionOperation; 
 use Google\Ads\GoogleAds\V21\Services\CampaignOperation; 
 use Google\Ads\GoogleAds\V21\Services\GoogleAdsRow; 
 use Google\Ads\GoogleAds\V21\Services\MutateGoogleAdsRequest; 
 use Google\Ads\GoogleAds\V21\Services\MutateGoogleAdsResponse; 
 use Google\Ads\GoogleAds\V21\Services\MutateOperation; 
 use Google\Ads\GoogleAds\V21\Services\MutateOperationResponse; 
 use Google\Ads\GoogleAds\V21\Services\SearchGoogleAdsRequest; 
 use Google\ApiCore\ApiException; 
 use Google\ApiCore\Serializer; 
 /** 
 * This example shows how to create a Performance Max retail campaign. 
 * 
 * This will be created for "All products". 
 * 
 * For more information about Performance Max retail campaigns, see 
 * https://developers.google.com/google-ads/api/docs/performance-max/retail. 
 * 
 * Prerequisites: 
 * - You need to have access to a Merchant Center account. You can find 
 * instructions to create a Merchant Center account here: 
 * https://support.google.com/merchants/answer/188924. 
 * This account must be linked to your Google Ads account. The integration 
 * instructions can be found at: 
 * https://developers.google.com/google-ads/api/docs/shopping-ads/merchant-center 
 * - You need your Google Ads account to track conversions. The different ways 
 * to track conversions can be found here: 
 * https://support.google.com/google-ads/answer/1722054. 
 * - You must have at least one conversion action in the account. For more about conversion 
 * actions, see 
 * https://developers.google.com/google-ads/api/docs/conversions/overview#conversion_actions. 
 */ 
 class AddPerformanceMaxRetailCampaign 
 { 
 private const CUSTOMER_ID = 'INSERT_CUSTOMER_ID_HERE'; 
 private const MERCHANT_CENTER_ACCOUNT_ID = 'INSERT_MERCHANT_CENTER_ACCOUNT_ID_HERE'; 
 // The final URL for the generated ads. Must have the same domain as the Merchant Center 
 // account. 
 private const FINAL_URL = 'INSERT_FINAL_URL_HERE'; 
 // Optional: Indicates whether the created campaign is enabled for brand guidelines. 
 private const BRAND_GUIDELINES_ENABLED = false; 
 // We specify temporary IDs that are specific to a single mutate request. 
 // Temporary IDs are always negative and unique within one mutate request. 
 // 
 // See https://developers.google.com/google-ads/api/docs/mutating/best-practices 
 // for further details. 
 // 
 // These temporary IDs are fixed because they are used in multiple places. 
 private const BUDGET_TEMPORARY_ID = -1; 
 private const PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID = -2; 
 private const ASSET_GROUP_TEMPORARY_ID = -3; 
 // There are also entities that will be created in the same request but do not need to be fixed 
 // temporary IDs because they are referenced only once. 
 /** @var int the negative temporary ID used in bulk mutates. */ 
 private static $nextTempId = self::ASSET_GROUP_TEMPORARY_ID - 1; 
 public static function main() 
 { 
 // Either pass the required parameters for this example on the command line, or insert them 
 // into t>he constants above. 
 $options = (new ArgumentParser())-pa>rseCommandArguments([ 
 ArgumentNames::CUSTOMER_ID = GetOpt::REQUIRED_ARG>UMENT, 
 ArgumentNames::MERCHANT_CENTER_ACCOUNT_ID = Get>Opt::REQUIRED_ARGUMENT, 
 ArgumentNames::FINAL_URL = GetOpt::REQUIRED_A>RGUMENT, 
 ArgumentNames::BRAND_GUIDELINES_ENABLED = GetOpt::OPTIONAL_ARGUMENT 
 ]); 
 // Generate a refreshable OAuth2 credential for authentic>ation. 
 >    $oAuth2Credential = (new OAuth2TokenBuilder())-fromFile()-build(); 
 // Construct a Google Ads client configured from a properties file and the 
 // OAuth2 credentials above. 
 $>googleAdsClient = (new G>oogleAdsClientBuilder()) 
 -fromFile() 
 >        -withOAuth2Credential($oAuth2Credential) 
 -build(); 
 try { 
 self::runExample( 
 $googleAdsClient, 
 $options[ArgumentNames::CUSTOMER_ID] ?: self::CUSTOMER_ID, 
 $options[ArgumentNames::MERCHANT_CENTER_ACCOUNT_ID] 
 ?: self::MERCHANT_CENTER_ACCOUNT_ID, 
 $options[ArgumentNames::FINAL_URL] ?: self::FINAL_URL, 
 filter_var( 
 $options[ArgumentNames::BRAND_GUIDELINES_ENABLED] 
 ?: self::BRAND_GUIDELINES_ENABLED, 
 FILTER_VALIDATE_BOOLEAN 
 ) 
 ); 
 } catch (GoogleAdsException $googleAdsException) { 
 printf( 
 "Request with ID '%s' has fa>iled.%sGoogle Ads failure details:%s", 
 $googleAdsException-getRequestId(), 
 PHP_EOL, 
> PHP_EO>L 
 ); 
 foreach ($googleAdsException-getGoogleAdsFailure()-getErrors() as $error) { 
 /** @var GoogleAdsError $error */ 
 >           prin>tf( 
 "\t%s: %s%s&qu>ot;, 
 $error-getErrorCode()-getErrorCode(), 
 $error-getMessage(), 
 PHP_EOL 
 ); 
 } 
 exit(1); 
 } catch (ApiException $apiException) { 
 printf( 
 >            "ApiException was thrown with message '%s'.%s", 
 $apiException-getMessage(), 
 PHP_EOL 
 ); 
 exit(1); 
 } 
 } 
 /** 
 * Runs the example. 
 * 
 * @param GoogleAdsClient $googleAdsClient the Google Ads API client 
 * @param int $customerId the customer ID 
 * @param int $merchantCenterAccountId the Merchant Center account ID 
 * @param string $finalUrl the final URL for the asset group of the campaign 
 * @param bool $brandGuidelinesEnabled whether the created campaign will be enabled for brand 
 *      guidelines 
 */ 
 public static function runExample( 
 GoogleAdsClient $googleAdsClient, 
 int $customerId, 
 int $merchantCenterAccountId, 
 string $finalUrl, 
 bool $brandGuidelinesEnabled 
 ) { 
 // This campaign will override the customer conversion goals. 
 // Retrieves the current list of customer conversion goals. 
 $customerConversionGoals = self::getCustomerConversionGoals( 
 $googleAdsClient, 
 $customerId 
 ); 
 // Performance Max campaigns require that repeated assets such as headlines 
 // and descriptions be created before the campaign. 
 // For the list of required assets for a Performance Max campaign, see 
 // https://developers.google.com/google-ads/api/docs/performance-max/assets. 
 // 
 // Creates the headlines. 
 $headlineAssetResourceNames = self::createMultipleTextAssets( 
 $googleAdsClient, 
 $customerId, 
 ["Travel", "Travel Reviews", "Book travel"] 
 ); 
 // Creates the descriptions. 
 $descriptionAssetResourceNames = self::createMultipleTextAssets( 
 $googleAdsClient, 
 $customerId, 
 ["Take to the air!", "Fly to the sky!"] 
 ); 
 // It's important to create the below entities in this order because they depend on 
 // each other. 
 $operations = []; 
 // The below methods create and return MutateOperations that we later 
 // provide to the GoogleAdsService.Mutate method in order to create the 
 // entities in a single request. Since the entities for a Performance Max 
 // campaign are closely tied to one-another, it's considered a best practice 
 // to create them in a single Mutate request so they all complete 
 // successfully or fail entirely, leaving no orphaned entities. See: 
 // https://developers.google.com/google-ads/api/docs/mutating/overview. 
 $operations[] = self::createCampaignBudgetOperation($customerId); 
 $operations[] = self::createPerformanceMaxCampaignOperation( 
 $customerId, 
 $merchantCenterAccountId, 
 $brandGuidelinesEnabled 
 ); 
 $operations = 
 array_merge($operations, self::createCampaignCriterionOperations($customerId)); 
 $operations[] = self::createAssetGroupOperation($customerId, $finalUrl); 
 $operations[] = self::createAssetGroupListingGroupFilterOperation($customerId); 
 $operations = array_merge($operations, self::createAssetandAssetGroupAssetOperations( 
 $customerId, 
 $headlineAssetResourceNames, 
 $descriptionAssetResourceNames, 
 $brandGuidelinesEnabled 
 )); 
 $operations = array_merge($operations, self::createConversionGoalOperations( 
 $customerId, 
 $custom>erConversionGoals 
 )); 
 // Issues a mutate request to crea>te everything and prints its information. 
 $googleAdsServiceClient = $googleAdsClient-getGoogleAdsServiceClient(); 
 $response = $googleAdsServiceClient-mutate( 
 MutateGoogleAdsRequest::build($customerId, $operations) 
 ); 
 self::printResponseDetails($response); 
 } 
 /** 
 * Creates a MutateOperation that creates a new CampaignBudget. 
 * 
 * A temporary ID will be assigned to this campaign budget so that it can be 
 * referenced by other objects being created in the same Mutate request. 
 * 
 * @param int $customerId the customer ID 
 * @return MutateOperation the mutate operation that creates a campaign budget 
 */ 
 private static function createCampaignBudgetOperation(int $customerId): MutateOperatio>n 
 { 
 // Creates a mutate operation that create>s a campaign budget operation. 
 return new MutateOperation([ 
 'campaign_budget_operation' = new CampaignBudgetOperation([ 
 'create' = new CampaignBudget([ 
 >             // Sets a temporary ID in the budget's resource name so it can be referenced 
 // by the campaign in later steps. 
 '>;resource_name' = ResourceNames::forCampaignBudget( 
 $customerId, 
 self::BUDGET_TEMPORARY_ID 
 ), 
 'name' = '>;Performance Max retail campaign budget #' . 
 >                       Helper::getPrintableDatetime(), 
 // The budget period already defaults to DAILY. 
 'amount_micros>' = 50000000, 
 'delivery_method' = BudgetDeliveryMethod::STANDARD, 
 // A Performance Max campaign cannot use a shared campaign budget. 
 'explicitly_shared' = false 
 ]) 
 ]) 
 ]); 
 } 
 /** 
 * Creates a MutateOperation that creates a new Performance Max campaign. 
 * 
 * A temporary ID will be assigned to this campaign so that it can 
 * be referenced by other objects being created in the same Mutate request. 
 * 
 * @param int $customerId the customer ID 
 * @param int $merchantCenterAccountId the Merchant Center account ID 
 * @param bool $brandGuidelinesEnabled whether the created campaign will be enabled for brand 
 *      guidelines 
 * @return MutateOperation the mutate operation that creates the campaign 
 */ 
 private static function createPerformanceMaxCampaignOperation( 
 int $customerId, 
 in>t $merchantCenterAccountId, 
 bool $brandGuid>elinesEnabled 
 ): MutateOperation { 
 >   // Creates a mutate operation that creates a campaign operation. 
 return new MutateOperation([ 
 'campaign_operation' = new CampaignOperation([ 
 >          'create' = new Campaign([ 
 'name' = 'Performance Max retail campaign #' . Helper::getPrintableDatetime(), 
 // Assigns the resource name with a temporary ID. 
 'resource_name' >= ResourceNames::forCampaign( 
 $customerId, 
 self::PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 ), 
 // Sets the budget using the given budget resource name. 
 'campaign_budget' = ResourceNames::forCampaignBudget( 
 $customerId, 
 self::BUDGET_TEMPORARY_ID 
 ), 
 // The campa>ign is the only entity in the mutate request that should have its 
 // status set. 
 // Recommendation: Set the campaign to PAUSED when creating it to prevent 
 // the ads from immediately serving. 
 >                  'status' = CampaignStatus::PAUSED, 
 // All Performance Max campaigns have an advertising_channel_type of 
 // PERFORMANCE_MAX. The advertising_channel_sub_type should not be set. 
 'advertising_channel_type' = AdvertisingChannelType::PERFORMANCE_MAX, 
 // Bidding strategy must be set directly on the campaign. 
 // Setting a portfolio bidding strategy by resource name is not supported. 
 // Max Conversion and Max Conversion Value are the only strategies supported 
 // for Performance Max campaigns. 
 // An optional ROAS (Return on Advertising Spend) can be set for 
 // maximize_conversion_value. The ROAS value must be specified as a ratio in 
 // the API. It is calculated by dividing "total value" by "total >spend". 
 // For more information on Max Conver>sion Value, see the support article: 
 // http://support.google.com/google-ads/answer/7684216. 
 // A target_roas of 3.5 corresponds to a 350% return on ad spend. 
 'maximize_conversion_value' = new MaximizeConversionValue([ 
 'target_roas' = 3.5 
 ]), 
 // Be>low is what you would use if you want to maximize conversions 
 // You can optionally set the 'target_cpa_micros' field on MaximizeConversions. 
 // This is the average amount that you would like to spend per conversion 
 // action. 
 // 'maximize_conversions' = new MaximizeConversions(), 
 // Sets the Final URL expansion opt out. This flag is specific to 
 // Performance Max campaigns. If opted out (true), only the final URLs in 
 // the asset group or URLs specified in the advertiser's Google Merchant 
 // Center or business data feeds are targeted. 
 // 
 // If opted in (false), the entire domain will be targeted. For best 
 // results, set this value to f>alse to opt in and allow URL expansions. You 
 // can optionally add exclusions to limit traffic to parts of your website. 
 // 
 // For a Retail campaign, we want the final URL's to be limited to those 
 > // explicitly surfaced via GMC. 
 'url_expansion_opt_out' = true, 
 // S>ets if the campaign is enabled for brand guidelines. For more >information 
 // on brand guidelines, see 
 // https://support.google.com/google-ads/answer/14934472. 
 'brand_guidelines_enabled' = $brandGuidelinesEnabled, 
 // Sets the shopping settings. 
 'shopping_setting' = new ShoppingSetting([ 
 'merchant_id' = $merchantCenterAcco>untId, 
 // Optional: To use products only from a specific feed, set feed_label to 
 // the feed label used in Merchant Center. 
 // See: ht>tps://support.google.com/merchants/answer/12453549. 
 // Removing the feed_label field will use products from all feeds. 
 // &>#39;feed_label' = 'INSERT_FEED_LABEL_HERE' 
 >        ]), 
 // Declare whether or not this campaign serves political ads targeting the EU. 
 'contains_eu_political_advertising' = 
 EuPoliticalAdvertisingStatus::DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING 
 // Optional fields. 
 'start_date' = date('Ymd', strtotime('+1 day')), 
 'end_date' = date('Ymd', strtotime('+365 days')) 
 ]) 
 ]) 
 ]); 
 } 
 /** 
 * Creates a list of MutateOperations that create new campaign criteria. 
 * 
 * @param int $customerId the customer ID 
 * @return MutateOperation[] a list of MutateOperations that create the new campaign criteria 
 */ 
 private static function createCampaignCriterionOperations(int $customerId): array 
 { 
 $operations = []; 
 // Sets the LOCATION campaign> criteria. 
 // Target all of New York City except Bro>oklyn. 
 // Location IDs are listed here: 
 />/ https://developers.google.com/google-ads/api/reference/data/geotargets 
 // and they can also be retrieved using the GeoTargetConstantService as shown 
 // here: https://devel>opers.google.com/google-ads/api/docs/targeting/location-targeting 
 $operations[] = new MutateOperation([ 
 'campaign_criterion_operation' = new CampaignCriterionOperation([ 
 'create' = new CampaignCriterion>([ 
 'campaign' = ResourceNames::forCampaign( 
 $custo>merId, 
 self::PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 ), 
 'location' = new LocationInfo([ 
 // Adds one posit>ive location target for New York City (ID=1023191), 
 >                // specifically adding the positive crite>ria before the negative one. 
 'geo_target_constant' = ResourceNames::forGeoTargetConstant(1023191) 
 ]), 
 'negative&#>39; = false 
 ]) 
 ]) 
 ]); 
 // Next adds the negative target for Brooklyn. 
 $operations[] = new MutateOp>eration([ 
 'campaign_criterion_operation' = new CampaignCriterionOperation([ 
 >          'create' = new CampaignCriterion([ 
 'campaign' = ResourceNames::forCampaign( 
 $customerId, 
 self::PER>FORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 ), 
 >                  'location' = new LocationInfo([ 
> // Next add the negative target for Brooklyn (ID=1022762). 
 'geo_target_constant' = ResourceNames::forGeoTargetConstant(1022762) 
 ]), 
 'negative' = true 
 ]) 
 ]) 
 ]); 
 // Sets the LANGUAGE campaign criterion. 
 $operations[] = new MutateOperation([ 
 >      'campaign_criterion_operation' = new CampaignCriter>ionOperation([ 
 'create' = new CampaignCriterion([ 
 'campaign' = ResourceNames::forCampaign( 
 $customerId, 
 self::PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 ), 
 // Sets the language. 
 // For a list of all language codes, see: 
 // https://developers.google.com/google-ads/api/reference/data/codes-formats#expandable-7 
 'language' = new LanguageInfo([ 
 'language_constant' = ResourceNames::forLanguageConstant(1000)  // English 
 ]) 
 ]) 
 ]) 
 ]); 
 return $operations; 
 } 
 /** 
 * Creates multiple text assets and returns the list of resource names. 
 * 
 * These repeated assets must be created in a separate request prior to creating the campaign. 
 * 
 * @param GoogleAdsClient $googleAdsClient the Google Ads API client 
 * @param int $customerId the customer ID 
 * @param string[] $texts a list of s>trings, each of which will be used to create a text >asset 
 * @return strin>g[] a list of asset reso>urce names 
 */ 
 private static function createMultipleTextAssets( 
 GoogleAdsClient $googleAdsClient, 
 int $customerId, 
 array $texts 
 >   ): array { 
 // Here again, we use the GoogleAdService to create multiple text assets in a single 
 // request. 
 $operations = []; 
 >    foreach ($texts as $text) { 
 // Creates a mutate operation for a text asset. 
 $operations[] = new MutateOperation([ 
 'a>sset_operation' = new AssetOperation([ 
 'create' = new Asset(['text_asset' = new TextAsset(['text' = $t>ext])]) 
 >       ]) 
 ]); 
 } 
 // Issues a mutate request to add all assets. 
 $googleAdsServiceClient = $googleAdsClient-getGoogleAdsServiceClient(); 
 /** @var MutateGoogleAdsResponse $mutateGoogleAdsResponse */ 
 $mutateGoogleAdsResponse = $googleAdsServiceClient-mutate( 
 MutateGoogleAdsRequest::build($customerId, $operations) 
 ); 
 $assetResourceNames = []; 
 foreach ($mutateGoogleAdsResponse-getMutateOperationResponses() as $response) { 
 /** @var MutateOperationResponse $response */ 
 $assetResourceNames[] = $response-getAssetResult()-getResourceName(); 
 } 
 self::printResponseDetails($mutateGoogleAdsResponse); 
 return $assetResourceNames; 
 } 
 /** 
 * Creates a Mu>tateOperation that creates a new asset group. 
 * 
> * A temporary ID will be assigned to this asset gr>oup so that it can 
 * be referenced by other objects being created in the same Mutate request. 
 * 
 * @param int $customerId the customer ID 
 * @return MutateO>peration a mutate operation creates a new asset group. 
 */ 
 private static function createAssetGroupOperation( 
 int >$customerId, 
 string $finalUrl 
 ): MutateOperation { 
 // Creates a new mutate operation that creates an asset group operation. 
 return new MutateOperation([ 
 >  'asset_group_operation' = new AssetGroupOpera>tion([ 
 'create' = ne>w AssetGroup([ 
 'resource_name' = ResourceNames::forAssetGroup( 
 $customerId, 
 self::ASSET_GROUP_TEMPORARY_ID 
 ), 
 'name' = 'Performance Max retail asset group #' . 
 Helper::getPrintableDatetime(), 
 'campaign' = ResourceNames::forCampaign( 
 $customerId, 
 self::PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 ), 
 'final_urls' = [$finalUrl], 
 'final_mobile_urls' = [$finalUrl], 
 'status' = AssetGroupStatus::PAUSED 
 >          ]) 
 ]) 
 ]); 
 } 
 /** 
 * Creates a MutateOperation that creates a new asset group listing group filter. 
 * 
 * A temporary ID will be assigned to this listing group fi>lter so that it can be referenced by 
 * other objects being created> in the same Mutate request. 
 * 
 * @param int $customerId the customer ID 
 * @return MutateOperation a MutateOperation that creates a new asset group listing group filter 
 */ 
 private static function createAssetGroupListingGroupFilterOperation( 
 int $customerId 
 ): MutateOperation { 
 return new MutateOperation([ 
 'asset_group_listing_group_filter_operation' 
 = new AssetGroupListingGroupFilterOperation([ 
 // Creates a new> asset group listing group filter containing the "default" 
 // listing group (All products). 
 'create' = new AssetGroupListingGroupFilter([ 
 'asset_group' = ResourceNam>es::forAssetGroup( 
 $customerId, 
 self::ASSET_GROUP_TEMPORARY_ID 
 ), 
 // Since this is the root node, do not set the 'parent_listing_group_filter' 
 // field. For all other nodes, this would refer to the parent listing group 
 // filter resource name. 
 // 
 // UNIT_INCLUDED means this node has no children. 
 'type' = ListingGroupFilterType::UNIT_INCLUDED, 
 // Because this is a Performance Max campaign for retail, we need to specify 
 // that this is in the shopping listing source. 
 'listing_source' = ListingGroupFilterListingSource::SHOPPING 
 ]) 
 ]) 
 ]); 
 } 
 /** 
 * Creates a list of MutateOperations that create new asset group asset and assets. 
 * 
 * A temporary ID will be assigned to this asset group so that it can 
 * be referenced by other objects being created in the same mutate request. 
 * 
 * @param int $customerId the customer ID 
 * @param string[] $headlineAssetResourceNames a list of headline resource names 
 * @param string[] $descriptionAssetResourceNames a list of description resource names 
 * @param bool $brandGuidelinesEnabled whether the created campaign will be enabled for brand 
 *      guidelines 
 * @return MutateOperation[] a list of MutateOperations that create new asset group assets and 
 *     assets 
 */ 
 private static function createAssetandAssetGroupAssetOperations( 
 int $customerId, 
 array $headlineAssetResourceNames, 
 array $descriptionAssetResourceNames, 
 bool $brandGuidelinesEnabled 
 ): array { 
 $operations = []; 
 // For the list of required assets for a Performance Max campaign, see 
 >     // https://developers.google.com/google-ads/api/docs/perf>ormance-max/assets 
 // An AssetGroup is linked t>o an Asset by creating a new AssetGroupAsset 
 //> and providing: 
 // -  the resource name of the AssetGroup 
 // -  the resource name of the Asset 
 // -  the field_type of the Asset in this AssetGroup. 
 // 
 // T>o learn more about AssetGroups, see 
 // https://developers.google.com/google-ads/api/docs/performance-max/asset-groups. 
 // Links the previously created multiple text assets. 
 // Links the headline assets. 
 foreach ($headlineAssetResourceNames as $resourceName) { 
 >      $operations[] = new MutateOperation([ 
 &#>39;asset_group_asset_operation' = new AssetGroupAsse>tOperation([ 
 'create' = new> AssetGroupAsset([ 
 'asset' = $resourceName, 
 'asset_group' = ResourceNames::forAssetGroup( 
 $customerId, 
 >                           self::ASSET_GROUP_TEMPORARY_ID 
 ), 
 'field_type' = AssetFieldType::HEADLINE 
 ]) 
 ]) 
 ]); 
 } 
 // Links the description assets. 
 foreach ($descriptionAssetResourceNames as $resourceName) { 
 $operations[] = new MutateOperation([ 
 'asset_group_asset_operation' = new AssetGroupAssetOperation([ 
 'create' = new AssetGroupAsset([ 
 'asset' = $resourceName, 
 'asset_group' = ResourceNames::forAssetGroup( 
 $customerId, 
 self::ASSET_GROUP_TEMPORARY_ID 
 ), 
 'field_type' = AssetFieldType::DESCRIPTION 
 ]) 
 ]) 
 ]); 
 } 
 // Creates and links the long headline text asset. 
 $operations = array_merge($operations, self::createAndLinkTextAsset( 
 $customerId, 
 'Travel the World', 
 AssetFieldType::LONG_HEADLINE 
 )); 
 // Creates and links the business name text asset. 
 $operations = array_merge($operations, self::createAndLinkBrandAssets( 
 $customerId, 
 $brandGuidelinesEnabled, 
 'Interplanetary Cruises', 
 'https://gaagl.page.link/1Crm', 
 'Logo Image' 
 )); 
 // Creates and links the image assets. 
 // Creates and links the Marketing Image Asset. 
 $operations = array_merge($operations, self::createAndLinkImageAsset( 
 $customerId, 
 'https://gaagl.page.link/Eit5', 
 AssetFieldType::MARKETING_IMAGE, 
 'Marketing Image' 
 )); 
 // Creates and links the Square Marketing Image Asset. 
 $operations = array_merge($operations, self::createAndLinkImageAsset( 
 $customerId, 
 'https://gaagl.page.link/bjYi', 
 AssetFieldType::SQUARE_MARKETING_IMAGE, 
 'Square Marketing Image' 
 )); 
 // After being created the list must be sorted so that a>ll asset operations come before all 
 // t>he asset group asset operations, otherwise the API> will reject the request. 
 return self::sortAssetAndAssetGroupAssetOperations($operat>ions); 
 } 
 /** 
 >   * Creates a list of MutateOperations that create a new linked text asset. 
 * 
 * @param int $customerId the customer ID 
 * @param string $text the text of the asset to be created 
 * @param int $fieldType t>he field type of the new asset in the AssetGroupAsset 
 > * @return MutateOperation[] a list of MutateOperati>ons that create a new linked text asset 
 */ 
 private static function createAndLinkText>Asset( 
 int $customerId, 
 string $text, 
 int $fieldType 
 ): array { 
 $operations = []; 
 // Creates a new mutate operation that creates a text >asset. 
 $operations[] = new MutateOperation([ 
 'asset_operation' = new AssetOperation([ 
 'create' = new Asset([ 
 'resource_name' = ResourceNames::forAsset($customerId, self::$nextTempId), 
 'text_asset' = new TextAsset(['text' = $text]) 
 ]) 
 ]) 
 ]); 
 // Creates an asset group asset to link the asset to the asset group. 
 $operations[] = new MutateOperation([ 
 'asset_group_asset_operation' = new AssetGroupAssetOperation([ 
 'create' = new AssetGroupAsset([ 
 'asset' = ResourceNames::forAsset($customerId, self::$nextTempId), 
 'asset_group' = ResourceNames::forAssetGroup( 
 $customerId, 
 self::ASSET_GROUP_TEMPORARY_ID 
 >                ), 
 'fiel>d_type' = $fieldType 
 ]) 
 >      ]) 
 ]); 
 self::$nextTempId--; 
 return $operations; 
 } 
 /** 
 * Creates a list of MutateOperations that create a new linked image asset. 
 * 
 * @param int $customerId the customer ID 
 * @param string $url the URL of the image to be retrieved and put into an asset 
 * @param int $>fieldType the field type of the new asset in the> AssetGroupAsset 
 * @>param string $assetName the asset name 
 * @return MutateOperation[] a list of MutateOperations that create a new linked image asset 
 */ 
 private static function createAndLinkImageAsset( 
 int $customerId, 
 string $url>, 
 int $fieldType, 
 string $assetName 
 ):> array { 
 $operations = []; 
 // Create>s a new mutate operation that creates an image asset. 
 $operations[] = new MutateOpera>tion([ 
 'asset_operation' = new AssetOperation([ 
 'create' = new Asset([ 
 'resource_name' = ResourceNames::forA>sset($customerId, self::$nextTempId), 
 // Provide a unique friendly name to identify your asset. 
 // When there is an existing image asset with the same content but a different 
 // name, the new name will be dropped silently. 
 'name' = $assetName, 
 'image_asset' = new ImageAsset(['data' = file_get_contents($url)]) 
 ]) 
 ]) 
 ]); 
 // Creates an asset group asset to link the asset to the asset group. 
 $operations[] = new MutateOperation([ 
 'asset_group_asset_operation' = new AssetGroupAssetOperation([ 
 'create' = new AssetGroupAsset([ 
 'asset' = ResourceNames::forAsset($customerId, self::$nextTempId), 
 'asset_group' = ResourceNames::forAssetGroup( 
 $customerId, 
 self::ASSET_GROUP_TEMPORARY_ID 
 ), 
 'field_type' = $fieldType 
 ]) 
 ]) 
 ]); 
 self::$n>extTempId--; 
 return $operations; 
 } 
> /** 
 * Creates a list of MutateOperations> that create linked brand assets. 
 * 
 * @param int $customerId the customer ID 
 * >@param bool $brandGuidel>inesEnabled whether the created campaign will be enabled for brand 
 *     guidelines 
 * @param string $businessName the business name text to be put into an asset 
 * @param string $logoUrl the URL of the logo to be retrieved and put into an as>set 
 * @param string $logoName the asset nam>e of the logo 
 * @return MutateOperation[] a l>ist of MutateOperations that create a new linked text asset 
 */ 
 private static function createAndLinkBrandAssets( 
 int $customerId, 
 bool $brandGuidelinesEnabled, 
 string $businessName, 
 string $logoUrl, 
 string $logoName 
 ): array { 
 $operations = []; 
 // Creates >a new mutate operation that creates a text asse>t. 
 $businessNameT>empId = self::$nextTempId--; 
 $operations[] = new MutateOperation([ 
 'asset_operation' = new AssetOperation([ 
 'create' = new Asset([ 
 'resource_name' = ResourceNames::forAsset($customerId, $businessNameTempId), 
 &#>39;text_asset' = new TextAsset(['text' = $busine>ssName]) 
 ]) 
 ]) 
 ]); 
> $logoTempId = self::$nextTempId--; 
 // Creates a new mutate operation that crea>tes an image asset. 
 $operations[] = new MutateOperation([ 
 'asset_operation' = new AssetOperation([ 
 'create' = new Asset([ 
 'resource>_name' = ResourceNames::forAsset($customerId, $logoTempId), 
 // Provide a unique friendly name to identify your asset. 
 // When there is an e>xisting image asset with the same content but a different 
 >                  // name, the new name will be droppe>d silently. 
 'name' = $logoName, 
 'ima>ge_asset' = new ImageAsset(['data' = file_get_contents($logoUrl)]) 
 ]) 
 ]) 
 ]); 
 if ($brandGuidelinesEnabled) { 
 // Creates a campaign asset to> link the business name and logo assets to the campaign. 
 $operations[] = new MutateOperation([ 
 'campaign_asset_operation' = new CampaignAssetOperation([ 
 'create' = new CampaignAsset([ 
 'asset' = ResourceNames::forAsset($>customerId, $businessNameTempId), 
 '>;campaign' = ResourceNames::forCampaign( 
 >                 $customerId, 
 self::PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_>ID 
 ), 
 'field_type' = AssetFieldType::BUSINESS_NAME 
 ]) 
 ]) 
 ]); 
 $operations[] = new> MutateOperation([ 
 'campaign_asset_operation' = new CampaignAssetOperation([ 
 'create' = new CampaignAsset([ 
 &#>39;asset' = ResourceNames::forAsset($customerId, $logoTemp>Id), 
 'campaign' = Resour>ceNames::forCampaign( 
 $customerId, 
 >self::PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 ), 
 'field_type' = AssetFieldType::LOGO 
 ]) 
 ]) 
 ]); 
> } else { 
 // Creates an asset group asset to link the business name and logo assets to the asset 
 // group. 
 $operations[] = new MutateOperation([ 
 'asset_group_asset_operation' = new AssetGroupAssetOperation([ 
 'create' = new AssetGroupAsset([ 
 'asset' = ResourceNames::forAsset($customerId, $businessNameTempId), 
 'asset_group' = ResourceNames::forAssetGroup( 
 $customerId, 
 self::ASSET_GROUP_TEMPORARY_ID 
 ), 
 'field_type' = AssetFieldType::BUSINESS_NAME 
 ]) 
 ]) 
 ]); 
 $operations[] = new MutateOperation([ 
 'asset_group_asset_>operation' = new AssetGroupAssetOperation([ 
 'create' = new AssetGroupA>sset([ 
 'asset' = ResourceNames::forAsset($customerId, $logoTempId), 
 'asset_group' = ResourceNames::forAssetGroup( 
 $customerId, 
 self::ASSET_GROUP_TEMPORARY_ID 
 ), 
 'field_type' = AssetFieldType::LOGO 
 ]) 
 ]) 
 ]); 
 } 
 return $operations; 
 } 
 /** 
 * Sorts a list of asset and asset group asset operations. This sorts the list such that all 
 * asset operations precede all asset group asset operations. If asset group assets are created 
 * before assets then an e>rror will be returned by the API. 
 * 
 * @param MutateOperation[] $operations a list of asset and asset group asset mutate operations 
 * @return MutateOperation[] a sorted list of asset and asset group asset mutate operations 
 */ 
 private static function sortAssetAndAssetGroupAssetOperations(array $operations): array 
 { 
 usort( 
 $operations, 
 function (MutateOperation $operation>1, MutateOperation $operation2) { 
 if (!is_null($operation1-getAssetOperation())) { 
 return -1; 
 } elseif (!is_null($operation1>-getAssetOperation())) { 
 return 0; 
 } else { 
 return 1; 
 } 
 } 
 ); 
 re>turn $operation>s; 
 } 
 /** 
 * Re>trieves the list of customer conversion g>oals. 
 * 
 >   * @param GoogleAdsClient >$googleAdsClient the Google Ads API client 
 * @param int $customerId the customer ID 
 * @return array list of dicts containing the category and origin of customer conversion goals 
 */ 
 private static function getCustomerConversionGoals( 
 GoogleAdsClient $googleAdsClient, 
 int $customerId 
 ): array { 
 $customerConversionGoals = []; 
 $googleAdsServiceClient = $googleAdsClient-getGoogleAdsServiceClient(); 
 // Creates a query that retrieves all customer conversion goals. 
 $query = 'SELECT customer_conversion_goal.category, customer_conversion_goal.origin ' . 
 'FROM customer_conversion_goal'; 
 // The number of conversion goals is typically less than 50 so we use a search request 
 // instead of search stream. 
 $response = 
 $googleAdsServiceClient-search(SearchGoogleAdsRequest::build($customerId, $query)); 
 // Iterates over all rows in all pages and builds the list of conversion >goals. 
 foreach ($response-iterateAllElements() as $googleAdsRow) { 
 /** @var GoogleAdsRow $googleAdsRow */ 
 $customerConversionGoals[] = [ 
 'category' = $googleAdsRow-getCustomerConversionGoal()-getCategory(), 
 'origin' = $googleAdsRow-getCustomerConversionGoal()-getOrigin() 
 ]; 
 } 
 return $customerConversionGoals; 
 } 
 /** 
 * Creates a list of MutateOperations that override customer conversion goals. 
 * 
 * @param int $customerId the customer ID 
 * @param array $customerConversionGoals the list of customer conversion goals that will be 
 *      overridden 
 * @return MutateOperation[] a list of MutateOperations that update campaign conversion goals 
 */ 
 private static function createConversionGoalOperations( 
 int $customerId, 
 array $customerConversionGoals 
 ): array { 
 $operations = []; 
 &&      // To override the customer conversion goals, we will change the biddability of each of the 
 // customer con>version goals so that only the desired conversion goal is biddable in this 
 >   // campaign. 
 foreach ($customerConversionGoals as $customerConversionGoal) { 
 $campaignConversionGoal = new CampaignC>onversionGoal([ 
 'resource_name' = ResourceNam>es::forCampaignConversionGoal( 
 $customerId, 
 self::PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID, 
 ConversionActionCategory::name($customerConversionGoal['category']), 
 >          ConversionOrigin::name($customerConversionGoal['origin']) 
 ) 
 ]); 
 // Changes the biddability for the campaign conversion goal. 
 // Sets biddability to true for the desired (category, origin). 
 // Sets biddability to false for all other conversion goals. 
 // Note: 
 //  1- It is assumed that this Conversion Action 
 //     (category=PURCHASE, origin=WEBSITE) exists in this account. 
 //  2- More than one goal can be biddable if desired. This example 
 >    //     shows only one. 
 if ( 
 $customerConversionGoal["category"] === ConversionActionCategory::PURCHASE 
 >    $customerConversionGoal["origin"] === ConversionOrigin::WEBSITE 
 ) { 
 $campaignConversionGoal-setBiddable(true); 
 } else { 
 $campaignConversionGoal-setBiddable(false); 
> } 
 $operations[] = new MutateOperati>on([ 
 >           'campaign_conversion_goal_operation' = new CampaignConversionGoalOperation([ 
 &#  
nGoal, 
 // Sets the update mask on the operation. Here the update mask will be a list 
 // of all the fields that were set on the update object. 
 'update_mask' = FieldMasks::allSetFieldsOf($campaignConversionGoal) 
 ]) 
 ]); 
 } 
 return $operations; 
 } 
 /** 
 * Prints the details of a MutateGoogleAdsResponse. Parses the "response" oneof field name and 
 * uses it to extract the new entity's name and resource name. 
 * 
 * @param MutateGoogleAdsResponse $mutateGoogleAdsResponse the mutate Google Ads response 
 */ 
 private static function printResponseDetails( 
 MutateGoogleAdsResponse $mutateGoogleAdsResponse 
 ): void { 
 foreach ($mutateGoogleAdsResponse-getMutateOperationResponses() as $response) { 
 /** @var MutateOperationResponse $response */ 
 $getter = Serializer::getGetter($response-getResponse()); 
 printf( 
 "Created a(n) %s with '%s'.%s", 
 preg_replace( 
 '/Result$/', 
 '', 
 ucfirst(Serializer::toCamelCase($response-getResponse())) 
 ), 
 $response-$getter()-getResourceName(), 
 PHP_EOL 
 ); 
 } 
 } 
 } 
 AddPerformanceMaxRetailCampaign::main(); 
 AddPerformanceMaxRetailCampaign.php 
  

Python

 #!/usr/bin/env python 
 # 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 
 # 
 #     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 Performance Max retail campaign. 
 This will be created for "All products". 
 For more information about Performance Max retail campaigns, see 
 https://developers.google.com/google-ads/api/docs/performance-max/retail 
 Prerequisites: 
 - You need to have access to a Merchant Center account. You can find 
 instructions to create a Merchant Center account here: 
 https://support.google.com/merchants/answer/188924. 
 This account must be linked to your Google Ads account. The integration 
 instructions can be found at: 
 https://developers.google.com/google-ads/api/docs/shopping-ads/merchant-center 
 - You need your Google Ads account to track conversions. The different ways 
 to track conversions can be found here: 
 https://support.google.com/google-ads/answer/1722054. 
 - You must have at least one conversion action in the account. For 
 more about conversion actions, see 
 https://developers.google.com/google-ads/api/docs/conversions/overview#conversion_actions 
 """ 
 import 
  
 argparse 
 from 
  
 datetime 
  
 import 
 datetime 
 , 
 timedelta 
 import 
  
 sys 
 from 
  
 typing 
  
 import 
 Dict 
 , 
 List 
 , 
 Union 
 from 
  
 uuid 
  
 import 
 uuid4 
 from 
  
 google.api_core 
  
 import 
 protobuf_helpers 
 from 
  
 examples.utils.example_helpers 
  
 import 
 get_image_bytes_from_url 
 from 
  
 google.ads.googleads.client 
  
 import 
 GoogleAdsClient 
 from 
  
 google.ads.googleads.errors 
  
 import 
 GoogleAdsException 
 from 
  
 google.ads.googleads.util 
  
 import 
 convert_snake_case_to_upper_case 
 from 
  
 google.ads.googleads.v21.enums.types.conversion_action_category 
  
 import 
 ( 
 ConversionActionCategoryEnum 
 , 
 ) 
 from 
  
 google.ads.googleads.v21.enums.types.conversion_origin 
  
 import 
 ( 
 ConversionOriginEnum 
 , 
 ) 
 from 
  
 google.ads.googleads.v21.enums.types.asset_field_type 
  
 import 
 ( 
 AssetFieldTypeEnum 
 , 
 ) 
 from 
  
 google.ads.googleads.v21.resources.types.asset 
  
 import 
 Asset 
 from 
  
 google.ads.googleads.v21.resources.types.asset_group 
  
 import 
 AssetGroup 
 from 
  
 google.ads.googleads.v21.resources.types.asset_group_asset 
  
 import 
 ( 
 AssetGroupAsset 
 , 
 ) 
 from 
  
 google.ads.googleads.v21.resources.types.asset_group_listing_group_filter 
  
 import 
 ( 
 AssetGroupListingGroupFilter 
 , 
 ) 
 from 
  
 google.ads.googleads.v21.resources.types.campaign 
  
 import 
 Campaign 
 from 
  
 google.ads.googleads.v21.resources.types.campaign_asset 
  
 import 
 ( 
 CampaignAsset 
 , 
 ) 
 from 
  
 google.ads.googleads.v21.resources.types.campaign_budget 
  
 import 
 ( 
 CampaignBudget 
 , 
 ) 
 from 
  
 google.ads.googleads.v21.resources.types.campaign_conversion_goal 
  
 import 
 ( 
 CampaignConversionGoal 
 , 
 ) 
 from 
  
 google.ads.googleads.v21.resources.types.campaign_criterion 
  
 import 
 ( 
 CampaignCriterion 
 , 
 ) 
 from 
  
 google.ads.googleads.v21.services.services.asset_group_service 
  
 import 
 ( 
 AssetGroupServiceClient 
 , 
 ) 
 from 
  
 google.ads.googleads.v21.services.services.asset_service 
  
 import 
 ( 
 AssetServiceClient 
 , 
 ) 
 from 
  
 google.ads.googleads.v21.services.services.campaign_budget_service 
  
 import 
 ( 
 CampaignBudgetServiceClient 
 , 
 ) 
 from 
  
 google.ads.googleads.v21.services.services.campaign_conversion_goal_service 
  
 import 
 ( 
 CampaignConversionGoalServiceClient 
 , 
 ) 
 from 
  
 google.ads.googleads.v21.services.services.campaign_service 
  
 import 
 ( 
 CampaignServiceClient 
 , 
 ) 
 from 
  
 google.ads.googleads.v21.services.services.geo_target_constant_service 
  
 import 
 ( 
 GeoTargetConstantServiceClient 
 , 
 ) 
 from 
  
 google.ads.googleads.v21.services.services.google_ads_service 
  
 import 
 ( 
 GoogleAdsServiceClient 
 , 
 ) 
 from 
  
 google.ads.googleads.v21.services.types.google_ads_service 
  
 import 
 ( 
 MutateGoogleAdsResponse 
 , 
 MutateOperationResponse 
 , 
 SearchGoogleAdsRequest 
 , 
 SearchGoogleAdsResponse 
 , 
 ) 
 from 
  
 google.ads.googleads.v21.services.types.google_ads_service 
  
 import 
 ( 
 MutateOperation 
 , 
 ) 
 # We specify temporary IDs that are specific to a single mutate request. 
 # Temporary IDs are always negative and unique within one mutate request. 
 # 
 # See https://developers.google.com/google-ads/api/docs/mutating/best-practices 
 # for further details. 
 # 
 # These temporary IDs are fixed because they are used in multiple places. 
 _BUDGET_TEMPORARY_ID 
 : 
 str 
 = 
 "-1" 
 _PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 : 
 str 
 = 
 "-2" 
 _ASSET_GROUP_TEMPORARY_ID 
 : 
 str 
 = 
 "-3" 
 # There are also entities that will be created in the same request but do not 
 # need to be fixed temporary IDs because they are referenced only once. 
 _next_temp_id 
 : 
 int 
 = 
 int 
 ( 
 _ASSET_GROUP_TEMPORARY_ID 
 ) 
 - 
 1 
 def 
  
 main 
 ( 
 client 
 : 
 GoogleAdsClient 
 , 
 customer_id 
 : 
 str 
 , 
 me>rchant_center_account_id 
 : 
 int 
 , 
 final_url 
 : 
 str 
 , 
 brand_guidelines_enabled 
 : 
 bool 
 , 
 ) 
 - 
 None 
 : 
  
 """The main method that creates all necessary entities for the example. 
 Args: 
 client: an initialized GoogleAdsClient instance. 
 customer_id: a client customer ID. 
 merchant_center_account_id: The Merchant Center account ID. 
 final_url: the final URL. 
 brand_guidelines_enabled: a boolean value indicating if the campaign is 
 enabled for brand guidelines. 
 """ 
 googleads_service 
 : 
 GoogleAdsServiceClient 
 = 
 client 
 . 
 get_service 
 ( 
 "GoogleAdsService" 
 ) 
 # This campaign will override the customer conversion goals. 
 # Retrieve the current list of customer conversion goals. 
 customer_conversion_goals 
 : 
 List 
 [ 
 Dict 
 [ 
 str 
 , 
 Union 
 [ 
 ConversionActionCategoryEnum 
 . 
 ConversionActionCategory 
 , 
 ConversionOriginEnum 
 . 
 ConversionOrigin 
 , 
 ], 
 ] 
 ] 
 = 
 get_customer_conversion_goals 
 ( 
 client 
 , 
 customer_id 
 ) 
 # Performance Max campaigns require that repeated assets such as headlines 
 # and descriptions be created before the campaign. 
 # For the list of required assets for a Performance Max campaign, see 
 # https://developers.google.com/google-ads/api/docs/performance-max/assets 
 # 
 # Create the headlines. 
 headline_asset_resource_names 
 : 
 List 
 [ 
 str 
 ] 
 = 
 create_multiple_text_assets 
 ( 
 client 
 , 
 customer_id 
 , 
 [ 
 "Travel" 
 , 
 "Travel Reviews" 
 , 
 "Book travel" 
 , 
 ], 
 ) 
 # Create the descriptions. 
 description_asset_resource_names 
 : 
 List 
 [ 
 str 
 ] 
 = 
 create_multiple_text_assets 
 ( 
 client 
 , 
 customer_id 
 , 
 [ 
 "Take to the air!" 
 , 
 "Fly to the sky!" 
 , 
 ], 
 ) 
 # The below methods create and return MutateOperations that we later 
 # provide to the GoogleAdsService.Mutate method in order to create the 
 # entities in a single request. Since the entities for a Performance Max 
 # campaign are closely tied to one-another, it's considered a best practice 
 # to create them in a single Mutate request so they all complete 
 # successfully or fail entirely, leaving no orphaned entities. See: 
 # https://developers.google.com/google-ads/api/docs/mutating/overview 
 campaign_budget_operation 
 : 
 MutateOperation 
 = 
 ( 
 create_campaign_budget_operation 
 ( 
 client 
 , 
 customer_id 
 , 
 ) 
 ) 
 performance_max_campaign_operation 
 : 
 MutateOperation 
 = 
 ( 
 create_performance_max_campaign_operation 
 ( 
 client 
 , 
 customer_id 
 , 
 merchant_center_account_id 
 , 
 brand_guidelines_enabled 
 , 
 ) 
 ) 
 campaign_criterion_operations 
 : 
 List 
 [ 
 MutateOperation 
 ] 
 = 
 ( 
 create_campaign_criterion_operations 
 ( 
 client 
 , 
 customer_id 
 , 
 ) 
 ) 
 asset_group_operation 
 : 
 MutateOperation 
 = 
 create_asset_group_operation 
 ( 
 client 
 , 
 customer_id 
 , 
 final_url 
 ) 
 listing_group_filter_operation 
 : 
 MutateOperation 
 = 
 ( 
 create_listing_group_filter_operation 
 ( 
 client 
 , 
 customer_id 
 ) 
 ) 
 asset_and_asset_group_asset_operations 
 : 
 List 
 [ 
 MutateOperation 
 ] 
 = 
 ( 
 create_asset_and_asset_group_asset_operations 
 ( 
 client 
 , 
 customer_id 
 , 
 headline_asset_resource_names 
 , 
 description_asset_resource_names 
 , 
 brand_guidelines_enabled 
 , 
 ) 
 ) 
 conversion_goal_operations 
 : 
 List 
 [ 
 MutateOperation 
 ] 
 = 
 ( 
 create_conversion_goal_operations 
 ( 
 client 
 , 
 customer_id 
 , 
 customer_conversion_goals 
 , 
 ) 
 ) 
 # Send the operations in a single Mutate request. 
 response 
 : 
 MutateGoogleAdsResponse 
 = 
 googleads_service 
 . 
 mutate 
 ( 
 customer_id 
 = 
 customer_id 
 , 
 mutate_operations 
 = 
 [ 
 # It's important to create these entities in this order because 
 # they depend on each other. 
 campaign_budget_operation 
 , 
 performance_max_campaign_operation 
 , 
 # Expand the list of multiple operations into the list of 
 # other mutate operations. 
 * 
 campaign_criterion_operations 
 , 
 asset_group_operation 
 , 
 listing_group_filter_operation 
 , 
 * 
 asset_and_asset_group_asset_operations 
 , 
> * 
 conversion_goal_operations 
 , 
 ], 
 ) 
 print_response_details 
 ( 
 response 
 ) 
 def 
  
 create_campaign_budget_operation 
 ( 
 client 
 : 
 GoogleAdsClient 
 , 
 customer_id 
 : 
 str 
 , 
 ) 
 - 
 MutateOperation 
 : 
  
 """Creates a MutateOperation that creates a new CampaignBudget. 
 A temporary ID will be assigned to this campaign budget so that it can be 
 referenced by other objects being created in the same Mutate request. 
 Args: 
 client: an initialized GoogleAdsClient instance. 
 customer_id: a client customer ID. 
 Returns: 
 a MutateOperation that creates a CampaignBudget. 
 """ 
 mutate_operation 
 : 
 MutateOperation 
 = 
 client 
 . 
 get_type 
 ( 
 "MutateOperation" 
 ) 
 campaign_budget_operation 
 = 
 mutate_operation 
 . 
 campaign_budget_operation 
 campaign_budget 
 : 
 CampaignBudget 
 = 
 campaign_budget_operation 
 . 
 create 
 campaign_budget 
 . 
 name 
 = 
 f 
 "Performance Max retail campaign budget # 
 { 
 uuid4 
 () 
 } 
 " 
 # The budget period already defaults to DAILY. 
 campaign_budget 
 . 
 amount_micros 
 = 
 50000000 
 campaign_budget 
 . 
 delivery_method 
 = 
 ( 
 client 
 . 
 enums 
 . 
 BudgetDeliveryMethodEnum 
 . 
 STANDARD 
 ) 
 # A Performance Max campaign cannot use a shared campaign budget. 
 campaign_budget 
 . 
 explicitly_shared 
 = 
 False 
 # Set a temporary ID in the budget's resource name so it can be referenced 
 # by the campaign in later steps. 
 campaign_budget_service 
 : 
 CampaignBudgetServiceClient 
 = 
 client 
 . 
 get_service 
 ( 
 "CampaignBudgetService" 
 ) 
 campaign_budget 
 . 
 resource_name 
 = 
 ( 
 campaign_budget_service 
 . 
 campaign_budget_path 
 ( 
 cus>tomer_id 
 , 
 _BUDGET_TEMPORARY_ID 
 ) 
 ) 
 return 
 mutate_operation 
 def 
  
 create_performance_max_campaign_operation 
 ( 
 client 
 : 
 GoogleAdsClient 
 , 
 customer_id 
 : 
 str 
 , 
 merchant_center_account_id 
 : 
 int 
 , 
 brand_guidelines_enabled 
 : 
 bool 
 , 
 ) 
 - 
 MutateOperation 
 : 
  
 """Creates a MutateOperation that creates a new Performance Max campaign. 
 A temporary ID will be assigned to this campaign so that it can 
 be referenced by other objects being created in the same Mutate request. 
 Args: 
 client: an initialized GoogleAdsClient instance. 
 customer_id: a client customer ID. 
 merchant_center_account_id: The Merchant Center account ID. 
 brand_guidelines_enabled: a boolean value indicating if the campaign is 
 enabled for brand guidelines. 
 Returns: 
 a MutateOperation that creates a campaign. 
 """ 
 mutate_operation 
 : 
 MutateOperation 
 = 
 client 
 . 
 get_type 
 ( 
 "MutateOperation" 
 ) 
 campaign 
 : 
 Campaign 
 = 
 mutate_operation 
 . 
 campaign_operation 
 . 
 create 
 campaign 
 . 
 name 
 = 
 f 
 "Performance Max retail campaign # 
 { 
 uuid4 
 () 
 } 
 " 
 # Set the campaign status as PAUSED. The campaign is the only entity in 
 # the mutate request that should have its status set. 
 campaign 
 . 
 status 
 = 
 client 
 . 
 enums 
 . 
 CampaignStatusEnum 
 . 
 PAUSED 
 # All Performance Max campaigns have an advertising_channel_type of 
 # PERFORMANCE_MAX. The advertising_channel_sub_type should not be set. 
 campaign 
 . 
 advertising_channel_type 
 = 
 ( 
 client 
 . 
 enums 
 . 
 AdvertisingChannelTypeEnum 
 . 
 PERFORMANCE_MAX 
 ) 
 # Bidding strategy must be set directly on the campaign. 
 # Setting a portfolio bidding strategy by resource name is not supported. 
 # Max Conversion and Max Conversion Value are the only strategies supported 
 # for Performance Max campaigns. 
 # An optional ROAS (Return on Advertising Spend) can be set for 
 # maximize_conversion_value. The ROAS value must be specified as a ratio in 
 # the API. It is calculated by dividing "total value" by "total spend". 
 # For more information on Max Conversion Value, see the support article: 
 # http://support.google.com/google-ads/answer/7684216. 
 # A target_roas of 3.5 corresponds to a 350% return on ad spend. 
 # campaign.maximize_conversion_value.target_roas = 3.5 
 # For first time users, it's recommended not to set a target ROAS. 
 # Although target ROAS is optional, you still need to define it 
 # even if you do not want to use it. 
 campaign 
 . 
 maximize_conversion_value 
 . 
 target_roas 
 = 
 None 
 # Below is what you would use if you want to maximize conversions 
 # campaign.maximize_conversions.target_cpa_micros = None 
 # The target CPA is optional. This is the average amount that you would 
 # like to spend per conversion action. 
 # Set the shopping settings. 
 campaign 
 . 
 shopping_setting 
 . 
 merchant_id 
 = 
 merchant_center_account_id 
 # Optional: To use products only from a specific feed, set 
 # shopping_setting.feed_label to the feed label used in Merchant Center. 
 # See: https://support.google.com/merchants/answer/12453549. 
 # Omitting the shopping_setting.feed_label field will use products from all 
 # feeds. 
 # campaign.shopping_setting.feed_label = "INSERT_FEED_LABEL_HERE" 
 # Set the Final URL expansion opt out. This flag is specific to 
 # Performance Max campaigns. If opted out (True), only the final URLs in 
 # the asset group or URLs specified in the advertiser's Google Merchant 
 # If opted in (False), the entire domain will be targeted. For best 
 # results, set this value to false to opt in and allow URL expansions. You 
 # can optionally add exclusions to limit traffic to parts of your website. 
 # For a Retail campaign, we want the final URL's to be limited to 
 # those explicitly surfaced via GMC. 
 campaign 
 . 
 url_expansion_opt_out 
 = 
 True 
 # Set if the campaign is enabled for brand guidelines. For more information 
 # on brand guidelines, see https://support.google.com/google-ads/answer/14934472. 
 campaign 
 . 
 brand_guidelines_enabled 
 = 
 brand_guidelines_enabled 
 # Assign the resource name with a temporary ID. 
 campaign_service 
 : 
 CampaignServiceClient 
 = 
 client 
 . 
 get_service 
 ( 
 "CampaignService" 
 ) 
 campaign 
 . 
 resource_name 
 = 
 campaign_service 
 . 
 campaign_path 
 ( 
 customer_id 
 , 
 _PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 ) 
 # Set the budget using the given budget resource name. 
 campaign_budget_service 
 : 
 CampaignBudgetServiceClient 
 = 
 client 
 . 
 get_service 
 ( 
 "CampaignBudgetService" 
 ) 
 campaign 
 . 
 campaign_budget 
 = 
 campaign_budget_service 
 . 
 campaign_budget_path 
 ( 
 customer_id 
 , 
 _BUDGET_TEMPORARY_ID 
 ) 
 # Declare whether or not this campaign serves political ads targeting the 
 # EU. Valid values are: 
 #   CONTAINS_EU_POLITICAL_ADVERTISING 
 #   DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING 
 campaign 
 . 
 contains_eu_political_advertising 
 = 
 ( 
 client 
 . 
 enums 
 . 
 EuPoliticalAdvertisin>gStatusEnum 
 . 
 DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING 
 ) 
 # Optional fields 
 campaign 
 . 
 start_date 
 = 
 ( 
 datetime 
 . 
 now 
 () 
 + 
 timedelta 
 ( 
 1 
 )) 
 . 
 strftime 
 ( 
 "%Y%m 
 %d 
 " 
 ) 
 campaign 
 . 
 end_date 
 = 
 ( 
 datetime 
 . 
 now 
 () 
 + 
 timedelta 
 ( 
 365 
 )) 
 . 
 strftime 
 ( 
 "%Y%m 
 %d 
 " 
 ) 
 return 
 mutate_operation 
 def 
  
 create_campaign_criterion_operations 
 ( 
 client 
 : 
 GoogleAdsClient 
 , 
 customer_id 
 : 
 str 
 , 
 ) 
 - 
 List 
 [ 
 MutateOperation 
 ]: 
  
 """Creates a list of MutateOperations that create new campaign criteria. 
 Args: 
 client: an initialized GoogleAdsClient instance. 
 customer_id: a client customer ID. 
 Returns: 
 a list of MutateOperations that create new campaign criteria. 
 """ 
 campaign_service 
 : 
 CampaignServiceClient 
 = 
 client 
 . 
 get_service 
 ( 
 "CampaignService" 
 ) 
 geo_target_constant_service 
 : 
 GeoTargetConstantServiceClient 
 = 
 ( 
 client 
 . 
 get_service 
 ( 
 "GeoTargetConstantService" 
 ) 
 ) 
 googleads_service 
 : 
 GoogleAdsServiceClient 
 = 
 client 
 . 
 get_service 
 ( 
 "GoogleAdsService" 
 ) 
 operations 
 : 
 List 
 [ 
 MutateOperation 
 ] 
 = 
 [] 
 # Set the LOCATION campaign criteria. 
 # Target all of New York City except Brooklyn. 
 # Location IDs are listed here: 
 # https://developers.google.com/google-ads/api/reference/data/geotargets 
 # and they can also be retrieved using the GeoTargetConstantService as shown 
 # here: https://developers.google.com/google-ads/api/docs/targeting/location-targeting 
 mutate_operation_nyc 
 : 
 MutateOperation 
 = 
 client 
 . 
 get_type 
 ( 
 "MutateOperation" 
 ) 
 campaign_criterion_nyc 
 : 
 CampaignCriterion 
 = 
 ( 
 mutate_operation_nyc 
 . 
 campaign_criterion_operation 
 . 
 create 
 ) 
 campaign_criterion_nyc 
 . 
 campaign 
 = 
 campaign_service 
 . 
 campaign_path 
 ( 
 customer_id 
 , 
 _PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 ) 
 # Adds one positive location target for New York City (ID=1023191), 
 # specifically adding the positive criteria before the negative one. 
 campaign_criterion_nyc 
 . 
 location 
 . 
 geo_target_constant 
 = 
 ( 
 geo_target_constant_service 
 . 
 geo_target_constant_path 
 ( 
 "1023191" 
 ) 
 ) 
 campaign_criterion_nyc 
 . 
 negative 
 = 
 False 
 operations 
 . 
 append 
 ( 
 mutate_operation_nyc 
 ) 
 # Next add the negative target for Brooklyn (ID=1022762). 
 mutate_operation_brooklyn 
 : 
 MutateOperation 
 = 
 client 
 . 
 get_type 
 ( 
 "MutateOperation" 
 ) 
 campaign_criterion_brooklyn 
 : 
 CampaignCriterion 
 = 
 ( 
 mutate_operation_brooklyn 
 . 
 campaign_criterion_operation 
 . 
 create 
 ) 
 campaign_criterion_brooklyn 
 . 
 campaign 
 = 
 campaign_service 
 . 
 campaign_path 
 ( 
 customer_id 
 , 
 _PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 ) 
 campaign_criterion_brooklyn 
 . 
 location 
 . 
 geo_target_constant 
 = 
 ( 
 geo_target_constant_service 
 . 
 geo_target_constant_path 
 ( 
 "1022762" 
 ) 
 ) 
 campaign_criterion_brooklyn 
 . 
 negative 
 = 
 True 
 operations 
 . 
 append 
 ( 
 mutate_operation_brooklyn 
 ) 
 # Set the LANGUAGE campaign criterion. 
 mutate_operation_lang 
 : 
 MutateOperation 
 = 
 client 
 . 
 get_type 
 ( 
 "MutateOperation" 
 ) 
 campaign_criterion_lang 
 : 
 CampaignCriterion 
 = 
 ( 
 mutate_operation_lang 
 . 
 campaign_criterion_operation 
 . 
 create 
 ) 
 campaign_criterion_lang 
 . 
 campaign 
 = 
 campaign_service 
 . 
 campaign_path 
 ( 
 customer_id 
 , 
 _PERFORMANCE_MAX>_CAMPAIGN_TEMPORARY_ID 
 ) 
 # Set the language. 
 # For a list of all language codes, see: 
 # https://developers.google.com/google-ads/api/reference/data/codes-formats#expandable-7 
 campaign_criterion_lang 
 . 
 language 
 . 
 language_constant 
 = 
 ( 
 googleads_service 
 . 
 language_constant_path 
 ( 
 "1000" 
 ) 
 ) 
 # English 
 operations 
 . 
 append 
 ( 
 mutate_operation_lang 
 ) 
 return 
 operations 
 def 
  
 create_multiple_text_assets 
 ( 
 client 
 : 
 GoogleAdsClient 
 , 
 customer_id 
 : 
 str 
 , 
 texts 
 : 
 List 
 [ 
 str 
 ] 
 ) 
 - 
 List 
 [ 
 str 
 ]: 
  
 """Creates multiple text assets and returns the list of resource names. 
 These repeated assets must be created in a separate request prior to 
 creating the campaign. 
 Args: 
 client: an initialized GoogleAdsClient instance. 
 customer_id: a client customer ID. 
 texts: a list of strings, each of which will be used to create a text 
 asset. 
 Returns: 
 asset_resource_names: a list of asset resource names. 
 """ 
 # Here again we use the GoogleAdService to create multiple text 
 # assets in a single request. 
 googleads_service 
 : 
 GoogleAdsServiceClient 
 = 
 client 
 . 
 get_service 
 ( 
 "GoogleAdsService" 
 ) 
 operations 
 : 
 List 
 [ 
 MutateOperation 
 ] 
 = 
 [] 
 for 
 text_content 
 in 
 texts 
 : 
 mutate_operation 
 : 
 MutateOperation 
 = 
 client 
 . 
 get_type 
 ( 
 "MutateOperation" 
 ) 
 asset 
 : 
 Asset 
 = 
 mutate_operation 
 . 
 asset_operation 
 . 
 create 
 asset 
 . 
 text_asset 
 . 
 text 
 = 
 text_content 
 operations 
 . 
 append 
 ( 
 mutate_operation 
 ) 
 # Send the operations in a s>ingle Mutate request. 
 response 
 : 
 MutateGoogleAdsResponse 
 = 
 googleads_service 
 . 
 mutate 
 ( 
 customer_id 
 = 
 customer_id 
 , 
 mutate_operations 
 = 
 operations 
 , 
 ) 
 asset_resource_names 
 : 
 List 
 [ 
 str 
 ] 
 = 
 [] 
 for 
 result 
 in 
 response 
 . 
 mutate_operation_responses 
 : 
 if 
 result 
 . 
 _pb 
 . 
 HasField 
 ( 
 "asset_result" 
 ): 
 asset_resource_names 
 . 
 append 
 ( 
 result 
 . 
 asset_result 
 . 
 resource_name 
 ) 
 print_response_details 
 ( 
 response 
 ) 
 return 
 asset_resource_names 
 def 
  
 create_asset_group_operation 
 ( 
 client 
 : 
 GoogleAdsClient 
 , 
 customer_id 
 : 
 str 
 , 
 final_url 
 : 
 str 
 ) 
 - 
 MutateOperation 
 : 
  
 """Creates a MutateOperation that creates a new asset group. 
 A temporary ID will be assigned to this asset group so that it can 
 be referenced by other objects being created in the same Mutate request. 
 Args: 
 client: an initialized GoogleAdsClient instance. 
 customer_id: a client customer ID. 
 final_url: the final URL. 
 Returns: 
 a MutateOperation that creates a new asset group. 
 """ 
 campaign_service 
 : 
 CampaignServiceClient 
 = 
 client 
 . 
 get_service 
 ( 
 "CampaignService" 
 ) 
 asset_group_service 
 : 
 AssetGroupServiceClient 
 = 
 client 
 . 
 get_service 
 ( 
 "AssetGroupService" 
 ) 
 # Create the AssetGroup. 
 mutate_operation 
 : 
 MutateOperation 
 = 
 client 
 . 
 get_type 
 ( 
 "MutateOperation" 
 ) 
 asset_group 
 : 
 AssetGroup 
 = 
 mutate_operation 
 . 
 asset_group_operatio>n 
 . 
 create 
 asset_group 
 . 
 name 
 = 
 f 
 "Performance Max retail asset group # 
 { 
 uuid4 
 () 
 } 
 " 
 asset_group 
 . 
 campaign 
 = 
 campaign_service 
 . 
 campaign_path 
 ( 
 customer_id 
 , 
 _PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 ) 
 asset_group 
 . 
 final_urls 
 . 
 append 
 ( 
 final_url 
 ) 
 asset_group 
 . 
 final_mobile_urls 
 . 
 append 
 ( 
 final_url 
 ) 
 asset_group 
 . 
 status 
 = 
 client 
 . 
 enums 
 . 
 AssetGroupStatusEnum 
 . 
 PAUSED 
 asset_group 
 . 
 resource_name 
 = 
 asset_group_service 
 . 
 asset_group_path 
 ( 
 customer_id 
 , 
 _ASSET_GROUP_TEMPORARY_ID 
 , 
 ) 
 return 
 mutate_operation 
 def 
  
 create_listing_group_filter_operation 
 ( 
 client 
 : 
 GoogleAdsClient 
 , 
 customer_id 
 : 
 str 
 ) 
 - 
 MutateOperation 
 : 
  
 """Creates a MutateOperation that creates a new listing group filter. 
 A temporary ID will be assigned to this listing group filter so that it 
 can be referenced by other objects being created in the same Mutate request. 
 Args: 
 client: an initialized GoogleAdsClient instance. 
 customer_id: a client customer ID. 
 Returns: 
 a MutateOperation that creates a new listing group filter. 
 """ 
 asset_group_service 
 : 
 AssetGroupServiceClient 
 = 
 client 
 . 
 get_service 
 ( 
 "AssetGroupService" 
 ) 
 # Creates a new ad group criterion containing the "default" listing 
 # group (All products). 
 mutate_operation 
 : 
 MutateOperation 
 = 
 client 
 . 
 get_type 
 ( 
 "MutateOperation" 
 ) 
 asset_group_listing_group 
 : 
 AssetGroupListingGroupFilter 
 = 
 ( 
 mutate_operation 
 . 
 asset_group_listing_group_filter_operation 
 . 
 create 
 ) 
 asset_group_listing_group 
 . 
 asset_group 
 = 
 ( 
 asset_group_service 
 . 
 asset_group_path 
 ( 
 c>ustomer_id 
 , 
 _ASSET_GROUP_TEMPORARY_ID 
 , 
 ) 
 ) 
 asset_group_listing_group 
 . 
 type_ 
 = 
 ( 
 client 
 . 
 enums 
 . 
 ListingGroupFilterTypeEnum 
 . 
 UNIT_INCLUDED 
 ) 
 # Because this is a Performance Max campaign for retail, we need to specify 
 # that this is in the shopping listing source. 
 asset_group_listing_group 
 . 
 listing_source 
 = 
 ( 
 client 
 . 
 enums 
 . 
 ListingGroupFilterListingSourceEnum 
 . 
 SHOPPING 
 ) 
 return 
 mutate_operation 
 def 
  
 create_asset_and_asset_group_asset_operations 
 ( 
 client 
 : 
 GoogleAdsClient 
 , 
 customer_id 
 : 
 str 
 , 
 headline_asset_resource_names 
 : 
 List 
 [ 
 str 
 ], 
 description_asset_resource_names 
 : 
 List 
 [ 
 str 
 ], 
 brand_guidelines_enabled 
 : 
 bool 
 , 
 ) 
 - 
 List 
 [ 
 MutateOperation 
 ]: 
  
 """Creates a list of MutateOperations that create a new asset_group. 
 A temporary ID will be assigned to this asset group so that it can 
 be referenced by other objects being created in the same Mutate request. 
 Args: 
 client: an initialized GoogleAdsClient instance. 
 customer_id: a client customer ID. 
 headline_asset_resource_names: a list of headline resource names. 
 description_asset_resource_names: a list of description resource names. 
 brand_guidelines_enabled: a boolean value indicating if the campaign is 
 enabled for brand guidelines. 
 Returns: 
 MutateOperations that create a new asset group and related assets. 
 """ 
 asset_group_service 
 : 
 AssetGroupServiceClient 
 = 
 client 
 . 
 get_service 
 ( 
 "AssetGroupService" 
 ) 
 operations 
 : 
 List 
 [ 
 MutateOperation 
 ] 
 = 
 [] 
 # For the list of required assets for a Performance Max campaign, see 
 # https://developers.google.com/google-ads/api/docs/performance-max/assets 
 # An AssetGroup is linked to an Asset by creating a new AssetGroupAsset 
 # and providing: 
 #   the resource name of the AssetGroup 
 #   the resource name of the Asset 
 #   the field_type of the Asset in this AssetGroup. 
 # 
 # To learn more about AssetGroups, see 
 # https://developers.google.com/google-ads/api/docs/performance-max/asset-groups 
 # Link the previously created multiple text assets. 
 # Link the headline assets. 
 for 
 resource_name 
 in 
 headline_asset_resource_names 
 : 
 mutate_operation 
 : 
 MutateOperation 
 = 
 client 
 . 
 get_type 
 ( 
 "MutateOperation" 
 ) 
 asset_group_asset 
 : 
 AssetGroupAsset 
 = 
 ( 
 mutate_operation 
 . 
 asset_group_asset_operation 
 . 
 create 
 ) 
 asset_group_asset 
 . 
 field_type 
 = 
 client 
 . 
 enums 
 . 
 AssetFieldTypeEnum 
 . 
 HEADLINE 
 asset_group_asset 
 . 
 asset_group 
 = 
 asset_group_service 
 . 
 asset_group_path 
 ( 
 customer_id 
 , 
 _ASSET_GROUP_TEMPORARY_ID 
 , 
 ) 
 asset_group_asset 
 . 
 asset 
 = 
 resource_name 
 operations 
 . 
 append 
 ( 
 mutate_operation 
 ) 
 #  Link the description assets. 
 for 
 resource_name 
 in 
 description_asset_resource_names 
 : 
 mutate_operation 
 : 
 MutateOperation 
 = 
 client 
 . 
 get_type 
 ( 
 "MutateOperation" 
 ) 
 asset_group_asset 
 : 
 AssetGroupAsset 
 = 
 ( 
 mutate_operation 
 . 
 asset_group_asset_operation 
 . 
 create 
 ) 
 asset_group_asset 
 . 
 field_type 
 = 
 ( 
 client 
 . 
 enums 
 . 
 AssetFieldTypeEnum 
 . 
 DESCRIPTION 
 ) 
 asset_group_asset 
 . 
 asset_group 
 = 
 asset_group_service 
 . 
 asset_group_path 
 ( 
 customer_id 
 , 
 _ASSET_GROUP_TEMPORARY_ID 
 , 
 ) 
 asset_group_asset 
 . 
 asset 
 = 
 resource_name 
 operations 
 . 
 append 
 ( 
 mutate_operation 
 ) 
 # Create and link the long headline text asset. 
 mutate_operations_long_headline 
 : 
 List 
 [ 
 MutateOperation 
 ] 
 = 
 ( 
 create_and_link_text_asset 
 ( 
 client 
 , 
 customer_id 
 , 
 "Travel the World" 
 , 
 client 
 . 
 enums 
 . 
 AssetFieldTypeEnum 
 . 
 LONG_HEADLINE 
 , 
 ) 
 ) 
 operations 
 . 
 extend 
 ( 
 mutate_operations_long_headline 
 ) 
 # Create and link the business name and logo asset. 
 mutate_operations_brand 
 : 
 List 
 [ 
 MutateOperation 
 ] 
 = 
 ( 
 create_and_link_brand_assets 
 ( 
 client 
 , 
 customer_id 
 , 
 brand_guidelines_enabled 
 , 
 "Interplanetary Cruises" 
 , 
 "https://gaagl.page.link/1Crm" 
 , 
 "Logo Image" 
 , 
 ) 
 ) 
 operations 
 . 
 extend 
 ( 
 mutate_operations_brand 
 ) 
 # Create and link the image assets. 
 # Create and link the Marketing Image Asset. 
 mutate_operations_marketing_image 
 : 
 List 
 [ 
 MutateOperation 
 ] 
 = 
 ( 
 create_and_link_image_asset 
 ( 
 client 
 , 
 customer_id 
 , 
 "https://gaagl.page.link/Eit5" 
 , 
 client 
 . 
 enums 
 . 
 AssetFieldTypeEnum 
 . 
 MARKETING_IMAGE 
 , 
 "Marketing Image" 
 , 
 ) 
 ) 
 operations 
 . 
 extend 
 ( 
 mutate_operations_marketing_image 
 ) 
 # Create> and link the Square Marketing Image Asset. 
 mutate_operations_square_image 
 : 
 List 
 [ 
 MutateOperation 
 ] 
 = 
 ( 
 create_and_link_image_asset 
 ( 
 client 
 , 
 customer_id 
 , 
 "https://gaagl.page.link/bjYi" 
 , 
 client 
 . 
 enums 
 . 
 AssetFieldTypeEnum 
 . 
 SQUARE_MARKETING_IMAGE 
 , 
 "Square Marketing Image" 
 , 
 ) 
 ) 
 operations 
 . 
 extend 
 ( 
 mutate_operations_square_image 
 ) 
 # After being created the list must be sorted so that all asset 
 # operations come before all the asset group asset operations, 
 # otherwise the API will reject the request. 
 return 
 sort_asset_and_asset_group_asset_operations 
 ( 
 operations 
 ) 
 def 
  
 create_and_link_text_asset 
 ( 
 client 
 : 
 GoogleAdsClient 
 , 
 customer_id 
 : 
 str 
 , 
 text 
 : 
 str 
 , 
 field_type 
 : 
 AssetFieldTypeEnum 
 . 
 AssetFieldType 
 , 
 ) 
 - 
 List 
 [ 
 MutateOperation 
 ]: 
  
 """Creates a list of MutateOperations that create a new linked text asset. 
 Args: 
 client: an initialized GoogleAdsClient instance. 
 customer_id: a client customer ID. 
 text: the text of the asset to be created. 
 field_type: the field_type of the new asset in the AssetGroupAsset. 
 Returns: 
 MutateOperations that create a new linked text asset. 
 """ 
 global 
 _next_temp_id 
 operations 
 : 
 List 
 [ 
 MutateOperation 
 ] 
 = 
 [] 
 asset_service 
 : 
 AssetServiceClient 
 = 
 client 
 . 
 get_service 
 ( 
 "AssetService" 
 ) 
 asset_group_service 
 : 
 AssetGroupServiceClient 
 = 
 client 
 . 
 get_service 
 ( 
 "AssetGroupService" 
 ) 
 # Create the Text Asset. 
 asset_temp_resource_name 
 = 
 asset_service 
 . 
 asset_path 
 ( 
 customer_id 
 , 
 str 
 ( 
 _next_temp_id 
 ) 
 ) 
 mutate_operation_asset 
 : 
 MutateOperation 
 = 
 client 
 . 
 get_type 
 ( 
 "MutateOperation" 
 ) 
 asset 
 : 
 Asset 
 = 
 mutate_operation_asset 
 . 
 asset_operation 
 . 
 create 
 asset 
 . 
 resource_name 
 = 
 asset_temp_r>esource_name 
 asset 
 . 
 text_asset 
 . 
 text 
 = 
 text 
 operations 
 . 
 append 
 ( 
 mutate_operation_asset 
 ) 
 # Create an AssetGroupAsset to link the Asset to the AssetGroup. 
 mutate_operation_group_asset 
 : 
 MutateOperation 
 = 
 client 
 . 
 get_type 
 ( 
 "MutateOperation" 
 ) 
 asset_group_asset 
 : 
 AssetGroupAsset 
 = 
 ( 
 mutate_operation_group_asset 
 . 
 asset_group_asset_operation 
 . 
 create 
 ) 
 asset_group_asset 
 . 
 field_type 
 = 
 field_type 
 asset_group_asset 
 . 
 asset_group 
 = 
 asset_group_service 
 . 
 asset_group_path 
 ( 
 customer_id 
 , 
 _ASSET_GROUP_TEMPORARY_ID 
 , 
 ) 
 asset_group_asset 
 . 
 asset 
 = 
 asset_temp_resource_name 
 operations 
 . 
 append 
 ( 
 mutate_operation_group_asset 
 ) 
 _next_temp_id 
 -= 
 1 
 return 
 operations 
 def 
  
 create_and_link_image_asset 
 ( 
 client 
 : 
 GoogleAdsClient 
 , 
 customer_id 
 : 
 str 
 , 
 url 
 : 
 str 
 , 
 field_type 
 : 
 AssetFieldTypeEnum 
 . 
 AssetFieldType 
 , 
 asset_name 
 : 
 str 
 , 
 ) 
 - 
 List 
 [ 
 MutateOperation 
 ]: 
  
 """Creates a list of MutateOperations that create a new linked image asset. 
 Args: 
 client: an initialized GoogleAdsClient instance. 
 customer_id: a client customer ID. 
 url: the url of the image to be retrieved and put into an asset. 
 field_type: the field_type of the new asset in the AssetGroupAsset. 
 asset_name: the asset name. 
 Returns: 
 MutateOperations that create a new linked image asset. 
 """ 
 global 
 _next_temp_id 
 operations 
 : 
 List 
 [ 
 MutateOperation 
 ] 
 = 
 [] 
 asset_service 
 : 
 AssetServiceClient 
 = 
 client 
 . 
 get_service 
 ( 
 "AssetService" 
 ) 
 asset_group_service 
 : 
 AssetGroupServiceClient 
 = 
 client 
 . 
 get_service 
 ( 
 "AssetGroupService" 
 ) 
 # Create the Image Asset. 
 asset_temp_resource_name 
 = 
 asset_service 
 . 
 asset_path 
 ( 
 customer_id 
 , 
 str 
 ( 
 _next_temp_id 
 ) 
 ) 
 mutate_operation_asset 
 : 
 MutateOperation 
 = 
 client 
 . 
 get_type 
 ( 
 "MutateOperation" 
 ) 
 asset 
 : 
 Asset 
 = 
 mutate_operation_asset 
 . 
 asset_operation 
 . 
 create 
 asset 
 . 
 resource_name 
 = 
 asset_temp_resource_name 
 asset 
 . 
 type_ 
 = 
 client 
 . 
 enums 
 . 
 AssetTypeEnum 
 . 
 IMAGE 
 # Provide a unique friendly name to identify your asset. 
 # When there is an> existing image asset with the same content but a different 
 # name, the new name will be dropped silently. 
 asset 
 . 
 name 
 = 
 asset_name 
 asset 
 . 
 image_asset 
 . 
 data 
 = 
 get_image_bytes_from_url 
 ( 
 url 
 ) 
 operations 
 . 
 append 
 ( 
 mutate_operation_asset 
 ) 
 # Create an AssetGroupAsset to link the Asset to the AssetGroup. 
 mutate_operation_group_asset 
 : 
 MutateOperation 
 = 
 client 
 . 
 get_type 
 ( 
 "MutateOperation" 
 ) 
 asset_group_asset 
 : 
 AssetGroupAsset 
 = 
 ( 
 mutate_operation_group_as>set 
 . 
 asset_group_asset_operation 
 . 
 create 
 ) 
 asset_group_asset 
 . 
 field_type 
 = 
 field_type 
 asset_group_asset 
 . 
 asset_group 
 = 
 asset_group_service 
 . 
 asset_group_path 
 ( 
 customer_id 
 , 
 _ASSET_GROUP_TEMPORARY_ID 
 , 
 ) 
 asset_group_asset 
 . 
 asset 
 = 
 asset_temp_resource_name 
 operations 
 . 
 append 
 ( 
 mutate_operation_group_asset 
 ) 
 _next_temp_id 
 -= 
 1 
 return 
 operations 
 def 
  
 sort_asset_and_asset_group_asset_operations 
 ( 
 operations 
 : 
 List 
 [ 
 MutateOperation 
 ], 
 ) 
 - 
 List 
 [ 
 MutateOperation 
 ]: 
  
 """Sorts a list of asset and asset group asset operations. 
 This so>rts the list such that all asset operations precede 
 all asset group asset operations. If asset group assets are 
 created before assets then an error will be returned by 
 the API. 
 Args: 
 operations: a list of asset and asset group asset operations. 
 Returns: 
 a sorted list of asset and asset group asset operations. 
 """ 
 def 
  
 sorter 
 ( 
 operation 
 : 
 MutateOperation 
 ) 
 - 
 bool 
 : 
  
 """Determines whether the operation creates an asset group asset. 
 Args: 
 operation: a MutateOperation instance. 
 Returns: 
 True if the MutateOperation creates an asset group asset. 
 """ 
 # Check if the oneof field 'asset_group_asset_operation' is set. 
 return 
 ( 
 operation 
 . 
 asset_group_asset_operation 
 != 
 type 
 ( 
 operation 
 . 
 asset_group_asset_operation 
 )() 
 ) 
 return 
 sorted 
 ( 
 operations 
 , 
 key 
 = 
 sorter 
 ) 
 def 
  
 get_customer_conversion_goals 
 ( 
 client 
 : 
 GoogleAdsClient 
 , 
 customer_id 
 : 
 str 
 ) 
 - 
 List 
 [ 
 Dict 
 [ 
 str 
 , 
 Union 
 [ 
 ConversionActionCategoryEnum 
 . 
 ConversionActionCategory 
 , 
 ConversionOriginEnum 
 . 
 ConversionOrigin 
 , 
 ], 
 ] 
 ]: 
  
 """Retrieves the list of customer conversion goals. 
 Args: 
 client: an initialized GoogleAdsClient instance. 
 customer_id: a client customer ID. 
 Returns: 
 a list of dicts containing the category and origin of customer 
 conversion goals. 
 """ 
 ga_service 
 : 
 GoogleAdsServiceClient 
 = 
 client 
 . 
 get_service 
 ( 
 "GoogleAdsService" 
 ) 
 customer_conversion_goals 
 : 
 List 
 [ 
 Dict 
 [ 
 str 
 , 
 Union 
 [ 
 ConversionActionCategoryEnum 
 . 
 ConversionActionCategory 
 , 
 ConversionOriginEnum 
 . 
 ConversionOrigin 
 , 
 ], 
 ] 
 ] 
 = 
 [] 
 query 
 : 
 str 
 = 
 """ 
 SELECT 
 customer_conversion_goal.category, 
 customer_conversion_goal.origin 
 FROM customer_convers>ion_goal 
 """ 
 # The number of conversion goals is typically less than 50 so we use 
 # GoogleAdsService.search instead of search_stream. 
 search_request 
 : 
 SearchGoogleAdsRequest 
 = 
 client 
 . 
 get_type 
 ( 
 "SearchGoogleAdsRequest" 
 ) 
 search_request 
 . 
 customer_id 
 = 
 customer_id 
 search_request 
 . 
 query 
 = 
 query 
 results 
 : 
 SearchGoogleAdsResponse 
 = 
 ga_service 
 . 
 search 
 ( 
 request 
 = 
 search_request 
 ) 
 # Iterate over the results and build the list of conversion goals. 
 for 
 row 
 in 
 results 
 : 
 customer_conversion_goals 
 . 
 append 
 ( 
 { 
 "category" 
 : 
 row 
 . 
 customer_conversion_goal 
 . 
 category 
 , 
 "origin" 
 : 
 row 
 . 
 customer_conversion_goal 
 . 
 origin 
 , 
 } 
 ) 
 return 
 customer_conversion_goals 
 def 
  
 create_conversion_goal_operations 
 ( 
 client 
 : 
 GoogleAdsClient 
 , 
 customer_id 
 : 
 str 
 , 
 customer_conversion_goals 
 : 
 List 
 [ 
 Dict 
 [ 
 str 
 , 
 Union 
 [ 
 ConversionActionCategoryEnum 
 . 
 ConversionActionCategory 
 , 
 ConversionOriginEnum 
 . 
 ConversionOrigin 
 , 
 ], 
 ] 
 ], 
 ) 
 - 
 List 
 [ 
 MutateOperation 
 ]: 
  
 """Creates a list of MutateOperations that override customer conversion goals. 
 Args: 
 client: an initialized GoogleAdsClient instance. 
 customer_id: a client customer ID. 
 customer_conversion_goals: the list of customer conversion goals that 
 will be overridden. 
 Returns: 
 MutateOperations that update campaign conversion goals. 
 """ 
 campaign_conversion_goal_service 
 : 
 CampaignConversionGoalServiceClient 
 = 
 ( 
 client 
 . 
 get_service 
 ( 
 "CampaignConversionGoalService" 
 ) 
 ) 
 operations 
 : 
 List 
 [ 
 MutateOperation 
 ] 
 = 
 [] 
 # To override the customer conversion goals, we will change the 
 # biddability of each of the customer conversion goals so that only 
 # the desired conversion goal is biddable in this campaign. 
 for 
 customer_goal_dict 
 in 
 customer_conversion_goals 
 : 
 mutate_operation 
 : 
 MutateOperation 
 = 
 client 
 . 
 get_type 
 ( 
 "MutateOperation" 
 ) 
 campaign_conversion_goal 
 : 
 CampaignConversionGoal 
 = 
 ( 
 mutate_operation 
 . 
 campaign_conversion_goal_operation 
 . 
 update 
 ) 
 category_enum_value 
 : 
 ( 
 ConversionActionCategoryEnum 
 . 
 ConversionActionCategory 
 ) 
 = 
 customer_goal_dict 
 [ 
 "category" 
 ] 
 origin_enum_value 
 : 
 ConversionOriginEnum 
 . 
 ConversionOrigin 
 = 
 ( 
 customer_goal_dict 
 [ 
 "origin" 
 ] 
 ) 
 campaign_conversion_goal 
 . 
 resource_name 
 = 
 ( 
 campaign_conversion_goal_service 
 . 
 campaign_conversion_goal_path 
 ( 
 customer_id 
 , 
 _PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 , 
 category_enum_value 
 . 
 name 
 , 
 origin_enum_value 
 . 
 name 
 , 
 ) 
 ) 
 # Change the biddability for the campaign conversion goal. 
> # Set biddability to True for the desired (category, origin). 
 # Set biddability to False for all other conversion goals. 
 # Note: 
 #  1- It is assumed that this Conversion Action 
 #     (category=PURCHASE, origin=WEBSITE) exists in this account. 
 #  2- More than one goal can be biddable if desired. This example 
 #     shows only one. 
 if 
 ( 
 category_enum_value 
 == 
 client 
 . 
 enums 
 . 
 ConversionActionCategoryEnum 
 . 
 PURCHASE 
 and 
 origin_enum_value 
 == 
 client 
 . 
 enums 
 . 
 ConversionOriginEnum 
 . 
 WEBSITE 
 ): 
 biddable 
 = 
 True 
 else 
 : 
 biddable 
 = 
 False 
 campaign_conversion_goal 
 . 
 biddable 
 = 
 biddable 
 field_mask 
 = 
 protobuf_helpers 
 . 
 field_mask 
 ( 
 None 
 , 
 campaign_conversion_goal 
 . 
 _pb 
 ) 
 client 
 . 
 copy_from 
 ( 
 mutate_operation 
 . 
 campaign_conversion_goal_operation 
 . 
 update_mask 
 , 
 field_mask 
 , 
 ) 
 operations 
 . 
 append 
 ( 
 mutate_operation 
 ) 
 return 
 operations 
 def 
  
 create_and_link_brand_assets 
 ( 
 client 
 : 
 GoogleAdsClient 
 , 
 customer_id 
 : 
 str 
 , 
 brand_guidelines_enabled 
 : 
 bool 
 , 
 business_name 
 : 
 str 
 , 
 logo_url 
 : 
 str 
 , 
 logo_name 
 : 
 str 
 , 
 ) 
 - 
 List 
 [ 
 MutateOperation 
 ]: 
  
 """Creates a list of MutateOperations that create linked brand assets. 
 Args: 
 client: an initialized GoogleAdsClient instance. 
 customer_id: a client customer ID. 
 brand_guidelines_enabled: a boolean value indicating if the campaign is 
 enabled for brand guidelines. 
 business_name: the business name text to be put into an asset. 
 logo_url: the url of the logo to be retrieved and put into an asset. 
 logo_name: the asset name of the logo. 
 Returns: 
 MutateOperations that create linked brand assets. 
 """ 
 global 
 _next_temp_id 
 operations 
 : 
 List 
 [ 
 MutateOperation 
 ] 
 = 
 [] 
 asset_service 
 : 
 AssetServiceClient 
 = 
 client 
 . 
 get_service 
 ( 
 "AssetService" 
 ) 
 # Create the Text Asset. 
 text_asset_temp_id 
 : 
 int 
 = 
 _next_temp_id 
 _next_temp_id 
 -= 
 1 
 text_asset_resource_name 
 = 
 asset_service 
 . 
 asset_path 
 ( 
 customer_id 
 , 
 str 
 ( 
 text_asset_temp_id 
 ) 
 ) 
 text_mutate_operation 
 : 
 MutateOperation 
 = 
 client 
 . 
 get_type 
 ( 
 "MutateOperation" 
 ) 
 text_asset_obj 
 : 
 Asset 
 = 
 text_mutate_operation 
 . 
 asset_operation 
 . 
 create 
 text_asset_obj 
 . 
 resource_name 
 = 
 text_asset_resource_name 
 text_asset_obj 
 . 
 text_asset 
 . 
 text 
 = 
 business_name 
 operations 
 . 
 append 
 ( 
 text_mutate_operation 
 ) 
 # Create the Image Asset. 
 image_asset_temp_id 
 : 
 int 
 = 
 _next_temp_id 
 _next_temp_id 
 -= 
 1 
 image_asset_resource_name 
 = 
 asset_service 
 . 
 asset_path 
 ( 
 customer_id 
 , 
 str 
 ( 
 image_asset_temp_id 
 ) 
 ) 
 image_mutate_operation 
 : 
 MutateOperation 
 = 
 client 
 . 
 get_type 
 ( 
 "MutateOperation" 
 ) 
 image_asset_obj 
 : 
 Asset 
 = 
 image_mutate_operation 
 . 
 asset_operation 
 . 
 create 
 image_asset_obj 
 . 
 resource_name 
 = 
 image_asset_resource_name 
 # Provide a unique friendly name to identify your asset. 
 # When there is an existing image asset with the same content but a different 
 # name, the new name will be dropped silently. 
 image_asset_obj 
 . 
 name 
 = 
 logo_name 
 image_asset_obj 
 . 
 type_ 
 = 
 client 
 . 
 enums 
 . 
 AssetTypeEnum 
 . 
 IMAGE 
 image_asset_obj 
 . 
 image_asset 
 . 
 data 
 = 
 get_image_bytes_from_url 
 ( 
 logo_url 
 ) 
 operations 
 . 
 append 
 ( 
 image_mutate_operation 
 ) 
 if 
 brand_guidelines_enabled 
 : 
 # Create CampaignAsset resources to link the Asset resources to the Campaign. 
 campaign_service 
 : 
 CampaignServiceClient 
 = 
 client 
 . 
 get_service 
 ( 
 "CampaignService" 
 ) 
 business_name_ca_mutate_op 
 : 
 MutateOperation 
 = 
 client 
 . 
 get_type 
 ( 
 "MutateOperation" 
 ) 
 business_name_campaign_asset 
 : 
 CampaignAsset 
 = 
 ( 
 business_name_ca_mutate_op 
 . 
 campaign_asset_operation 
 . 
 create 
 ) 
 business_name_campaign_asset 
 . 
 field_type 
 = 
 ( 
 client 
 . 
 enums 
 . 
 AssetFieldTypeEnum 
 . 
 BUSINESS_NAME 
 ) 
 business_name_campaign_asset 
 . 
 campaign 
 = 
 campaign_service 
 . 
 campaign_path 
 ( 
 customer_id 
 , 
 _PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 ) 
 business_name_campaign_asset 
 . 
 asset 
 = 
 text_asset_resource_name 
 operations 
 . 
 append 
 ( 
 business_name_ca_mutate_op 
 ) 
 logo_ca_mutate_op 
 : 
 MutateOperation 
 = 
 client 
 . 
 get_type 
 ( 
 "MutateOperation" 
 ) 
 logo_campaign_asset 
 : 
 CampaignAsset 
 = 
 ( 
 logo_ca_mutate_op 
 . 
 campaign_asset_operation 
 . 
 create 
 ) 
 logo_campaign_asset 
 . 
 field_type 
 = 
 client 
 . 
 enums 
 . 
 AssetFieldTypeEnum 
 . 
 LOGO 
 logo_campaign_asset 
 . 
 campaign 
 = 
 campaign_service 
 . 
 campaign_path 
 ( 
 customer_id 
 , 
 _PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 ) 
 logo_campaign_asset 
 . 
 asset 
 = 
 image_asset_resource_name 
 operations 
 . 
 append 
 ( 
 logo_ca_mutate_op 
 ) 
 else 
 : 
 # Create AssetGroupAsset resources to link the Asset resources to the AssetGroup. 
 asset_group_service 
 : 
 AssetGroupServiceClient 
 = 
 client 
 . 
 get_service 
 ( 
 "AssetGroupService" 
 ) 
 business_name_aga_mutate_op 
 : 
 MutateOperation 
 = 
 client 
 . 
 get_type 
 ( 
> "MutateOperation" 
 ) 
 business_name_asset_group_asset 
 : 
 AssetGroupAsset 
 = 
 ( 
 business_name_aga_mutate_op 
 . 
 asset_group_asset_operation 
 . 
 create 
 ) 
 business_name_asset_group_asset 
 . 
 field_type 
 = 
 ( 
 client 
 . 
 enums 
 . 
 AssetFieldTypeEnum 
 . 
 BUSINESS_NAME 
 ) 
 business_name_asset_group_asset 
 . 
 asset_group 
 = 
 ( 
 asset_group_service 
 . 
 asset_group_path 
 ( 
 customer_id 
 , 
 _ASSET_GROUP_TEMPORARY_ID 
 , 
 ) 
 ) 
 business_name_asset_group_asset 
 . 
 asset 
 = 
 text_asset_resource_name 
 operations 
 . 
 append 
 ( 
 business_name_aga_mutate_op 
 ) 
 logo_aga_mutate_op 
 : 
 MutateOperation 
 = 
 client 
 . 
 get_type 
 ( 
 "MutateOperation" 
 ) 
 logo_asset_group_asset 
 : 
 AssetGroupAsset 
 = 
 ( 
 logo_aga_mutate_op 
 . 
 asset_group_asset_operation 
 . 
 create 
 ) 
 logo_asset_group_asset 
 . 
 field_type 
 = 
 client 
 . 
 enums 
 . 
 AssetFieldTypeEnum 
 . 
 LOGO 
 logo_asset_group_asset 
 . 
 asset_group 
 = 
 ( 
 asset_group_service 
 . 
 asset_group_path 
 ( 
 customer_id 
 , 
 _ASSET_GROUP_TEMPORARY_ID 
 , 
 ) 
 ) 
 logo_asset_group_asset 
 . 
 asset 
 = 
 image_asset_resource_name 
 operations 
 . 
 append 
 ( 
 logo_aga_mutate_op 
 ) 
 return 
 operations 
 def 
  
 print_response_details 
 ( 
 response 
 : 
 MutateGoogleAdsResponse 
 ) 
 - 
 None 
 : 
  
 """Prints the details of a MutateGoogleAdsResponse. 
 Parses the "response" oneof field name and uses it to extract the new 
 entity's name and resource name. 
 Args: 
 response: a MutateGoogleAdsResponse object. 
 """ 
 # Parse the Mutate response to print details about the entities that 
 # were created by the request. 
 suffix 
 : 
 str 
 = 
 "_result" 
 for 
 result_item 
 in 
 response 
 . 
 mutate_operation_responses 
 : 
 # Ensure result_item is MutateOperationResponse, not just Any 
 result_pb 
 : 
 MutateOperationResponse 
 = 
 result_item 
 for 
 field_descriptor 
 , 
 value 
 in 
 result_pb 
 . 
 _pb 
 . 
 ListFields 
 (): 
 field_name_str 
 : 
 str 
 = 
 field_descriptor 
 . 
 name 
 if 
 field_name_str 
 . 
 endswith 
 ( 
 suffix 
 ): 
 name 
 = 
 field_name_str 
 [: 
 - 
 len 
 ( 
 suffix 
 )] 
 else 
 : 
 name 
 = 
 field_name_str 
 print 
 ( 
 f 
 "Created a(n) 
 { 
 convert_snake_case_to_upper_case 
 ( 
 name 
 ) 
 } 
 with " 
 f 
 " 
 { 
 str 
 ( 
 value 
 ) 
 . 
 strip 
 () 
 } 
 ." 
 ) 
 if 
 __name__ 
 == 
 "__main__" 
 : 
 parser 
 = 
 argparse 
 . 
 ArgumentParser 
 ( 
 description 
 = 
 ( 
 "Creates a Performance Max retail campaign." 
 ) 
 ) 
 # 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." 
 , 
 ) 
 parser 
 . 
 add_argument 
 ( 
 "-m" 
 , 
 "--merchant_center_account_id" 
 , 
 type 
 = 
 int 
 , 
 required 
 = 
 True 
 , 
 help 
 = 
 "The Merchant Center account ID." 
 , 
  
uot;-u" , 
 "--final_url" 
 , 
 type 
 = 
 str 
 , 
 required 
 = 
 False 
 , 
 default 
 = 
 "http://www.example.com" 
 , 
 help 
 = 
 "The final URL for the asset group of the campaign." 
 , 
 ) 
 parser 
 . 
 add_argument 
 ( 
 "-b" 
 , 
 "--brand_guidelines_enabled" 
 , 
 type 
 = 
 bool 
 , 
 default 
 = 
 False 
 , 
 help 
 = 
 ( 
 "A boolean value indicating if the created campaign is enabled " 
 "for brand guidelines." 
 ), 
 ) 
 args 
 : 
 argparse 
 . 
 Namespace 
 = 
 parser 
 . 
 parse_args 
 () 
 # GoogleAdsClient will read the google-ads.yaml configuration file in the 
 # home directory if none is specified. 
 googleads_client 
 : 
 GoogleAdsClient 
 = 
 GoogleAdsClient 
 . 
 load_from_storage 
 ( 
 version 
 = 
 "v21" 
 ) 
 try 
 : 
 main 
 ( 
 googleads_client 
 , 
 args 
 . 
 customer_id 
 , 
 args 
 . 
 merchant_center_account_id 
 , 
 args 
 . 
 final_url 
 , 
 args 
 . 
 brand_guidelines_enabled 
 , 
 ) 
 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 
 ' 
 \t 
 Error with message " 
 { 
 error 
 . 
 message 
 } 
 ".' 
 ) 
 if 
 error 
 . 
 location 
 : 
 for 
 field_path_element 
 in 
 error 
 . 
 location 
 . 
 field_path_elements 
 : 
 print 
 ( 
 f 
 " 
 \t\t 
 On field: 
 { 
 field_path_element 
 . 
 field_name 
 } 
 " 
 ) 
 sys 
 . 
 exit 
 ( 
 1 
 ) 
 add_performance_max_retail_campaign 
 . 
 py 

Ruby

 #!/usr/bin/env ruby 
 # Encoding: utf-8 
 # 
 # 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 
 # 
 #     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 Performance Max retail campaign. 
 # 
 # This will be created for "All products". 
 # 
 # For more information about Performance Max retail campaigns, see 
 # https://developers.google.com/google-ads/api/docs/performance-max/retail 
 # 
 # Prerequisites: 
 # - You need to have access to a Merchant Center account. You can find 
 #   instructions to create a Merchant Center account here: 
 #   https://support.google.com/merchants/answer/188924. 
 #   This account must be linked to your Google Ads account. The integration 
 #   instructions can be found at: 
 #   https://developers.google.com/google-ads/api/docs/shopping-ads/merchant-center 
 # - You need your Google Ads account to track conversions. The different ways 
 #   to track conversions can be found here: 
 #   https://support.google.com/google-ads/answer/1722054. 
 # - You must have at least one conversion action in the account. For 
 #   more about conversion actions, see 
 #   https://developers.google.com/google-ads/api/docs/conversions/overview#conversion_actions 
 require 
  
 'optparse' 
 require 
  
 'date' 
 require 
  
 'open-uri' 
 require 
  
 'google/ads/google_ads' 
 # We specify temporary IDs that are specific to a single mutate request. 
 # Temporary IDs are always negative and unique within one mutate request. 
 # 
 # See https://developers.google.com/google-ads/api/docs/mutating/best-practices 
 # for further details. 
 # 
 # These temporary IDs are fixed because they are used in multiple places. 
 BUDGET_TEMPORARY_ID 
  
 = 
  
 "-1" 
 PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
  
 = 
  
 "-2" 
 ASSET_GROUP_TEMPORARY_ID 
  
 = 
  
 "-3" 
 # There are also entities that will be created in the same request but do not 
 # need to be fixed temporary IDs because they are referenced only once. 
 def 
  
 next_temp_id 
  
 @id 
  
 ||= 
  
 ASSET_GROUP_TEMPORARY_ID 
 . 
 to_i 
  
 @id 
  
 -= 
  
 1 
 end 
 def 
  
 add_performance_max_retail_campaign 
 ( 
  
 customer_id 
 , 
  
 merchant_center_account_id 
 , 
  
 final_url 
 , 
  
 brand_guidelines_enabled 
 ) 
  
 # GoogleAdsClient will read a config file from 
  
 # ENV['HOME']/google_ads_config.rb when called without parameters 
  
 client 
  
 = 
  
 Google 
 :: 
 Ads 
 :: 
 GoogleAds 
 :: 
 GoogleAdsClient 
 . 
 new 
  
 # This campaign will override the customer conversion goals. 
  
 # Retrieve the current list of customer conversion goals. 
  
 customer_conversion_goals 
  
 = 
  
 _get_customer_conversion_goals 
 ( 
  
 client 
 , 
  
 customer_id 
 ) 
  
 # Performance Max campaigns require that repeated assets such as headlines 
  
 # and descriptions be created before the campaign. 
  
 # For the list of required assets for a Performance Max campaign, see 
  
 # https://developers.google.com/google-ads/api/docs/performance-max/assets 
  
 # 
  
 # Create the headlines. 
  
 headline_asset_resource_names 
  
 = 
  
 create_multiple_text_assets 
 ( 
  
 client 
 , 
  
 customer_id 
 , 
  
 [ 
  
 "Travel" 
 , 
  
 "Travel Reviews" 
 , 
  
 "Book travel" 
 , 
  
 ] 
 ) 
  
 # Create the descriptions. 
  
 description_asset_resource_names 
  
 = 
  
 create_multiple_text_assets 
 ( 
  
 client 
 , 
  
 customer_id 
 , 
  
 [ 
  
 "Take to the air!" 
 , 
  
 "Fly to the sky!" 
 , 
  
 ] 
 ) 
  
 # The below methods create and return MutateOperations that we later 
  
 # provide to the GoogleAdsService.Mutate method in order to create the 
  
 # entities in a single request. Since the entities for a Performance Max 
  
 # campaign are closely tied to one-another, it's considered a best practice 
  
 # to create them in a single Mutate request so they all complete 
  
 # successfully or fail entirely, leaving no orphaned entities. See: 
  
 # https://developers.google.com/google-ads/api/docs/mutating/overview 
  
 campaign_budget_operation 
  
 = 
  
 create_campaign_budget_operation 
 ( 
  
 client 
 , 
  
 customer_id 
 , 
  
 ) 
  
 performance_max_campaign_operation 
  
 = 
  
 create_performance_max_campaign_operation 
 ( 
  
 client 
 , 
  
 customer_id 
 , 
  
 merchant_center_account_id 
 , 
  
 brand_guidelines_enabled 
 , 
  
 ) 
  
 campaign_criterion_operations 
  
 = 
  
 create_campaign_criterion_operations 
 ( 
  
 client 
 , 
  
 customer_id 
 , 
  
 ) 
  
 asset_group_operation 
  
 = 
  
 create_asset_group_operation 
 ( 
  
 client 
 , 
  
 customer_id 
 , 
  
 final_url 
 , 
  
 ) 
  
 listing_group_filter_operation 
  
 = 
  
 create_listing_group_filter_operation 
 ( 
  
 client 
 , 
  
 customer_id 
 , 
  
 ) 
  
 asset_and_asset_group_asset_operations 
  
 = 
  
 create_asset_and_asset_group_asset_operations 
 ( 
  
 client 
 , 
  
 customer_id 
 , 
  
 headline_asset_resource_names 
 , 
  
 description_asset_resource_names 
 , 
  
 brand_guidelines_enabled 
 , 
  
 ) 
  
 conversion_goal_operations 
  
 = 
  
 create_conversion_goal_operations 
 ( 
  
 client 
 , 
  
 customer_id 
 , 
  
 customer_conversion_goals 
 , 
  
 ) 
  
 # Send the operations in a single Mutate request. 
  
 response 
  
 = 
  
 client 
 . 
 service 
 . 
 google_ads 
 . 
 mutate 
 ( 
  
 customer_id 
 : 
  
 customer_id 
 , 
  
 mutate_operations 
 : 
  
 [ 
  
 # It's important to create these entities in this order because 
  
 # they depend on each other. 
  
 campaign_budget_operation 
 , 
  
 performance_max_campaign_operation 
 , 
  
 # Expand the list of multiple operations into the list of 
  
 # other mutate operations 
  
 campaign_criterion_operations 
 , 
  
 asset_group_operation 
 , 
  
 listing_group_filter_operation 
 , 
  
 asset_and_asset_group_asset_operations 
 , 
  
 conversion_goal_operations 
 , 
  
 ]. 
 flatten 
 ) 
  
 print_response_details 
 ( 
 response 
 ) 
 end 
 # Creates a MutateOperation that creates a new CampaignBudget. 
 # 
 # A temporary ID will be assigned to this campaign budget so that it can be 
 # referenced by other objects being created in the same Mutate request. 
 def 
  
 create_campaign_budget_operation 
 ( 
 client 
 , 
  
 customer_id 
 ) 
  
 client 
 . 
 operation 
 . 
 mutate 
  
 do 
  
 | 
 m 
 | 
  
 m 
 . 
 campaign_budget_operation 
  
 = 
  
 client 
 . 
 operation 
 . 
 create_resource 
 . 
 campaign_budget 
  
 do 
  
 | 
 cb 
 | 
  
 cb 
 . 
 name 
  
 = 
  
 "Performance Max campaign budget 
 #{ 
 SecureRandom 
 . 
 uuid 
 } 
 " 
  
 # The budget period already defaults to DAILY. 
  
 cb 
 . 
 amount_micros 
  
 = 
  
 50_000_000 
  
 cb 
 . 
 delivery_method 
  
 = 
  
 :STANDARD 
  
 # A Performance Max campaign cannot use a shared campaign budget. 
  
 cb 
 . 
 explicitly_shared 
  
 = 
  
 false 
  
 # Set a temporary ID in the budget's resource name so it can be referenced 
  
 # by the campaign in later steps. 
  
 cb 
 . 
 resource_name 
  
 = 
  
 client 
 . 
 path 
 . 
 campaign_budget 
 ( 
 customer_id 
 , 
  
 BUDGET_TEMPORARY_ID 
 ) 
  
 end 
  
 end 
  
 end 
 # Creates a MutateOperation that creates a new Performance Max campaign. 
 # 
 # A temporary ID will be assigned to this campaign so that it can 
 # be referenced by other objects being created in the same Mutate request. 
 def 
  
 create_performance_max_campaign_operation 
 ( 
  
 client 
 , 
  
 customer_id 
 , 
  
 merchant_center_account_id 
 , 
  
 brand_guidelines_enabled 
 ) 
  
 client 
 . 
 operation 
 . 
 mutate 
  
 do 
  
 | 
 m 
 | 
  
 m 
 . 
 campaign_operation 
  
 = 
  
 client 
 . 
 operation 
 . 
 create_resource 
 . 
 campaign 
  
 do 
  
 | 
 c 
 | 
  
 c 
 . 
 name 
  
 = 
  
 "Performance Max retail campaign 
 #{ 
 SecureRandom 
 . 
 uuid 
 } 
 " 
  
 # Set the campaign status as PAUSED. The campaign is the only entity in 
  
 # the mutate request that should have its status set. 
  
 c 
 . 
 status 
  
 = 
  
 :PAUSED 
  
 # All Performance Max campaigns have an advertising_channel_type of 
  
 # PERFORMANCE_MAX. The advertising_channel_sub_type should not be set. 
  
 c 
 . 
 advertising_channel_type 
  
 = 
  
 :PERFORMANCE_MAX 
  
 # Bidding strategy must be set directly on the campaign. 
  
 # Setting a portfolio bidding strategy by resource name is not supported. 
  
 # Max Conversion and Maximize Conversion Value are the only strategies 
  
 # supported for Performance Max campaigns. 
  
 # An optional ROAS (Return on Advertising Spend) can be set for 
  
 # maximize_conversion_value. The ROAS value must be specified as a ratio in 
  
 # the API. It is calculated by dividing "total value" by "total spend". 
  
 # For more information on Maximize Conversion Value, see the support 
  
 # article: http://support.google.com/google-ads/answer/7684216. 
  
 # A target_roas of 3.5 corresponds to a 350% return on ad spend. 
  
 c 
 . 
 bidding_strategy_type 
  
 = 
  
 :MAXIMIZE_CONVERSION_VALUE 
  
 c 
 . 
 maximize_conversion_value 
  
 = 
  
 client 
 . 
 resource 
 . 
 maximize_conversion_value 
  
 do 
  
 | 
 mcv 
 | 
  
 mcv 
 . 
 target_roas 
  
 = 
  
 3 
 . 
 5 
  
 end 
  
 # Set the shopping settings. 
  
 c 
 . 
 shopping_setting 
  
 = 
  
 client 
 . 
 resource 
 . 
 shopping_setting 
  
 do 
  
 | 
 ss 
 | 
  
 ss 
 . 
 merchant_id 
  
 = 
  
 merchant_center_account_id 
  
 # Optional: To use products only from a specific feed, set feed_label 
  
 # to the feed label used in Merchant Center. 
  
 # See: https://support.google.com/merchants/answer/12453549. 
  
 # Omitting the feed_label field will use products from all feeds. 
  
 # feed_label = "INSERT_FEED_LABEL_HERE" 
  
 end 
  
 # Set the Final URL expansion opt out. This flag is specific to 
  
 # Performance Max campaigns. If opted out (true), only the final URLs in 
  
 # the asset group or URLs specified in the advertiser's Google Merchant 
  
 # Center or business data feeds are targeted. 
  
 # If opted in (false), the entire domain will be targeted. For best 
  
 # results, set this value to false to opt in and allow URL expansions. You 
  
 # can optionally add exclusions to limit traffic to parts of your website. 
  
 # 
  
 # For a Retail campaign, we want the final URLs to be limited to those 
  
 # explicitly surfaced via GMC. 
  
 c 
 . 
 url_expansion_opt_out 
  
 = 
  
 true 
  
 # Set if the campaign is enabled for brand guidelines. For more 
  
 # information on brand guidelines, see 
  
 # https://support.google.com/google-ads/answer/14934472. 
  
 c 
 . 
 brand_guidelines_enabled 
  
 = 
  
 brand_guidelines_enabled 
  
 # Assign the resource name with a temporary ID. 
  
 c 
 . 
 resource_name 
  
 = 
  
 client 
 . 
 path 
 . 
 campaign 
 ( 
 customer_id 
 , 
  
 PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 ) 
  
 # Set the budget using the given budget resource name. 
  
 c 
 . 
 campaign_budget 
  
 = 
  
 client 
 . 
 path 
 . 
 campaign_budget 
 ( 
 customer_id 
 , 
  
 BUDGET_TEMPORARY_ID 
 ) 
  
 # Declare whether or not this campaign serves political ads targeting the EU 
  
 # Valid values are CONTAINS_EU_POLITICAL_ADVERTISING and 
  
 # DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING 
  
 c 
 . 
 contains_eu_political_advertising 
  
 = 
  
 :DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING 
  
 # Optional fields 
  
 c 
 . 
 start_date 
  
 = 
  
 DateTime 
 . 
 parse 
 (( 
 Date 
 . 
 today 
  
 + 
  
 1 
 ) 
 . 
 to_s 
 ) 
 . 
 strftime 
 ( 
 '%Y%m%d' 
 ) 
  
 c 
 . 
 end_date 
  
 = 
  
 DateTime 
 . 
 parse 
 ( 
 Date 
 . 
 today 
 . 
 next_year 
 . 
 to_s 
 ) 
 . 
 strftime 
 ( 
 '%Y%m%d' 
 ) 
  
 end 
  
 end 
  
 end 
 # Creates a list of MutateOperations that create new campaign criteria. 
 def 
  
 create_campaign_criterion_operations 
 ( 
 client 
 , 
  
 customer_id 
 ) 
  
 operations 
  
 = 
  
 [] 
  
 # Set the LOCATION campaign criteria. 
  
 # Target all of New York City except Brooklyn. 
  
 # Location IDs are listed here: 
  
 # https://developers.google.<<com/google-ads/api/reference/data/geotargets 
  
 # and they can also be retrieved using the GeoTargetConstantService as shown 
  
 # here: https://developers.google.com/google-ads/api/docs/targeting/location-targeting 
  
 operations 
  
 client 
 . 
 operation 
 . 
 mutate 
  
 do 
  
 | 
 m 
 | 
  
 m 
 . 
 campaign_criterion_operation 
  
 = 
  
 client 
 . 
 operation 
 . 
 create_resource 
 . 
 campaign_criterion 
  
 do 
  
 | 
 cc 
 | 
  
 cc 
 . 
 campaign 
  
 = 
  
 client 
 . 
 path 
 . 
 campaign 
 ( 
  
 customer_id 
 , 
  
 PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 ) 
  
 # Adds one positive location target for New York City (ID=1023191), 
  
 # specifically adding the positive criteria before the negative one. 
  
 cc 
 . 
 location 
  
 = 
  
 client 
 . 
 resource 
 . 
 l<<ocation_info 
  
 do 
  
 | 
 li 
 | 
  
 li 
 . 
 geo_target_constant 
  
 = 
  
 client 
 . 
 path 
 . 
 geo_target_constant 
 ( 
 "1023191" 
 ) 
  
 end 
  
 cc 
 . 
 negative 
  
 = 
  
 false 
  
 end 
  
 end 
  
 # Next add the negative target for Brooklyn (ID=1022762). 
  
 operations 
  
 client 
 . 
 operation 
 . 
 mutate 
  
 do 
  
 | 
 m 
 | 
  
 m 
 . 
 campaign_criterion_operation 
  
 = 
  
 client 
 . 
 operation 
 . 
 create_resource 
 . 
 campaign_criterion 
  
 do 
  
 | 
 cc 
 | 
  
 cc 
 . 
 campaign 
  
 = 
  
 client 
 . 
 path 
 . 
 campaign 
 ( 
  
 customer_id 
 , 
  
 PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_I<<D 
 ) 
  
 cc 
 . 
 location 
  
 = 
  
 client 
 . 
 resource 
 . 
 location_info 
  
 do 
  
 | 
 li 
 | 
  
 li 
 . 
 geo_target_constant 
  
 = 
  
 client 
 . 
 path 
 . 
 geo_target_constant 
 ( 
 "1022762" 
 ) 
  
 end 
  
 cc 
 . 
 negative 
  
 = 
  
 true 
  
 end 
  
 end 
  
 # Set the LANGUAGE campaign criterion. 
  
 operations 
  
 client 
 . 
 operation 
 . 
 mutate 
  
 do 
  
 | 
 m 
 | 
  
 m 
 . 
 campaign_criterion_operation 
  
 = 
  
 client 
 . 
 operation 
 . 
 create_resource 
 . 
 campaign_criterion 
  
 do 
  
 | 
 cc 
 | 
  
 cc 
 . 
 campaign 
  
 = 
  
 client 
 . 
 path 
 . 
 campaign 
 ( 
  
 customer_id 
 , 
  
 PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 ) 
  
 # Set the language. 
  
 # For a list of all language codes, see: 
  
 # https://developers.google.com/google-ads/api/reference/data/codes-formats#expandable-7 
  
 cc 
 . 
 language 
  
 = 
  
 client 
 . 
 resource 
 . 
 language_info 
  
 do 
  
 | 
 li 
 | 
  
 li 
 . 
 language_constant 
  
 = 
  
 client 
 . 
 path 
 . 
 language_constant 
 ( 
 "1000" 
 ) 
  
 # English 
  
 end 
  
 end 
  
 end 
  
 operations 
 end 
 # Creates multiple text assets and returns the list of resource names. 
 # These repeated assets must be created in a separate request prior to creating 
 # the campaign. 
 def 
  
 create_multiple_text_assets 
 ( 
 client 
 , 
  
 customer_id 
 , 
  
 texts 
 ) 
  
 operations 
  
 = 
  
 texts 
 . 
 map 
  
 do 
  
 | 
 text 
 | 
  
 client 
 . 
 operation 
 . 
 mutate 
  
 do 
  
 | 
 m 
 | 
  
 m 
 . 
 asset_operation 
  
 = 
  
 client 
 . 
 operation 
 . 
 create_resource 
 . 
 asset 
  
 do 
  
 | 
 asset 
 | 
  
 asset 
 . 
 text_asset 
  
 = 
  
 client 
 . 
 resource 
 . 
 text_asset 
  
 do 
  
 | 
 text_asset 
 | 
  
 text_asset 
 . 
 text 
  
 = 
  
 text 
  
 end 
  
 end 
  
 end 
  
 end 
  
 # Send the operations in a single Mutate request. 
  
 response 
  
 = 
  
 client 
 . 
 service 
 . 
 google_ads 
 . 
 mutate 
 ( 
  
 customer_id 
 : 
  
 customer_id 
 , 
  
 mutate_operations 
 : 
  
 operations 
 , 
  
 ) 
  
 asset_resource_names 
  
 = 
  
 [] 
  
 response 
 . 
 mutate_operation_responses 
 . 
 each 
  
 do 
  
 | 
 result 
 | 
  
 if 
  
 result 
 . 
 asset_result 
  
 asset_resource_names 
 . 
 append 
 ( 
 result 
 . 
 asset_result 
 . 
 resource_name 
 ) 
  
 end 
  
 end 
  
 print_response_details 
 ( 
 response 
 ) 
  
 asset_resource_names 
 end 
 # Creates a MutateOperation that creates a new asset_group. 
 # 
 # A temporary ID will be assigned to this asset group so that it can 
 # be referenced by other objects being created in the same Mutate request. 
 def 
  
 create_asset_group_operation 
 ( 
  
 client 
 , 
  
 customer_id 
 , 
  
 final_url 
 ) 
  
 # Create the AssetGroup 
  
 client 
 . 
 operation 
 . 
 mutate 
  
 do 
  
 | 
 m 
 | 
  
 m 
 . 
 asset_group_operati<<on 
  
 = 
  
 client 
 . 
 operation 
 . 
 create_resource 
 . 
<< asset_group 
  
 do 
  
 | 
 ag 
 | 
  
 ag 
 . 
 name 
  
 = 
  
 "Performance Max retail asset group 
 #{ 
 SecureRandom 
 . 
 uuid 
 } 
 " 
  
 ag 
 . 
 campaign 
  
 = 
  
 client 
 . 
 path 
 . 
 campaign 
 ( 
  
 customer_id 
 , 
  
 PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 ) 
  
 ag 
 . 
 final_urls 
  
 final_url 
  
 ag 
 . 
 final_mobile_urls 
  
 final_url 
  
 ag 
 . 
 status 
  
 = 
  
 :PAUSED 
  
 ag 
 . 
 resource_name 
  
 = 
  
 client 
 . 
 path 
 . 
 asset_group 
 ( 
  
 customer_id 
 , 
  
 ASSET_GROUP_TEMPORARY_ID 
 , 
  
 ) 
  
 end 
  
 end 
 end 
 # Creates a MutateOperation that creates a new listing group filter. 
 # A temporary ID will be assigned to this listing group filter so that it can 
 # be referenced by other objects being created in the same Mutate request. 
 def 
  
 create_listing_group_filter_operation 
 ( 
 client 
 , 
  
 customer_id 
 ) 
  
 client 
 . 
 operation 
 . 
 mutate 
  
 do 
  
 | 
 m 
 | 
  
 m 
 . 
 asset_group_listing_group_filter_operation 
  
 = 
  
 client 
 . 
 operation 
 . 
 create_resource 
 . 
 asset_group_listing_group_filter 
  
 do 
  
 | 
 aglg 
 | 
  
 aglg 
 . 
 asset_group 
  
 = 
  
 client 
 . 
 path 
 . 
 asset_group 
 ( 
  
 customer_id 
 , 
  
 ASSET_GROUP_TEMPORARY_ID 
 , 
  
 ) 
  
 aglg 
 . 
 type 
  
 = 
  
 :UNIT_INCLUDED 
  
 # Because this is a Performance Max campaign for retail, we need to 
  
 # specify that this is in the shopping listing source. 
  
 aglg 
 . 
 listing_source 
  
 = 
  
 :SHOPPING 
  
 end 
  
 end 
 end 
 # Creates a list of MutateOperations that create a new asset_group. 
 # A temporary ID will be assigned to this asset group so that it can be 
 # referenced by other objects being created in the same Mutate request. 
 def 
  
 create_asset_and_asset_group_asset_operations 
 ( 
  
 client 
 , 
  
 customer_id 
 , 
  
 headline_asset_resource_names 
 , 
  
 description_asset_resource_names 
 , 
  
 brand_guidelines_enabled 
 ) 
  
 operations 
  
 = 
  
 [] 
  
 # For the list of required assets for a Performance Max campaign, see 
  
 # https://developers.google.com/google-ads/api/docs/performance-max/assets 
  
 # 
  
 # An AssetGroup is linked to an Asset by creating a new AssetGroupAsset 
  
 # and providing: 
  
 #   the resource name of the AssetGroup 
  
 #   the resource name of the Asset 
  
 #   the field_type of the Asset in this AssetGroup. 
  
 # 
  
 # To le<<arn more about AssetGroups, see 
  
 # https://developers.google.com/google-ads/api/docs/performance-max/asset-groups 
  
 # Link the previously created multiple text assets. 
  
 # Link the headline assets. 
  
 headline_asset_resource_names 
 . 
 each 
  
 do 
  
 | 
 resource_name 
 | 
  
 operations 
  
 client 
 . 
 operation 
 . 
 mutate 
  
 do 
  
 | 
 m 
 | 
  
 m 
 . 
 asset_group_asset_operation 
  
 = 
  
 client 
 . 
 operation 
 . 
 create_resource 
  
 . 
 asset_group_asset 
  
 do 
  
 | 
 aga 
 | 
  
 aga 
 . 
 field_type 
  
 = 
  
 :HEADLINE 
 << 
 aga 
 . 
 asset_group 
  
 = 
  
 client 
 . 
 path 
 . 
 asset_group 
 ( 
  
 customer_id 
 , 
  
 ASSET_GROUP_TEMPORARY_ID 
 ) 
  
 aga 
 . 
 asset 
  
 = 
  
 resource_name 
  
 end 
  
 end 
  
 end 
  
 #  Link the description assets. 
  
 description_asset_resource_names 
 . 
 each 
  
 do 
  
 | 
 resource_name 
 | 
  
 operations 
  
 client 
 . 
 operation 
 . 
 mutate 
  
 do 
  
 | 
 m 
 | 
  
 m 
 . 
 asset_group_asset_operation 
  
 = 
  
 client 
 . 
 operation 
 . 
 create_resource 
  
 . 
 asset_group_asset 
  
 do 
  
 | 
 aga 
 | 
  
 aga 
 . 
 field_type 
  
 = 
  
 :DESCRIPTION 
  
 aga 
 . 
 asset_group 
  
 = 
  
 client 
 . 
 path 
 . 
 asset_group 
 ( 
  
 customer_id 
 , 
  
 ASSET_GROUP_TEMPORARY_ID 
 ) 
  
 aga 
 . 
 asset 
  
 = 
  
 resource_name 
  
 end 
  
 end 
  
 end 
  
 # Create and link the long headline text asset. 
  
 operations 
  
 += 
  
 create_and_link_text_asset 
 ( 
  
 client 
 , 
  
 customer_id 
 , 
  
 "Travel the World" 
 , 
  
 :LONG_HEADLINE 
 ) 
  
 # Create and link the business name and logo asset. 
  
 operations 
  
 += 
  
 create_and_link_brand_assets 
 ( 
  
 client 
 , 
  
 customer_id 
 , 
  
 brand_guidelines_enabled 
 , 
  
 "Interplanetary Cruises" 
 , 
  
 "https://gaagl.page.link/1Crm" 
 , 
  
 "Logo Image" 
 ) 
  
 # Create and link the image assets. 
  
 # Create and link the Marketing Image Asset. 
  
 operations 
  
 += 
  
 create_and_link_image_asset 
 ( 
  
 client 
 , 
  
 customer_id 
 , 
  
 "https://gaagl.page.link/Eit5" 
 , 
  
 :MARKETING_IMAGE 
 , 
  
 "Marketing Image" 
 ) 
  
 # Create and link the Square Marketing Image Asset. 
  
 operations 
  
 += 
  
 create_and_link_image_asset 
 ( 
  
 client 
 , 
  
 customer_id 
 , 
  
 "https://gaagl.page.link/bjYi" 
 , 
  
 :SQUARE_MARKETING_IMAGE 
 , 
  
 "Square Marketing Image" 
 ) 
  
 # After being created the list must be sorted so that all asset 
  
 # operations come before all the asset group asse<<t operations, 
  
 # otherwise the API will reject the request. 
  
 sort_asset_and_asset_group_asset_operations 
 ( 
 operations 
 ) 
 end 
 # Creates a list of MutateOperations that create a new linked text asset. 
 def 
  
 create_and_link_text_asset 
 ( 
 client 
 , 
  
 customer_id 
 , 
  
 text 
 , 
  
 field_type 
 ) 
  
 operations 
  
 = 
  
 [] 
  
 temp_id 
  
 = 
  
 next_temp_id 
  
 # Create the Text Asset. 
  
 operations 
  
 client 
 . 
 operat<<ion 
 . 
 mutate 
  
 do 
  
 | 
 m 
 | 
  
 m 
 . 
 asset_operation 
  
 = 
  
 client 
 . 
 operation 
 . 
 create_resource 
 . 
 asset 
  
 do 
  
 | 
 a 
 | 
  
 a 
 . 
 resource_name 
  
 = 
  
 client 
 . 
 path 
 . 
 asset 
 ( 
 customer_id 
 , 
  
 temp_id 
 ) 
  
 a 
 . 
 text_asset 
  
 = 
  
 client 
 . 
 resource 
 . 
 text_asset 
  
 do 
  
 | 
 text_asset 
 | 
  
 text_asset 
 . 
 text 
  
 = 
  
 text 
  
 end 
  
 end 
  
 end 
  
 # Create an AssetGroupAsset to link the Asset to the AssetGroup. 
  
 operations 
  
 client 
 . 
 operation 
 . 
 mutate 
  
 do 
  
 | 
 m 
 | 
  
 m 
 . 
 asset_group_asset_operation 
  
 = 
  
 client 
 . 
 operation 
 . 
 create_resource 
  
 . 
 asset_group_asset 
  
 do 
  
 | 
 aga 
 | 
  
 aga 
 . 
 field_type 
  
 = 
  
 field_type 
  
 aga 
 . 
 asset_group 
  
 = 
  
 client 
 . 
 path 
 . 
 asset_group 
 ( 
  
 customer_id 
 , 
  
 ASSET_G<<ROUP_TEMPORARY_ID 
 ) 
  
 aga 
 . 
 asset 
  
 = 
  
 client 
 . 
 path 
 . 
 asset 
 ( 
 customer_id 
 , 
  
 temp_id 
 ) 
  
 end 
  
 end 
  
 operations 
 end 
 # Creates a list of MutateOperations that create a new linked image asset. 
 def 
  
 create_and_link_image_asset 
 ( 
 client 
 , 
  
 customer_id 
 , 
  
 url 
 , 
  
 field_type 
 , 
  
 asset_name 
 ) 
  
 operations 
  
 = 
  
 [] 
  
 temp_id 
  
 = 
  
 next_temp_id 
  
 # Create the Image Asset. 
  
 operations 
  
 client 
 . 
 operation 
 . 
 mutate 
  
 do 
  
 | 
 m 
 | 
  
 m 
 . 
 asset_operation 
  
 = 
  
 client 
 . 
 operation 
 . 
 create_resource 
 . 
 asset 
  
 do 
  
 | 
 a 
 | 
  
 a 
 . 
 resource_name 
  
 = 
  
 client 
 . 
 path 
 . 
 asset 
 ( 
 customer_id 
 , 
  
 temp_id 
 ) 
  
 a 
 . 
 type 
  
 = 
  
 :IMAGE 
  
 # Provide a unique friendly name to identify your asset. 
  
 # When there is an existi<<ng image asset with the same content but a different 
  
 # name, the new name will be dropped silently. 
  
 a 
 . 
 name 
  
 = 
  
 asset_name 
  
 a 
 . 
 image_asset 
  
 = 
  
 client 
 . 
 resource 
 . 
 image_asset 
  
 do 
  
 | 
 image_asset 
 | 
  
 image_asset 
 . 
 data 
  
 = 
  
 get_image_bytes 
 ( 
 url 
 ) 
  
 end 
  
 end 
  
 end 
  
 # Create an AssetGroupAsset to link the Asset to the AssetGroup. 
  
 operations 
  
 client 
 . 
 operation 
 . 
 mutate 
  
 do 
  
 | 
 m 
 | 
  
 m 
 . 
 asset_group_asset_operation 
  
 = 
  
 client 
 . 
 operation 
 . 
 create_resource 
  
 . 
 asset_group_asset 
  
 do 
  
 | 
 aga 
 | 
  
 aga 
 . 
 field_type 
  
 = 
  
 field_type 
  
 aga 
 . 
 asset_group 
  
 = 
  
 client 
 . 
 path 
 . 
 asset_group 
 ( 
  
 customer_id 
 , 
  
 ASSET_GROUP_TEMPORARY_ID 
 ) 
  
 aga 
 . 
 asset 
  
 = 
  
 client 
 . 
 path 
 . 
 asset 
 ( 
 customer_id 
 , 
  
 temp_id 
 ) 
  
 end 
  
 end 
  
 operations 
 end 
 # Sorts a list of asset and asset group asset operations.  This sorts the list 
 # such that all asset operations precede all asset group asset operat<<ions. If 
 # asset group assets are created before assets then an error will be returned 
 # by the API. 
 def 
  
 sort_asset_and_asset_group_asset_operations 
 ( 
 operations 
 ) 
  
 operations 
 . 
 sort_by 
  
 do 
  
 | 
 operation 
 | 
  
 if 
  
 operation 
 . 
 asset_group_asset_operation 
  
 1 
  
 else 
  
 0 
  
 end 
  
 end 
 end 
 def 
  
 _get_customer_conversion_goals 
 ( 
 client 
 , 
  
 customer_id 
 ) 
  
 query 
  
 = 
  
 ~ 
 EOD 
  
 SELECT 
  
 customer_conversion_goal 
 . 
 category 
 , 
  
 customer_conversion_goal 
 . 
 origin 
  
 FROM 
  
 customer_conversion_goal 
  
 EOD 
  
 customer_conversion_goals 
  
 = 
  
 [] 
  
 ga_service 
  
 = 
  
 client 
 . 
 servi<<ce 
 . 
 google_ads 
  
 # The n>umber of conversion goals is typically less than 50 so we >use 
  
 # GoogleAdsService.search instead of search_stream. 
  
 response 
  
 = 
  
 ga_service 
 . 
 search 
 ( 
  
 customer_id 
 : 
  
 customer_id 
 , 
  
 query 
 : 
  
 query 
 , 
  
 ) 
  
 # Iterate over the results and build the list of conversion goals. 
  
 response 
 . 
 each 
  
 do 
  
 | 
 row 
 | 
  
 customer_conversion_goals 
  
 { 
  
 "category" 
  
 = 
  
 row 
 . 
 customer_conversion_goal 
 . 
 category 
 , 
  
 "origin" 
  
 = 
  
 row 
 . 
 customer_conversion_goal 
 . 
 origin 
  
 } 
  
 end 
  
 customer_conversion_goals 
 end 
 def 
  
 create_conversion_goal_operations 
 ( 
 client 
 , 
  
 customer_id 
 , 
  
 customer_conversion_goals 
 ) 
 << 
 campaign_conversion_goal_service 
  
 = 
  
 client 
 . 
 service 
 . 
 campaign_conversion_goal 
  
 operations 
  
 = 
  
 [] 
  
 # To override the customer conversion goals, we will change the 
  
 # biddability of each of the customer conversion goals so that only 
  
 # the desired conversion goal is biddable in this campaign. 
  
 customer_conversion_goals 
 . 
 each 
  
 do 
  
 | 
 customer_conversion_goal 
 | 
  
 operations 
  
 client 
 . 
 operation 
 . 
 mutate 
  
 do 
  
 | 
 m 
 | 
  
 m 
 . 
 campaign_conversion_goal_operation 
  
 = 
  
 client 
 . 
 operation 
 . 
 campaign_conversion_goal 
  
 do 
  
 | 
 op 
 | 
  
 op 
 . 
 update 
  
 = 
  
 client 
 . 
 resource 
 . 
 campaign_conversion_goal 
  
 do 
  
 | 
 ccg 
 | 
  
 ccg 
 . 
 resource_name 
  
 = 
  
 client 
 . 
 path 
 . 
 campaign_conversion_goal 
 ( 
  
 customer_id 
 , 
  
 PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 , 
  
 customer_conversion_goal 
 [ 
 "category" 
 ]. 
 to_s 
 , 
  
 customer_conversion_goal 
 [ 
 "origin" 
 ]. 
 to_s 
 ) 
  
 # Change the biddability for the campaign conversion goal. 
  
 # Set biddability to True for the desired (category, origin). 
  
 # Set biddability to False &&for all other conversion goals. 
  
 # Note: 
  
 #  1- It is assumed that this Conversion Action 
  
 #     (category=PURCHASE, origin=WEBSITE) exists in this account. 
  
 #  2- More than one goal can be biddable if desired. This example 
  
 #     shows only one. 
  
 ccg 
 . 
 biddable 
  
 = 
  
 ( 
 customer_conversion_goal 
 [ 
 "category" 
 ] 
  
 == 
  
 :PURCHASE 
  
  
 customer_conversion_goal 
 [ 
 "origin" 
 ] 
  
 == 
  
 :WEBSITE 
 ) 
  
 end 
  
 op 
 . 
 update_m<<ask 
  
 = 
  
 Google 
 :: 
 Ads 
 :: 
 GoogleAds 
 :: 
 FieldMaskUtil 
 . 
 all_set_fields_of 
 ( 
 op 
 . 
 update 
 ) 
  
 end 
  
 end 
  
 end 
  
 operations 
 end 
 # Creates a list of MutateOperations that create linked brand assets. 
 def 
  
 create_and_link_brand_assets 
 ( 
  
 client 
 , 
  
 customer_id 
 , 
  
 brand_guidelines_enabled 
 , 
  
 business_name 
 , 
  
 logo_url 
 , 
  
 logo_name 
 ) 
  
 operations 
  
 = 
  
 [] 
  
 # Create the Text Asset. 
  
 text_asset_temp_id 
  
<< = 
  
 next_temp_id 
  
 operations 
  
 client 
 . 
 operation 
 . 
 mutate 
  
 do 
  
 | 
 m 
 | 
  
 m 
 . 
 asset_operation 
  
 = 
  
 client 
 . 
 operation 
 . 
 create_resource 
 . 
 asset 
  
 do 
  
 | 
 a 
 | 
  
 a 
 . 
 resource_name 
  
 = 
  
 client 
 . 
 path 
 . 
 asset 
 ( 
 customer_id 
 , 
  
 text_asset_temp_id 
 ) 
  
 a 
 . 
 text_asset 
  
 = 
  
 client 
 . 
 resource 
 . 
 text_asset 
  
 do 
  
 | 
 text_asset 
 | 
  
 text_asset 
 . 
 text 
  
 = 
  
 business_name 
  
 end 
  
 end 
  
 end 
  
 # Create the Image Asset. 
  
 image_asset_temp_id 
  
 = 
  
 next_temp_id 
  
 operations 
  
 client 
 . 
 operation 
 . 
 mutate 
  
 do 
  
 | 
 m 
 | 
  
 m 
 . 
 asset_operation 
  
 = 
  
 client 
 . 
 operation 
 . 
 create_resource 
 . 
 asset 
  
 do 
  
 | 
 a 
 | 
  
 a 
 . 
 resource_name 
  
 = 
  
 client 
 . 
 path 
 . 
 asset 
 ( 
 customer_id 
 , 
  
 image_asset_temp_id 
 ) 
  
 # Provide a unique friendly name to identify your asset. 
  
 # When there is an existing image asse<<t with the same content but a different 
  
 # name, the new name will be dropped silently. 
  
 a 
 . 
 name 
  
 = 
  
 logo_name 
  
 a 
 . 
 type 
  
 = 
  
 :IMAGE 
  
 a 
 . 
 image_asset 
  
 = 
  
 client 
 . 
 resource 
 . 
 image_asset 
  
 do 
  
 | 
 image_asset 
 | 
  
 image_asset 
 . 
 data 
  
 = 
  
 get_image_bytes 
 ( 
 logo_url 
 ) 
  
 end 
  
 end 
  
 end 
  
 if 
  
 brand_guidelines_enabled 
  
 # Create CampaignAsset resources to link the Asset resources to the Campaign. 
  
 op<<erations 
  
 client 
 . 
 operation 
 . 
 mutate 
  
 do 
  
 | 
 m 
 | 
  
 m 
 . 
 campaign_asset_operation 
  
 = 
  
 client 
 . 
 operation 
 . 
 create_resource 
 . 
  
 campaign_asset 
  
 do 
  
 | 
 ca 
 | 
  
 ca 
 . 
 field_type 
  
 = 
  
 :BUSINESS_NAME 
  
 ca 
 . 
 campaign 
  
 = 
  
 client 
 . 
 path 
 . 
 campaign 
 ( 
  
 customer_id 
 , 
  
 PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 , 
  
 ) 
  
 ca 
 . 
 asset 
  
 = 
  
 client 
 . 
 path 
 . 
 asset 
 ( 
 customer_id 
 , 
  
 text_asset_temp_id 
 ) 
  
 end 
  
 end 
  
 operations 
  
 client 
 . 
 operation 
 . 
 mutate 
  
 do 
  
 | 
 m 
 | 
  
 m 
 . 
 campaign_asset_operation 
  
 = 
  
 client 
 . 
 o<<peration 
 . 
 create_resource 
 . 
  
 campaign_asset 
  
 do 
  
 | 
 ca 
 | 
  
 ca 
 . 
 field_type 
  
 = 
  
 :LOGO 
  
 ca 
 . 
 campaign 
  
 = 
  
 client 
 . 
 path 
 . 
 campaign 
 ( 
  
 customer_id 
 , 
  
 PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 , 
  
 ) 
  
 ca 
 . 
 asset 
  
 = 
  
 client 
 . 
 path 
 . 
 asset 
 ( 
 customer_id 
 , 
  
 image_asset_temp_id 
 ) 
  
 end 
  
 end 
  
 else 
  
 # Create AssetGroupAsset resources to link the Asset resources to the AssetGroup. 
  
 opera<<tions 
  
 client 
 . 
 operation 
 . 
 mutate 
  
 do 
  
 | 
 m 
 | 
  
 m 
 . 
 asset_group_asset_operation 
  
 = 
  
 client 
 . 
 operation 
 . 
 create_resource 
 . 
  
 asset_group_asset 
  
 do 
  
 | 
 aga 
 | 
  
 aga 
 . 
 field_type 
  
 = 
  
 :BUSINESS_NAME 
  
 aga 
 . 
 asset_group 
  
 = 
  
 client 
 . 
 path 
 . 
 asset_group 
 ( 
  
 customer_id 
 , 
  
 ASSET_GROUP_TEMPORARY_ID 
 , 
  
 ) 
  
 aga 
 . 
 asset 
  
 = 
  
 client 
 . 
 path 
 . 
 asset 
 ( 
 customer_id 
 , 
  
 text_asset_temp_id 
 ) 
  
 end 
  
 end 
  
 operations 
  
 client 
 . 
 operation 
 . 
 mutate 
  
 do 
  
 | 
 m 
 | 
  
 m 
 . 
 asset_group_asset_operation 
  
 = 
  
 client 
 . 
 operation 
 . 
 create_resource 
 . 
  
 asset_group_asset 
  
 do 
  
 | 
 aga 
 | 
  
 aga 
 . 
 field_type 
  
 = 
  
 :LOGO 
  
 aga 
 . 
 asset_group 
  
 = 
  
 client 
 . 
 path 
 . 
 asset_group 
 ( 
  
 customer_id 
 , 
  
 ASSET_GROUP_TEMPORARY_ID 
 , 
  
 ) 
  
 aga 
 . 
 asset 
  
 = 
  
 client 
 . 
 path 
 . 
 asset 
 ( 
 customer_id 
 , 
  
 image_asset_temp_id 
 ) 
  
 end 
  
 end 
  
 end 
  
 operations 
 end 
 # Loads image data from a URL. 
 def 
  
 get_image_bytes 
 ( 
 url 
 ) 
  
 URI 
 . 
 open 
 ( 
 url 
 ) 
 . 
 read 
  
 end 
  
 # Prints the details of a MutateGoogleAdsResponse. 
  
 def 
  
 print_response_details 
 ( 
 response 
 ) 
  
 # Parse the mutate response to print details about the entities that 
  
 # were created by the request. 
  
 suffix 
  
 = 
  
 "_result" 
  
 response 
 . 
 mutate_operation_responses 
 . 
 each 
  
 do 
  
 | 
 result 
 | 
  
 result 
 . 
 to_h 
 . 
 select 
  
 { 
 | 
 k 
 , 
  
 v 
 | 
  
 v 
  
 } 
 . 
 each 
  
 do 
  
 | 
 name 
 , 
  
 value 
 | 
  
 if 
  
 name 
 . 
 to_s 
 . 
 end_with? 
 ( 
 suffix 
 ) 
  
 name 
  
 = 
  
 name 
 . 
 to_s 
 . 
 delete_suffix 
 ( 
 suffix 
 ) 
  
 end 
  
 puts 
  
 "Created a(n) 
 #{ 
 :: 
 Google 
 :: 
 Ads 
 :: 
 GoogleAds 
 :: 
 Utils 
 . 
 camelize 
 ( 
 name 
 ) 
 } 
 " 
  
 \ 
  
 "with 
 #{ 
 value 
 . 
 to_s 
 . 
 strip 
 } 
 ." 
  
 end 
  
 end 
  
 end 
 if 
  
 __FILE__ 
  
 == 
  
 $0 
  
 options 
  
 = 
  
 {} 
  
 # The following parameter(s) should be provided to run the example. You can 
  
 # either specify these by changing the INSERT_XXX_ID_HERE values below, or on 
  
 # the command line. 
  
 # 
  
 # Parameters passed on the command line will override any parameters set in 
  
 # code. 
  
 # 
  
 # Running the example with -h will print the command line usage. 
  
 options 
 [ 
 :customer_id 
 ] 
  
 = 
  
 'INSERT_CUSTOMER_ID_HERE' 
  
 options 
 [ 
 :merchant_center_account_id 
 ] 
  
 = 
  
 'INSERT_MERCHANT_CENTER_ACCOUNT_ID_HERE' 
  
 options 
 [ 
 :final_url 
 ] 
  
 = 
  
 'INSERT_FINAL_URL_HERE' 
  
 options 
 [ 
 :brand_guidelines_enabled 
 ] 
  
 = 
  
 false 
  
 OptionParser 
 . 
 new 
  
 do 
  
 | 
 opts 
 | 
  
 opts 
 . 
 banner 
  
 = 
  
 sprintf 
 ( 
 'Usage: %s [options]' 
 , 
  
 File 
 . 
 basename 
 ( 
 __FILE__ 
 )) 
  
 opts 
 . 
 separator 
  
 '' 
  
 opts 
 . 
 separator 
  
 'Options:' 
  
 opts 
 . 
 on 
 ( 
 '-C' 
 , 
  
 '--customer-id CUSTOMER-ID' 
 , 
  
 String 
 , 
  
 'Customer ID' 
 ) 
  
 do 
  
 | 
 v 
 | 
  
 options 
 [ 
 :customer_id 
 ] 
  
 = 
  
 v 
  
 end 
  
 opts 
 . 
 on 
 ( 
 '-m' 
 , 
  
 '--merchant-center-account-id MERCHANT-CENTER-ACCOUNT-ID' 
 , 
  
 Integer 
 , 
  
 'Merchant Center Account ID' 
 ) 
  
 do 
  
 | 
 v 
 | 
  
 options 
 [ 
 :merchant_center_account_id 
 ] 
  
 = 
  
 v 
  
 end 
  
 opts 
 . 
 on 
 ( 
 '-f' 
 , 
  
 '--final-url FINAL-URL' 
 , 
  
 String 
 , 
  
 'Final URL' 
 ) 
  
 do 
  
 | 
 v 
 | 
  
 options 
 [ 
 :final_url 
 ] 
  
 = 
  
 v 
  
 end 
  
 opts 
 . 
 on 
 ( 
 '-B' 
 , 
  
 '--brand-guidelines-enabled&>#39; 
 , 
  
 'Enable brand guidelines (optional)' 
 ) 
  
 do 
  
 options 
 [ 
 :brand_guidelines_enabled 
 ] 
  
 = 
  
 true 
  
 end 
  
 opts 
 . 
 separator 
  
 '' 
  
 opts 
 . 
 separator 
  
 'Help:' 
  
 opts 
 . 
 on_tail 
 ( 
 '-h' 
 , 
  
 '--help' 
 , 
  
 'Show this message' 
 ) 
  
 do 
  
 puts 
  
 opts 
  
 exit 
  
 end 
  
 end 
 . 
 parse! 
  
 begin 
  
 add_performance_max_retail_campaign 
 ( 
  
 options 
 . 
 fetch 
 ( 
 :customer_id 
 ) 
 . 
 tr 
 ( 
 "-" 
 , 
  
 "" 
 ), 
  
 options 
 . 
 fetch 
 ( 
 :merchant_center_accoun  
 
 ), 
  
 options 
 . 
 fetch 
 ( 
 :final_url 
 ), 
  
 options 
 [ 
 :brand_guidelines_enabled 
 ] 
 ) 
  
 rescue 
  
 Google 
 :: 
 Ads 
 :: 
 GoogleAds 
 :: 
 Errors 
 :: 
 GoogleAdsError 
  
 = 
  
 e 
  
 e 
 . 
 failure 
 . 
 errors 
 . 
 each 
  
 do 
  
 | 
 error 
 | 
  
 STDERR 
 . 
 printf 
 ( 
 "Error with message: %s 
 \n 
 " 
 , 
  
 error 
 . 
 message 
 ) 
  
 if 
  
 error 
 . 
 location 
  
 error 
 . 
 location 
 . 
 field_path_elements 
 . 
 each 
  
 do 
  
 | 
 field_path_element 
 | 
  
 STDERR 
 . 
 printf 
 ( 
 " 
 \t 
 On field: %s 
 \n 
 " 
 , 
  
 field_path_element 
 . 
 field_name 
 ) 
  
 end 
  
 end 
  
 error 
 . 
 error_code 
 . 
 to_h 
 . 
 each 
  
 do 
  
 | 
 k 
 , 
  
 v 
 | 
  
 next 
  
 if 
  
 v 
  
 == 
  
 :UNSPECIFIED 
  
 STDERR 
 . 
 printf 
 ( 
 " 
 \t 
 Type: %s 
 \n\t 
 Code: %s 
 \n 
 " 
 , 
  
 k 
 , 
  
 v 
 ) 
  
 end 
  
 end 
  
 raise 
  
 end 
  
 end 
 add_performance_max_retail_campaign 
 . 
 rb 
  

Perl

 #!/usr/bin/perl -w 
 # 
 # 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. 
 # 
 # This example shows how to create a Performance Max retail campaign. 
 # 
 # This will be created for "All products". 
 # 
 # For more information about Performance Max retail campaigns, see 
 # https://developers.google.com/google-ads/api/docs/performance-max/retail. 
 # 
 # Prerequisites: 
 # - You need to have access to a Merchant Center account. You can find 
 #   instructions to create a Merchant Center account here: 
 #   https://support.google.com/merchants/answer/188924. 
 #   This account must be linked to your Google Ads account. The integration 
 #   instructions can be found at: 
 #   https://developers.google.com/google-ads/api/docs/shopping-ads/merchant-center. 
 # - You need your Google Ads account to track conversions. The different ways 
 #   to track conversions can be found here: 
 #   https://support.google.com/google-ads/answer/1722054. 
 # - You must have at least one conversion action in the account. For more about 
 #   conversion actions, see 
 #   https://developers.google.com/google-ads/api/docs/conversions/overview#conversion_actions. 
 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::Utils::MediaUtils 
 ; 
 use 
  
 Google::Ads::GoogleAds::Utils::FieldMasks 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Resources::CampaignBudget 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Resources::Campaign 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Resources::ShoppingSetting 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Resources::CampaignCriterion 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Resources::CampaignAsset 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Resources::Asset 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Resources::AssetGroup 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Resources::AssetGroupAsset 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Resources::CampaignConversionGoal 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Resources::AssetGroupListingGroupFilter 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Common::MaximizeConversionValue 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Common::LocationInfo 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Common::LanguageInfo 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Common::TextAsset 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Common::ImageAsset 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Enums::BudgetDeliveryMethodEnum 
  
 qw(STANDARD) 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Enums::CampaignStatusEnum 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Enums::AdvertisingChannelTypeEnum 
  
 qw(PERFORMANCE_MAX) 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Enums::AssetGroupStatusEnum 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Enums::AssetFieldTypeEnum 
  
 qw(HEADLINE DESCRIPTION LONG_HEADLINE BUSINESS_NAME LOGO MARKETING_IMAGE SQUARE_MARKETING_IMAGE) 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Enums::ConversionActionCategoryEnum 
  
 qw(PURCHASE) 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Enums::ConversionOriginEnum 
  
 qw(WEBSITE) 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Enums::ListingGroupFilterTypeEnum 
  
 qw(UNIT_INCLUDED) 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Enums::ListingGroupFilterListingSourceEnum 
  
 qw(SHOPPING) 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Enums::EuPoliticalAdvertisingStatusEnum 
  
 qw(DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING) 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Services::GoogleAdsService::MutateOperation 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Services::CampaignBudgetService::CampaignBudgetOperation 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Services::CampaignService::CampaignOperation 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Services::CampaignCriterionService::CampaignCriterionOperation 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Services::AssetService::AssetOperation 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Services::AssetGroupService::AssetGroupOperation 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Services::AssetGroupAssetService::AssetGroupAssetOperation 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Services::CampaignConversionGoalService::CampaignConversionGoalOperation 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Services::AssetGroupListingGroupFilterService::AssetGroupListingGroupFilterOperation 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Services::CampaignAssetService::CampaignAssetOperation 
 ; 
 use 
  
 Google::Ads::GoogleAds::V21::Utils::ResourceNames 
 ; 
 use 
  
 Getopt::Long 
  
 qw(:config auto_help) 
 ; 
 use 
  
 Pod::Usage 
 ; 
 use 
  
 Cwd 
  
 qw(abs_path) 
 ; 
 use 
  
 Data::Uniqid 
  
 qw(uniqid) 
 ; 
 use 
  
 POSIX 
  
 qw(strftime) 
 ; 
 # We specify temporary IDs that are specific to a single mutate request. 
 # Temporary IDs are always negative and unique within one mutate request. 
 # 
 # See https://developers.google.com/google-ads/api/docs/mutating/best-practices 
 # for further details. 
 # 
 # These temporary IDs are fixed because they are used in multiple places. 
 use 
  
 constant 
>  
 BUDGET_TEMPORARY_ID 
  
 = 
  
 - 
 1 
 ; 
 use 
  
 constant 
>  
 PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
  
 = 
  
 - 
 2 
 ; 
 use 
  
 constant 
>  
 ASSET_GROUP_TEMPORARY_ID 
  
 = 
  
 - 
 3 
 ; 
 # There are also entities that will be created in the same request but do not 
 # need to be fixed temporary IDs because they are referenced only once. 
 our 
  
 $next_temp_id 
  
 = 
  
 ASSET_GROUP_TEMPORARY_ID 
  
 - 
  
 1 
 ; 
 sub 
  
 add_performance_max_retail_campaign 
  
 { 
  
 my 
  
 ( 
 $api_client 
 , 
  
 $customer_id 
 , 
  
 $merchant_center_account_id 
 , 
  
 $final_url 
 , 
  
 $brand_guidelines_enabled 
 ) 
  
 = 
  
 @_ 
 ; 
  
 # This campaign will override the customer conversion goals. 
  
 # Retrieve the current list of customer conversion goals. 
  
 my 
  
 $customer_conversion_goals 
  
 = 
  
 get_customer_conversion_goals 
 ( 
 $api_client 
 , 
  
 $customer_id 
 ); 
  
 # Performance Max campaigns require that repeated assets such as headlines 
  
 # and descriptions be created before the campaign. 
  
 # For the list of required assets for a Performance Max campaign, see 
  
 # https://developers.google.com/google-ads/api/docs/performance-max/assets. 
  
 # 
  
 # Create the headlines. 
  
 my 
  
 $headline_asset_resource_names 
  
 = 
  
 create_multiple_text_assets 
 ( 
 $api_client 
 , 
  
 $customer_id 
 , 
  
 [ 
 "Travel" 
 , 
  
 "Travel Reviews" 
 , 
  
 "Book travel" 
 ]); 
  
 # Create the descriptions. 
  
 my 
  
 $description_asset_resource_names 
  
 = 
  
 create_multiple_text_assets 
 ( 
 $api_client 
 , 
  
 $customer_id 
 , 
  
 [ 
 "Take to the air!" 
 , 
  
 "Fly to the sky!" 
 ]); 
  
 # It's important to create the below entities in this order because they depend 
  
 # on each other. 
  
 my 
  
 $operations 
  
 = 
  
 [] 
 ; 
  
 # The below> methods create and return MutateOperations that we later provide to 
  
 # the GoogleAdsService-mutate() method in order to create the entities in a 
  
 # single request. Since the entities for a Performance Max campaign are closely 
  
 # tied to one-another, it's considered a best practice to create them in a 
  
 # single mutate request so they all complete successfully or fail entirely, 
  
 # leaving no orphaned entities. See: 
  
 # https://developers.google.com/google-ads/api/docs/mutating/overview. 
  
 push 
  
 @$operations 
 , 
  
 create_campaign_budget_operation 
 ( 
 $customer_id 
 ); 
  
 push 
  
 @$operations 
 , 
  
 create_performance_max_campaign_operation 
 ( 
 $customer_id 
 , 
  
 $merchant_center_account_id 
 , 
  
 $brand_guidelines_enabled 
 ); 
  
 push 
  
 @$operations 
 , 
  
 @ 
 { 
 create_campaign_criterion_operations 
 ( 
 $customer_id 
 )}; 
  
 push 
  
 @$operations 
 , 
  
 create_asset_group_operation 
 ( 
 $customer_id 
 , 
  
 $final_url 
 ); 
  
 push 
  
 @$operations 
 , 
  
 create_listing_group_filter_operation 
 ( 
 $customer_id 
 ); 
  
 push 
  
 @$operations 
 , 
  
 @ 
 { 
  
 create_asset_and_asset_group_asset_operations 
 ( 
  
 $customer_id 
 , 
  
 $headline_asset_resource_names 
 , 
  
 $description_asset_resource_names 
 , 
  
 $brand_guidelines_enabled 
  
 )}; 
  
 push 
  
 @$operations 
 , 
  
 @ 
 { 
 create_conversion_goal_operations 
 ( 
 $customer_id 
 , 
  
 $customer_conversion_goals 
 )}; 
  
 # Issue a mutate reque>st to create everyt>hing and print its information. 
>  
 my 
  
 $mutate_google_ads_response 
  
 = 
  
 $>api_client 
 - 
 GoogleAdsService 
 () 
 - 
 mutate 
 ({ 
  
 customerId 
  
 = 
  
 $customer_id 
 , 
  
 mutateOperations 
  
 = 
  
 $operations 
  
 }); 
  
 print_response_details 
 ( 
 $mutate_google_ads_response 
 ); 
  
 return 
  
 1 
 ; 
 } 
 # Creates a MutateOperation that creates a new CampaignBudget. 
 # 
 # A temporary ID will be assigned to this campaign budget so that it can be 
 # referenced by other objects being created in the same mutate request. 
 sub 
  
 create_campaign_budget_operation 
  
 { 
  
 my 
  
 ( 
 $customer_id 
 ) 
  
 = 
  
 @_ 
 ; 
  
 # Create a mutate operation that creates a campaign budget> operation. 
  
 return 
  
 Google::Ads::Goog>leAds::V21::Services::GoogleAdsService:: 
 MutateOperation 
 - 
  
 new 
 ({ 
  
 campaignBudgetOperation 
  
 = 
 > 
 Google::Ads::GoogleAd>s::V21::Services::CampaignBudgetService:: 
 CampaignBudgetO>peration 
  
 - 
 new 
 ({ 
  
 create 
  
 = 
  
 Google::Ads::GoogleAds::V21::Resources:: 
 CampaignBudget 
 - 
 new 
 ( 
  
 { 
  
 # Set a temporary ID in the budget's resource nam>e so it can be 
  
 # referenced by the campaign in later steps. 
  
 resourceName 
  
 = 
  
 Google::Ads::GoogleAds::V21::Utils::ResourceNames:: 
 camp>aign_budget 
 ( 
  
 $customer_id 
 , 
  
 BUDGET_TEMPORARY_ID 
  
 ), 
  
 name 
  
 = 
  
 "Performance Max retail campaign budget> #" 
  
 . 
  
 uniqid 
 (), 
  
 # The >budget period already defaults to DAILY. 
  
 amountMicros 
  
 = 
  
 50000000 
 , 
  
 deliveryMethod 
  
 = 
  
 STANDARD 
 , 
>  
 # A Performance Max campaign cannot use a shared campaign budget. 
  
 explicitlyShared 
  
 = 
  
 "false" 
 , 
  
 })})}); 
 } 
 # Creates a MutateOperation that creates a new Performance Max campaign. 
 # 
 # A temporary ID will be assigned to this campaign so that it can be referenced 
 # by other objects being created in the same mutate request. 
 sub 
  
 create_performance_max_campaign_operation 
  
 { 
  
 my 
  
 ( 
 $customer_id 
 , 
  
 $merchant_center_account_id 
 , 
  
 $brand_guidelines_enabled 
 ) 
  
 = 
  
 @_ 
 ; 
  
 # Create a mutate operation> that creates a campaign operation. 
>  
 return 
  
 Google::Ads::GoogleAds::V21::Services::GoogleAdsService:: 
 MutateOperation 
 - 
  
 n>ew 
 ({ 
  
 campaignOpera>tion 
  
 = 
  
 Google::Ads::GoogleAds::V21::Servic>es::CampaignService:: 
 CampaignOperation 
  
 - 
 new 
 ({ 
  
 create 
  
 = 
  
 Google::Ads::GoogleAds:>:V21::Resources:: 
 Campaign 
 - 
 new 
 ({ 
  
 # Assign the resource name with a temporary ID. 
  
 resourceName 
  
 = 
  
 Google::Ads::GoogleAds::V21::Utils::ResourceNa>mes:: 
 campaign 
 ( 
  
 $customer_id 
 , 
  
 PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
  
 ), 
  
 name 
  
 = 
  
 "Performance Max reta>il campaign #'" 
  
 . 
  
 uniqid 
 (), 
  
 # Set the budget using the given budget resource name. 
  
 campaignBudget 
  
 = 
  
 Google::Ads::GoogleAds::V21::Utils::ResourceNames:: 
 campaign_budget 
 ( 
  
 $customer_id 
 , 
  
 BUDGET_TEMPORARY_ID 
  
 ), 
  
 # Set the campaign status >as PAUSED. The campaign is the only entity in 
  
 # the mutate request that should have its status set. 
  
 status 
  
 = 
  
 Google::Ads::GoogleAds::V21::Enums::CampaignStatusEnum:: 
 PAUSED 
 , 
  
 # All Performance Max campaigns have an advertisin>gChannelType of 
  
 # PERFORMANCE_MAX. The advertisingChannelSubType should not be set. 
  
 advertisingChannelType 
  
 = 
  
 PERFORMANCE_MAX 
 , 
  
 # Bidding strategy must be set directly on the campaign. 
  
 # Setting a portfolio bidding strategy by resource name is not supported. 
  
 # Max Conversion and Max Conversion Value are the only strategies 
  
 # supported for Performance Max campaigns. 
  
 # An optional ROAS (Return on Advertising Spend) can be set for 
  
 # maximizeConversionValue. The ROAS value must be specified as a ratio in 
  
 # the API. It is calculated by dividing "total value" by "total spend". 
  
 # For more information on Max Conversion Value, see the support article: 
  
 # http://support.google.com/google-ads/answer/7684216. 
  
 # A targetRoas of 3.5 correspo>nds to a 350% return on ad spend. 
  
 # For first time users, it's> recommended not to set a target ROAS. 
  
 # ma>ximizeConversionValue = 
  
 #   Google::Ads::GoogleAds::V21::Common::MaximizeConversionValue- 
  
 #   new({ 
  
 #     targetRoas = 3>.5 
  
 #   } 
  
 # ), 
  
 # Below is what you >would use if you want to maximize conversions. 
  
 #> maximizeConversions = 
  
 #   Google::Ads::GoogleAds::V21::Common::MaximizeConversions- 
  
 #   new({ 
  
 #     targetCpaMicros = 1000000 
  
 #   } 
  
 # ), 
  
 # The target CPA is optional. This is th>e average amount that you would 
  
 # like to spend per convers>ion action. 
  
 # Set the> shopping settings. 
  
 shoppingSetting 
  
 = 
  
 Google::Ads::GoogleAds::V21::Resources:: 
 ShoppingSetting 
 - 
 new 
 ({ 
  
 merchantId 
  
 = 
  
 $merchant_center_account_id 
 , 
  
 # Optional: To use products only from a specific feed, set feedLabel 
  
 # to the feed label used in Merchant Center. 
  
 # See: https://>support.google.com/merchants/answer/12453549. 
  
 # Omitting the feedLabel field will use products from all feeds. 
  
 # feedLabel = "INSERT_FEED_LABEL_HERE" 
  
 } 
  
 ), 
  
 # Set the final URL expansion opt out. This flag is specific to 
  
 # Performance Max campaigns. If opted out (true), only the final URLs in 
  
 # the asset group or URLs specified in the advertiser's Google Merchant 
  
 # Center or business data feeds are targeted. 
  
 # If opted in (false), the entire domain will be targeted. For best 
  
 # results, set this value to false to opt in and allow URL expansions. You 
  
 # can optionally add exclusions to limit traffic to parts of your website. 
 > 
 # 
  
 # For a Retail campaign, we want the final URL to be limited to those 
  
 # explicitly surfaced via GMC. 
  
 urlExpansionOptOut 
  
 = 
  
 "true" 
 , 
  
 # Declare whether or not this campaign serves political ads targeting >the EU. 
  
 # Valid values are CONTAINS_EU_POLITICAL_ADVERTISING and 
  
 # DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING. 
  
 containsEuPoliticalAdvertising 
  
 = 
  
 DOES_NOT_CONTAIN_EU_POLITICAL_ADVERTISING 
 , 
  
 # Set if the campaign is e>nabled for brand guidelines. For more information 
  
 # on brand guidelines, >see https://support.google.com/google-ads/answer/14934472. 
  
 brand>GuidelinesEnabled 
  
 = 
  
 $brand_guidelines_enabled 
 , 
  
 # Optional fields. 
  
 startDate 
  
 = 
  
 strftime 
 ( 
 "%Y%m%d" 
 , 
  
 localtime 
 ( 
 time 
  
 + 
  
 60 
  
 * 
  
 60 
  
 * 
  
 24 
 )), 
  
 endDate 
  
 = 
  
 strftime 
 ( 
 "%Y%m%d" 
 , 
  
 localtime 
 ( 
 time 
  
 + 
  
 60 
  
 * 
  
 60 
  
 * 
  
 24 
  
 * 
  
 365 
 )), 
  
 })})}); 
 } 
 # Creates a list of MutateOperations that create new campaign criteria. 
 sub 
  
 create_campaign_criterion_operations 
  
 { 
  
 my 
  
 ( 
 $customer_id 
 ) 
  
 = 
  
 @_ 
 ; 
  
 my 
  
 $operations 
  
 = 
  
 [] 
 ; 
  
 # Set the LOCATION campaign criteria. 
  
 # Target all of New York City except Brooklyn. 
  
 # Location IDs are listed here: 
  
 # https://developers.google.com/google-ads/api/reference/data/geotargets 
  
 # and they can also be retrieved using the GeoTargetConstantS>ervice as shown 
  
 # here: https://developers.>google.com/google-ads/api/docs/targeting/location-targeting. 
  
 push 
  
 @$operations 
 , 
  
 Google::Ads::GoogleAds::>V21::Services::GoogleAds>Service:: 
 MutateOperation 
 - 
  
 new 
 ({ 
  
 campaignCriterionOperation 
  
 = 
>  
 Google::Ads::GoogleAds>::V21::Services::CampaignCriterionService:: 
 CampaignCriterionOperation 
  
 - 
 new 
 ({ 
  
 create 
  
 = 
  
 Google::Ads::GoogleAds::V21::Resources:: 
 CampaignCriterion 
 - 
 new 
 ({ 
  
 campaign 
  
 = 
  
 Google::Ads::GoogleAds::V21::Utils::ResourceNames:: 
 campaign 
 ( 
  
 $customer_id 
 , 
  
 PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 > 
 ), 
  
 # Adds one positive location target fo>r New York City (ID=1023191), 
 > 
 # specifically adding the positive criteria before the negative one. 
  
 location 
  
 = 
  
 Google::Ads::GoogleAds::V21::Common:: 
 LocationInfo 
 - 
 new 
 ({ 
>  
 geoTargetConstant 
  
 = 
  
 Google::Ads::GoogleAds::V21::Utils::ResourceNames:: 
 geo_target_constant 
 ( 
  
 1023191 
 )} 
  
 ), 
 > 
 negative 
  
 = 
  
 "false" 
 > 
 })})}); 
  
 # Next add the negative target for Brooklyn (ID=1022762). 
  
 push 
  
 @$operations 
 , 
  
 Google::Ads::G>oogleAds::V21::Services:>:GoogleAdsService:: 
 MutateOperation 
 - 
  
 new 
 ({ 
  
 campaignCriterionOp>eration 
  
 = 
  
 Google::Ads:>:GoogleAds::V21::Services::CampaignCriterionService:: 
 CampaignCriterionOperation 
  
 - 
 new 
 ({ 
  
 create 
  
 = 
  
 Google::Ads::GoogleAds::V21::Resources:: 
 CampaignCriterion 
 - 
 new 
 ({ 
>  
 campaign 
  
 = 
  
 Google::Ads::GoogleAds::V>21::Utils::ResourceNames:: 
 campaign 
 ( 
 > 
 $customer_id 
 , 
  
 PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
  
 ), 
  
 location 
  
 = 
  
 Google::Ads::GoogleAds::V21::Common:: 
 Location>Info 
 - 
 new 
 ({ 
  
 geoTargetConstant 
  
 = 
  
 Google::Ads::GoogleAds::V21::Utils::ResourceNames:: 
 geo_target_constant 
 ( 
  
 1022762 
> )} 
  
 ), 
  
 negative 
  
> = 
  
 "true" 
  
 })})}); 
  
 # Set the LANGUAGE campaign criterion. 
  
 push 
  
 @$operations 
 , 
  
 Goog>le::Ads::GoogleAds::V21:>:Services::GoogleAdsService:: 
 MutateOperation 
 - 
  
 new 
 ({ 
  
 campaignC>riterionOperation 
  
 = 
  
 Go>ogle::Ads::GoogleAds::V21::Services::CampaignCriterionService:: 
 CampaignCriterionOperation 
  
 - 
 new 
 ({ 
  
 create 
  
 = 
  
 Google::Ads::GoogleAds::V21::Resources:: 
 CampaignCriterion 
 - 
 new 
 ({ 
  
 campaign 
  
 = 
  
 Google::Ads::GoogleAds::V21::Utils::ResourceNames:: 
 campaign 
 ( 
  
 $customer_id 
 , 
  
 PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 > 
 ), 
  
 # Set the language. 
  
 # For a list> of all language codes, see: 
 > 
 # https://developers.google.com/google-ads/api/reference/data/codes-formats#expandable-7. 
  
 language 
  
 = 
  
 Google::Ads::GoogleAds::V21::Common:: 
 LanguageInfo 
 - 
 new 
 ({ 
  
 languageConstant 
  
 = 
  
 Google::Ads::GoogleAds::V21::Utils::ResourceNames:: 
 language_constant 
 ( 
  
 1000 
 ) 
  
 # English 
  
 })})})}); 
  
 return 
  
 $operations 
 ; 
 } 
 # Creates multiple text assets and returns the list of resource names. 
 # 
 # These repeated assets must be created in a separate request prior to 
 # creating the campaign. 
 sub 
  
 create_multiple_text_assets 
  
 { 
  
 my 
  
 ( 
 $api_client 
 , 
  
 $customer_id 
 , 
  
 $texts 
 ) 
  
 = 
  
 @_ 
 ; 
  
 # Here again we use the GoogleAdService to create multiple text assets in a 
  
 # singl>e request. 
  
 my 
  
 $operations 
  
 = 
  
> [] 
 ; 
  
 foreach 
  
 my 
  
 $text 
  
 ( 
 @$texts 
 ) 
  
 { 
  
 # Create a mutate operation for a text a>sset. 
  
 push 
  
 @$operations 
 , 
  
 Go>ogle::Ads::GoogleAds::V21::Services::GoogleAdsS>ervice:: 
 MutateOperation 
  
 - 
 ne>w 
 ({ 
  
 assetOperation 
  
 = 
  
 Google::Ads::GoogleAds::V21>::Services::AssetService:: 
 AssetO>peration 
 - 
  
 new 
 ({ 
  
 create 
  
 = 
  
 Google::Ads::GoogleAds::V21::Resources:: 
 Asset 
 - 
 new 
 ({ 
  
 textAsset 
  
 = 
 > 
 Google:>:Ads::GoogleAds::V21::Common:: 
 T>extAsset 
 - 
 new 
 ({ 
  
 te>xt 
  
 = 
  
 $text 
  
 })})})}); 
  
 } 
  
 # Issue a mutate request to add all assets. 
  
 my 
  
 $mutate_google_a>ds_response 
  
 = 
  
 $api_client 
 - 
 GoogleAdsService 
 () 
 - 
 mutate 
 ({ 
  
 customerId 
  
 = 
>  
 $customer_id 
 , 
  
 mutateOperations 
  
 = 
  
 $operations 
  
 }); 
  
 my 
  
 $asset_resource_names 
  
 = 
  
 [] 
 ; 
  
 foreach 
  
 my 
  
 $response 
  
 ( 
 @ 
 { 
 $mutate_google_ads_response 
 - 
 { 
 mutateOperationResponses 
 }}) 
  
 { 
  
 push 
  
 @$asset_resource_names 
 , 
  
 $response 
 - 
 { 
 assetResult 
 }{ 
 resourceName 
 }; 
  
 } 
  
 print_response_details 
 ( 
 $mutate_google_ads_response 
 ); 
  
 return 
  
 $asset_resource_names 
 ; 
 } 
 # Creates a MutateOperation that creates a new asset group. 
 # 
 # A temporary ID will be assigned to this asset group so that it can be referenced 
 # by other objects being created in the same mutate request. 
 sub 
  
 c>reate_asset_group_operation 
  
 { 
  
 my 
  
 ( 
 $c>ustomer_id 
 , 
  
 $final_url 
 ) 
  
 = 
  
 @_ 
 ; 
  
 # Create a mutate operation that creates an asset group operati>on. 
  
 return 
  
 Google:>:Ads::GoogleAds::V21::Services::GoogleAdsService:: 
 Mu>tateOperation 
 - 
  
 new 
 ({ 
  
 ass>etGroupOperation 
  
 = 
  
 Google::Ads::GoogleAds::V21::Services::AssetGroupService:: 
 AssetGroupOperation 
  
 - 
 new 
 ({ 
  
 create 
  
 = 
  
 Google::Ads::GoogleAds::V21::Resources:: 
> AssetGroup 
 - 
 new 
 ({ 
  
 resourceName 
  
 = 
  
 Google::Ads::G>oogleAds::V21::Utils::ResourceNames:: 
 asset_group 
 ( 
  
 $customer_id 
 , 
  
 ASSET_GROUP_TEMPORARY_ID 
  
 ), 
  
 name 
  
 = 
  
 "Performance Max retail asset group #">; 
  
 . 
  
 uniqid 
 (), 
  
 campaign 
  
 = 
 > 
 Google::Ads::GoogleAds::V21::Utils::R>esourceNames:: 
 campaign 
 ( 
  
 $customer_id 
 , 
  
 PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
  
 ), 
  
 finalUrls 
  
 = 
  
 [ 
 $final_url 
 ], 
  
 finalMobileUrls 
  
 = 
  
 [ 
 $final_url 
 ], 
  
 status 
  
 = 
  
 Google::Ads::GoogleAds::V21::Enums::AssetGroupStatusEnum:: 
 PAUSED 
  
 })})}); 
 } 
 # Creates a MutateOperation that creates a new listing group filter. 
 # A temporary ID will be assigned to this listing group filter so that it 
 # can be referenced by other objects being created in the same Mutate request. 
 sub 
  
 create_listing_group_filter_ope>ration 
  
 { 
  
 my 
  
 ( 
 $customer>_id 
 ) 
  
 = 
  
 @_ 
 ; 
  
 # Creates a new ad group criterion containing the "default" listing group 
  
 # (All products). 
  
 my 
  
 $listing_group_filter 
  
 = 
  
 Google::Ads::GoogleAds::V21::Resources:: 
 AssetGroupListingGroupFilter 
 - 
 new 
 ({ 
  
 assetGroup 
  
 = 
  
 Google::Ads::GoogleAds::V21::Utils::ResourceNames:: 
 asset_group 
 ( 
  
 $customer_id 
 , 
  
 ASSET_GRO>UP<_TEMPORARY_ID 
 > 
 ), 
  
 # Since this is the root node, do not set the parentListingGroupFilter. 
  
 # For all other nodes, this would r>efer to the parent listing group filter 
  
 # resource name. 
  
 # parentListingGroupFilter = "PARENT FILTER NAME" 
  
 # The subdivision type means this nod>e has children. This type is used for 
  
 # the root node as well. 
  
 type 
  
 = 
  
 UNIT_INCLUDED 
 , 
  
 #> Because this is a Performance Max campaign for retail, >we need to specify 
  
 # that this is in the shopping listing source. 
  
 listingSource 
  
 = 
  
 SHOPPING 
  
 }); 
  
 return 
  
 Google:>:Ads::GoogleAds::V21::Se>rvices::GoogleAdsService:: 
 MutateOperation 
 - 
  
 new 
 ({ 
  
 assetGroupListingGroupFilterOperation 
  
 = 
  
 Google::Ads::GoogleAds::V21::Services::AssetGroupListingGroupFilterService:: 
 AssetGroupListingGroupFilterOperation 
  
 - 
 new 
 ({ 
  
 create 
  
 = 
  
 $listing_group_filter 
  
 })}); 
 } 
 # Creates a list of MutateOperations that create a new asset_group. 
 # A temporary ID will be assigned to this asset group so that it can 
 # be referenced by other objects being created in the same Mutate request. 
 sub 
  
 create_asset_and_asset_group_asset_operations 
  
 { 
  
 my 
  
 ( 
  
 $customer_id 
 , 
  
 $headline_asset_resource_names 
 , 
  
 $description_asset_resource_names 
 , 
  
 $brand_guidelines_enabled 
  
 ) 
  
 = 
  
 @_ 
 ; 
  
 my 
  
 $operations 
  
 = 
  
 [] 
 ; 
  
 # For the list of required assets for a Performance Max campaign, see 
  
 # https://developers.google.com/google-ads/api/docs/performance-max/assets. 
  
 # An AssetGroup is linked to an Asset by creating a new AssetGroupAsset 
  
 # and providing: 
  
 # - the resource name of the AssetGroup 
  
 # - the resource name of the Asset 
  
 # - the fieldType of the Asset in this AssetGroup 
  
 # 
  
 # To learn more about AssetGroups, see 
  
 # https://developers.google.com/google-ads/api/docs/performance-max/asset-groups. 
  
 # >Link the previously created multiple tex>t assets. 
  
 # Link the headline assets. 
  
 foreach 
  
 my 
  
 $resource_name 
  
 ( 
 @$headline_asset_resource_names 
 ) 
  
 { 
  
 p>ush 
  
 @$operations 
 , 
  
 Go>ogle::Ads::GoogleAds::V21::Services::GoogleAdsService:: 
 MutateOperation 
>  
 - 
 new 
 ({ 
  
 assetGroupAss>etOperation 
  
 = 
  
 Google::Ads::GoogleAd>s::V21::Services::AssetGroupAssetService:: 
 AssetGroupAssetOperation 
  
 - 
 new 
 ({ 
  
 create 
  
 = 
  
 Google::Ads::GoogleAds::V21::Resources:: 
 AssetGroupAsset 
 - 
 new 
 ({ 
 > 
 asset 
  
 = 
  
 $resource_name 
 , 
  
 assetGroup 
  
 = 
  
 Google::Ads::GoogleAds::V21::Utils::ResourceNames:: 
 asset_group 
 ( 
  
 $customer_id 
 , 
  
 ASSET_GROUP_TEMPORARY_ID 
  
 ), 
  
 fie>ldType 
  
 = 
  
 HEADLINE 
  
 })})}); 
>  
 } 
  
 # Link the description assets. 
  
 foreach 
  
 my 
  
 $resource_name 
  
 ( 
 @$description_asset_resource_names 
 ) 
  
 { 
  
 p>ush 
  
 @$operations 
 , 
  
 Go>ogle::Ads::GoogleAds::V21::Services::GoogleAdsService:: 
 MutateOperation 
>  
 - 
 new 
 ({ 
  
 assetGroupAss>etOperation 
  
 = 
  
 Google::Ads::GoogleAd>s::V21::Services::AssetGroupAssetService:: 
 AssetGroupAssetOperation 
  
 - 
 new 
 ({ 
  
 create 
  
 = 
  
 Google::Ads::GoogleAds::V21::Resources:: 
 AssetGroupAsset 
 - 
 new 
 ({ 
 > 
 asset 
  
 = 
  
 $resource_name 
 , 
  
 assetGroup 
  
 = 
  
 Google::Ads::GoogleAds::V21::Utils::ResourceNames:: 
 asset_group 
 ( 
  
 $customer_id 
 , 
  
 ASSET_GROUP_TEMPORARY_ID 
  
 ), 
  
 fieldType 
  
 = 
  
 DESCRIPTION 
  
 })})}); 
  
 } 
  
 # Create and link the long headline text asset. 
  
 push 
  
 @$operations 
 , 
  
 @ 
 { 
 create_and_link_text_asset 
 ( 
 $customer_id 
 , 
  
 "Travel the World" 
 , 
  
 LONG_HEADLINE 
 )}; 
  
 # Create and link the business name and logo asset. 
  
 push 
  
 @$operations 
 , 
  
 @ 
 { 
  
 create_and_link_brand_assets 
 ( 
  
 $customer_id 
 , 
  
 $brand_guidelines_enabled 
 , 
  
 "Interplanetary Cruises" 
 , 
  
 "https://gaagl.page.link/1Crm" 
 , 
  
 "Logo Image" 
  
 )}; 
  
 # Create and link the image assets. 
  
 # Create and link the marketing image asset. 
  
 push 
  
 @$operations 
 , 
  
 @ 
 { 
  
 create_and_link_image_asset 
 ( 
  
 $customer_id 
 , 
  
 "https://gaagl.page.link/Eit5" 
 , 
  
 MARKETING_IMAGE 
 , 
  
 "Marketing Image" 
  
 )}; 
  
 # Create and link the square marketing image asset. 
  
 push 
  
 @$operations 
 , 
  
 @ 
 { 
  
 create_and_link_image_asset 
 ( 
  
 $customer_id 
 , 
  
 "https://gaagl.page.link/bjYi" 
 , 
  
 SQUARE_MARKETING_IMAGE 
 , 
  
 "Square Marketing Image" 
  
 )}; 
  
 # After being created the list must be sorted so that all asset 
  
 # operations come before all the asset group asset operations, 
  
 # otherwise the API will reject the request. 
  
 return 
  
 sort_asset_and_asset_group_asset_operations 
 ( 
 $operation>s 
 ); 
 } 
 # Creates a list of Mutate>Operations that create a new linked text asset. 
 sub 
  
 create_and_link_text_asse>t 
  
 { 
  
 my 
  
 ( 
 $customer_id 
 , 
  
 $text 
 , 
  
 $f>ield_type 
 ) 
  
 = 
  
 @_ 
 ; 
  
 my 
  
 $operations 
  
 = 
  
 [] 
 ; 
  
 # Cr>eate a new mutate operation for a >text asset. 
  
 push 
  
 @$operations 
 , 
  
 Google::Ads::GoogleAds::V21::Services::GoogleAdsService:: 
 MutateOperation 
 - 
  
 new 
 ({ 
  
 assetOperation 
  
 = 
  
 Google::Ads>::GoogleAds::V21::Services::AssetService:: 
 AssetO>peration 
 - 
  
 new 
 ({ 
 > 
 create 
  
 = 
  
 Google::Ads::GoogleAds::V21::Resources:: 
 Asset 
 - 
 new 
 ({ 
  
 resourceName 
  
 = 
  
 Google::Ads::GoogleAds::V21::Utils::ResourceNames:: 
 asset 
 ( 
  
 $customer_id 
 , 
  
 $nex>t_temp_id 
  
 ), 
  
> textAsset 
  
 = 
  
 Google::Ads::GoogleAds::V21::Common:: 
 TextAsset 
 - 
 new 
 ({ 
  
 text 
  
 = 
  
 $text 
 > 
 })})})}); 
  
 # Cre>ate an asset group asset to link the asset to the asset group. 
  
 push 
>  
 @$operations 
 , 
  
 Google::>Ads::GoogleAds::V21::Services::GoogleAdsService:: 
 MutateOperation 
 - 
  
 new 
 ({ 
  
 assetGroupAssetOperation 
  
 = 
  
 Google::Ads::GoogleAds::V21::>Services::AssetGroupAssetService:: 
 AssetGroupAssetOperation 
  
 - 
 new 
 ({ 
  
 create 
  
 = 
  
 Google::Ads::GoogleAds::V21::Resources:: 
 AssetGroupAsset 
 - 
 new 
 ({ 
 > 
 asset 
  
 = 
  
 Google::Ads::GoogleAds::V21::Utils::ResourceNames:: 
 asset 
 ( 
  
 $customer_id 
 , 
  
 $next_temp_id 
  
 ), 
  
 assetGroup 
  
 = 
  
 Google::Ads::GoogleAds::V21::Utils::ResourceNames:: 
 asset_group 
 ( 
  
 $customer_id 
 , 
  
 ASSET_GROUP_TEMPORARY_ID 
  
 ), 
  
 fieldType 
  
 = 
  
 $field_type 
  
 })})}); 
  
 $next_temp_id 
 -- 
 ; 
  
 return 
  
 $operations 
 ; 
 } 
 # Creates> a list of MutateOperations that >create a new linked image asset. 
 sub 
  
 create_and_link_image_asset 
  
 { 
  
 my 
  
 ( 
 $cus>tomer_id 
 , 
  
 $url 
 , 
  
 $field_type 
 , 
  
 $ass>et_name 
 ) 
  
 = 
  
 @_ 
 ; 
  
 my 
  
 $operations 
  
 = 
  
 [] 
 ; 
  
 # Crea>te a new mutate operation for an i>mage asset. 
  
 push 
  
 @$operations 
 , 
  
 Google::Ads::GoogleAds::V21::Services::GoogleAdsService:: 
 MutateOperation 
 - 
  
 new 
 ({ 
  
 assetOperation 
  
 = 
  
 Google::Ads::GoogleAds::V21::Services::AssetService:: 
 AssetOperation 
 - 
  
 new 
 ({ 
  
 create 
  
 = 
  
 Google::Ads::GoogleAds::V21::Resources:: 
 Asset 
 - 
 new 
 ({ 
  
 resourceName 
  
 = 
  
 Google::Ads::GoogleAds::V21::Utils::R>esourceNames:: 
 asset 
 ( 
  
 $cu>stomer_id 
 , 
  
 $next_temp_id 
  
 ), 
  
 # Provi>de a unique friendly name to i>dentify your asset. 
  
 # When there is an existing image asset with the same content but a different 
  
 # name, the new name will be dropped silently. 
  
 name 
  
 = 
  
 $asset_nam>e 
 , 
  
 imageAsset 
  
 = 
 > 
 Google::Ads::GoogleAds::V21::Common:: 
 ImageAsset 
 - 
 new 
 ({ 
  
 data 
  
 = 
  
 get_base64_data_from_url 
> ( 
 $url 
 )})})})}); 
  
 # Cre>ate an asset group asset to link the asset to the asset group. 
  
 push 
>  
 @$operations 
 , 
  
 Google::>Ads::GoogleAds::V21::Services::GoogleAdsService:: 
 MutateOperation 
 - 
  
 new 
 ({ 
  
 assetGroupAssetOperation 
  
 = 
  
 Google::Ads::GoogleAds::V21::>Services::AssetGroupAssetService:: 
 AssetGroupAssetOperation 
  
 - 
 new 
 ({ 
  
 create 
  
 = 
  
 Google::Ads::GoogleAds::V21::Resources:: 
 AssetGroupAsset 
 - 
 new 
 ({ 
 > 
 asset 
  
 = 
  
 Google::Ads::GoogleAds::V21::Utils::ResourceNames:: 
 asset 
 ( 
  
 $customer_id 
 , 
  
 $next_temp_id 
  
 ), 
  
 assetGroup 
  
 = 
  
 Google::Ads::GoogleAds::V21::Utils::ResourceNames:: 
 asset_group 
 ( 
  
 $customer_id 
 , 
  
 ASSET_GROUP_TEMPORARY_ID 
  
 ), 
  
 fieldType 
  
 = 
  
 $field_type 
  
 })})}); 
  
 $next_temp_id 
 -- 
 ; 
  
 return 
  
 $operations 
 ; 
 } 
 # Creates a list of MutateOperations that create linked brand ass>ets. 
 sub 
  
 create_and_link_brand_as>sets 
  
 { 
  
 my 
  
 ( 
 $customer_id 
 , 
  
 $brand_guidelines_enabled 
 , 
  
 $business_name 
 , 
  
 $logo_u>rl 
 , 
  
 $logo_name 
 ) 
  
 = 
  
 @_ 
 ; 
  
> my 
  
 $operations 
  
 = 
  
 [] 
 ; 
  
 # Create the text asset>. 
  
 my 
  
 $text_asset_temp_id 
  
 = 
  
 $next>_temp_id 
 -- 
 ; 
  
 push 
  
 @$operations 
 , 
  
 Google::Ads::GoogleAds::V21::Services::GoogleAdsService:: 
 MutateOperation 
 - 
  
 new 
 ({ 
  
 assetOperation 
  
 = 
  
 Google::Ads::Goog>leAds::V21::Services::AssetService:: 
 AssetOperati>on 
 - 
  
 new 
 ({ 
  
 cr>eate 
  
 = 
  
 Google::Ads::GoogleAds::V21::Resources:: 
 Asset 
 - 
 new 
 ({ 
  
 resourceName 
  
 = 
  
 Google::Ads::GoogleAds::V21::Utils::ResourceNames:: 
 asset 
 ( 
  
 $customer_id 
 , 
  
 $text_asset_temp_id 
 > 
 ), 
  
 te>xtAsset 
  
 = 
  
 Google::Ads::GoogleAds::V21::Common:: 
 TextAsset 
 - 
 new 
 ({ 
 > 
 text 
  
 = 
  
 $business_name 
 > 
 })})})}); 
  
 # Create the image asset. 
>  
 my 
  
 $image_asset_temp_id 
  
 = 
  
 $next>_temp_id 
 -- 
 ; 
  
 push 
  
 @$operations 
 , 
  
 Google::Ads::GoogleAds::V21::Services::GoogleAdsService:: 
 MutateOperation 
 - 
  
 new 
 ({ 
  
 assetOperation 
  
 = 
  
 Google::Ads::GoogleAds::V21::Services::AssetService:: 
 AssetOperation 
 - 
  
 new 
 ({ 
  
 create 
  
 = 
  
 Google::Ads::GoogleAds::V21::Resources:: 
 Asset 
 - 
 new 
 ({ 
  
 resourceName 
  
 = 
  
 Google::Ads::GoogleAds::V21::Utils::Resource>Names:: 
 asset 
 ( 
  
 $customer>_id 
 , 
  
 $image_asset_temp_id 
  
 ), 
  
 # Prov>ide a unique friendly name to >identify your asset. 
  
 # When there is an existing image asset with the same content but a different 
  
 # name, the new name will be dropped silently. 
  
 name 
  
 = 
  
 $logo_name 
 , 
  
 imageAsset 
  
 = 
  
 Google::Ads::Goog>leAds::V21::Common:: 
 ImageAsset 
 - 
 new 
 ({ 
 > 
 data 
  
 = 
  
 get_base64_data_from_url 
 ( 
 $logo_url 
 )})})})}); 
  
 if 
  
 ( 
 $brand_guidelines_enabled 
 ) 
  
 { 
 > 
 # Create CampaignAsset >resources to link the Asset resources to the Campaign. 
  
 push 
  
 @$ope>rations 
 , 
  
 Google::Ads::Googl>eAds::V21::Services::GoogleAdsService:: 
 Muta>teOperation 
  
 - 
 new 
 ({ 
  
 campaignAssetOperation 
  
 = 
  
 Google::Ads::GoogleAds::V21::Services::CampaignAssetService:: 
 CampaignAssetOperation 
  
 - 
 new 
 ({ 
  
 create 
  
 = 
 > 
 Google::Ads::GoogleAds::V21::Resources:: 
 CampaignAsset 
 - 
 new 
 ({ 
  
 fieldType 
  
 = 
  
 BUSINESS_NAME 
 , 
  
 campaign 
  
 = 
  
 Google::Ads::GoogleAds::V21::Utils::ResourceNames:: 
 campaign 
 ( 
  
 $customer_id 
 , 
  
 PERFORMANCE_MA>X_CAMPAIGN_TEMPORARY_ID 
 > 
 ), 
  
 asset 
  
 = 
  
 Google::Ads::GoogleAds::V21::Utils::ResourceNames:: 
 asset 
 ( 
>  
 $custom>er_id 
 , 
  
 $text_asset_temp_id 
  
 )})})}); 
  
 push 
  
 @$ope>rations 
 , 
  
 Google::Ads::Googl>eAds::V21::Services::GoogleAdsServ>ice:: 
 MutateOperation 
  
 - 
 new 
 ({ 
  
 campaignAssetOperation 
  
 = 
  
 Google::Ads::GoogleAds::V21::Services::CampaignAssetService:: 
 CampaignAssetOperation 
  
 - 
 new 
 ({ 
  
 crea>te 
  
 = 
  
 Google::Ads::GoogleAds::V21::Resources:: 
 CampaignAsset 
 - 
 new 
 ({ 
  
 fieldType 
  
 = 
  
 LOGO 
 , 
  
 campaign 
  
 = 
  
 Google::Ads::GoogleAds::V21::Utils::ResourceNames:: 
 campaign 
 ( 
  
 $customer_id 
 , 
  
 PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
  
 ), 
  
 asset 
  
 = 
  
 Google::Ad>s::GoogleAds::V21::Utils::ResourceNames:>: 
 asset 
 ( 
  
 $customer_id 
 , 
  
 $image_asset_temp_id 
  
 )})})}); 
  
 } 
  
 else 
  
 { 
  
 # Creat>e AssetGroupAsset resource>s to link the Asset resources to the AssetGroup. 
  
 push 
  
 @$operations 
 , 
>  
 Google::Ads::GoogleAds>::V21::Services::GoogleAdsService:: 
 MutateOperation 
  
 - 
 new 
 ({ 
  
 assetGroupAssetOperation 
  
 = 
  
 Google::Ads::GoogleAds::V21::Services::AssetGroupAssetService:: 
 AssetG>roupAssetOperation 
  
 - 
 new 
 ({ 
  
 create 
  
 = 
  
 Google::Ads::GoogleAds::V21::Resources:: 
 AssetGroupAsset 
 - 
 new 
 ({ 
  
 asset 
  
 = 
  
 Google::Ads::>GoogleAds::V21::Utils::ResourceNames:: 
 asset 
 ( 
  
 $customer_id 
 , 
  
 $text_asset_temp_id 
  
 ), 
  
 assetGroup 
  
 = 
>  
 Google::Ads::GoogleAds>::V21::Utils::ResourceNames:: 
 asset_group 
 ( 
  
 $customer_id 
 , 
  
 ASSET_GROUP_TEMPORARY_ID 
 > 
 ), 
  
> fieldType 
  
 = 
  
 BUSINESS_NAME 
  
 })})}); 
  
 push 
  
 @$operations 
 , 
>  
 Google::Ads::GoogleAds>::V21::Services::GoogleAdsService:: 
 MutateOperation 
  
 - 
 new 
 ({ 
  
 assetGroupAssetOperation 
  
 = 
  
 Google::Ads::GoogleAds::V21::Services::AssetGroupAssetService:: 
 AssetGr>oupAssetOperation 
  
 - 
 new 
 ({ 
  
 create 
  
 = 
  
 Google::Ads::GoogleAds::V21::Resources:: 
 AssetGroupAsset 
 - 
 new 
 ({ 
  
 asset 
  
 = 
  
 Google::Ads::G>oogleAds::V21::Utils::ResourceNames:: 
 asset 
 ( 
  
 $customer_id 
 , 
  
 $image_asset_temp_id 
  
 ), 
  
 assetGroup 
  
 = 
  
 Google::Ads::GoogleAds::V21::Utils::ResourceNames:: 
 asset_group 
 ( 
  
 $customer_id 
 , 
  
 ASSET_GROUP_TEMPORARY_ID 
  
 ), 
  
 fieldType 
  
 = 
  
 LOGO 
  
 })})}); 
  
 } 
  
 return 
  
 $operations 
 ; 
 } 
 # Sorts a list of asset an>d asset group asset operations. 
 # 
 # This sorts the list such that all asset operations precede 
 # all asset group asset operations. If asset group assets are 
 # created before assets then an error will be returned by the API. 
 sub 
  
 sort_asset_and_asset_group_asset_operations 
  
 { 
  
 my 
  
 ( 
 $operations 
 ) 
  
 = 
  
 @_ 
 ; 
  
 sub 
  
 sorter 
  
 { 
  
 if 
  
 ( 
 defined 
  
 $a 
 - 
 { 
 assetOperation 
 }) 
  
 { 
  
 return 
  
 - 
 1 
 ; 
  
 } 
  
 else 
  
 { 
  
 return 
  
 1 
 ; 
  
 } 
  
 } 
  
 my 
  
 @operations_sorted 
  
 = 
  
 sort 
  
 sorter 
  
 @$operations 
 ; 
  
 return 
  
 \ 
 @operations_sorted 
 ; 
 } 
 # Retrieves the list of customer conversion goals. 
 sub 
  
 get_customer_conversion_goals 
  
 { 
  
 my 
  
 ( 
 $api_client 
 , 
  
 $customer_id 
 ) 
  
 = 
  
> @_ 
 ; 
  
 my 
  
 $customer_conversion_goals 
  
 = 
  
 [] 
 ; 
  
 # Create a query that retrieves all> customer conversio>n goals. 
  
 my 
  
 $query 
  
 = 
 > 
 "SELECT customer_convers>ion_goal.category, customer_conversion_goal.origin " 
  
 . 
  
 "FROM customer_conversion_goal" 
 ; 
  
 # The number of conversi>on goals is typically less than 50 so we use 
  
 # GoogleAdsService-search() m>ethod instead of >search_stream(). 
  
 my 
  
 $search_response 
  
 = 
  
 $api_client 
> - 
 GoogleAdsService 
> () 
 - 
 search 
 ({ 
  
 customerId 
  
 = 
  
 $customer_id 
 , 
  
 query 
  
 = 
  
 $query 
  
 }); 
  
 # Iterate over the results and build the list of conversion goals. 
  
 foreach 
  
 my 
  
 $google_ads_row 
  
 ( 
 @ 
 { 
 $search_response 
 - 
 { 
 results 
 }}) 
  
 { 
  
 push 
  
 @$customer_conversion_goals 
 , 
  
 { 
  
 category 
  
 = 
  
 $google_ads_row 
 - 
 { 
 customerConversionGoal 
 }{ 
 category 
 }, 
  
 origin 
  
 = 
  
 $google_ads_row 
 - 
 { 
 customerConversionGoal 
 }{ 
 origin 
 }}; 
  
 } 
  
 return 
  
 $customer_conversion_goals 
 ; 
 } 
 # Creates a list of MutateOperations that override customer conversion goals. 
 sub 
  
 create_conversion_goal_operations 
  
 { 
  
 my 
  
 ( 
 $customer_id 
 , 
  
 $customer_conversion_goals 
 ) 
  
 = 
  
 @_ 
 ; 
  
 my 
  
 $operations 
  
 = 
  
 [] 
 ; 
  
 # To override the> customer conversion goals, >we will change the biddability of 
  
 # each of the customer conversion goals so that only the desired conversion goal 
  
 # is biddable in this campaign. 
  
 foreach 
  
 my 
  
 $customer_conversion_goal 
  
 ( 
 @$cust>omer_conversion_goals 
 ) 
  
 { 
  
 my 
  
 $campaign_conver>sion_goal 
  
 = 
  
 Google::Ads::GoogleAds::V21::Resources:: 
 CampaignConversionGoal 
 - 
 new 
 ({ 
  
 resourceName 
  
 = 
  
 Google::Ads::GoogleAds::V21::Utils::ResourceNames:: 
 campaign_conversion_goal 
 ( 
  
 $customer_id 
 , 
  
 PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID 
 , 
  
 $customer_conversion_goal 
 - 
 { 
 category 
 }, 
  
 $customer_conversion_goal 
 - 
 { 
 origin 
 })}); 
  
 # Change the biddability for the campaign conversion goal. 
  
 # Set biddability to true for the de>sired (category, origin). 
 && 
 # Set biddability to false> for all other conversion goals. 
  
 # Note: 
  
 #  1- It i>s assumed that this Conversion Action 
  
 #     (category=PURCHASE>, origin=WEBSITE) exists in this account. 
  
 #  2- More than one goal can be biddable if desired. This example 
  
 #     shows only one. 
>  
 if 
  
 ( 
  
 $customer_conversion_goal 
 - 
 { 
 category 
 } 
  
 e>q 
  
 PURCHASE 
  
 $customer_conversion_goal 
 - 
 { 
 origin 
 } 
  
 eq 
  
 WEBSITE 
 ) 
  
 { 
  
 $campaign_conversion_goal 
 - 
 { 
 biddable 
 } 
  
 = 
  
 "tr>ue" 
 ; 
  
 } 
  
 else 
  
 { 
 > 
 $campaign_conversion_goal 
 - 
 { 
 biddable 
 } 
  
 = 
  
 "false" 
 ; 
  
 } 
  
 push 
  
 @$operations 
 , 
  
 Google::Ads::GoogleAds::V21::Services::GoogleAdsService:: 
 MutateOperation 
  
 - 
 new 
 ({ 
  
 campaignConversio>nGoalOperation 
  
 = 
  
 Google::Ads::GoogleAds::V21::Services::CampaignConversionGoalService:: 
 CampaignConversionGoalOperation 
  
 - 
 new 
 ({ 
  
 update 
  
 = 
  
 $campaign_conversion_goal 
 , 
  
 # Set the update mask on the operation. Here the update mask will be 
  
 # a list of all the fields that were set on the update object. 
  
 update>Mask 
  
 = 
  
 all_set_fields_of 
 ( 
 $campaign_conversion_goal 
 )})}); 
  
 } 
  
 return 
  
 $o>perations 
 ; 
 } 
 # Prints the details of a MutateGoogleAdsResponse. 
 # Parses the "response" oneof fiel>d name and uses it to extract the new entity's 
 # name and resource name. 
 sub 
  
 print_response_details 
  
 { 
  
 my 
  
 ( 
 $mutate_google_ads_response 
 ) 
  
 = 
  
 @_ 
 ; 
  
 foreach 
  
 my 
  
 $response 
  
 ( 
 @ 
 { 
 $mutate_google_ads_response 
 - 
 { 
 mutateOperationResponses 
 }}) 
  
 { 
  
 my 
  
 $result_type 
  
 = 
  
 [ 
 keys 
  
 %$respons>e 
 ] 
 - 
 [ 
 0 
 ]; 
  
 printf 
  
 "Created a(n) %s with '%s'.\n" 
 , 
  
 ucfirst 
  
 $re>sult_type 
  
 =~ 
  
 s/Result$// 
 r 
 , 
  
 $response 
 - 
 { 
 $result_type 
 }{ 
 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 a>ny server returned fault. 
 $api_client 
 - 
 set_die_on_f>aults 
 ( 
 1 
 ); 
 my 
  
 $customer_id 
  
 = 
  
 undef 
 ; 
 my 
  
 $merchant_c>enter_account_id 
  
 = 
  
 undef 
 ; 
 my 
  
 $sales_country 
 > 
 = 
  
 "US" 
 ; 
 my 
  
 $final_url 
 > 
 = 
  
 "http://www.example.com" 
 ; 
 my 
  
 $brand_guidelines_enabled 
  
 = 
  
 "false" 
 ; 
 # Parameters passed on the command line will override any parameters set in code. 
 GetOptions 
 ( 
  
 "customer_id=s" 
  
 = 
  
 \ 
 $customer_id 
 , 
  
 "merchant_center_account_id=i" 
  
 = 
  
 \ 
 $merchant_center_account_id 
 , 
  
 "sales_country=s" 
  
 = 
  
 \ 
 $sales_country 
 , 
  
 "final_url=s" 
  
 = 
  
 \ 
 $final_url 
 , 
  
 "brand_guidelines_enabled=s" 
  
 = 
  
 \ 
 $brand_guidelines_enabled 
 ); 
 # 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 
 , 
  
 $merchant_center_account_id 
 , 
  
 $sales_country 
 , 
  
 $final_url 
 ); 
 # Call the example. 
 add_performance_max_retail_campaign 
 ( 
 $api_client 
 , 
  
 $customer_id 
  
 =~ 
  
 s/-//g 
 r 
 , 
  
 $merchant_center_account_id 
 , 
  
 $sales_country 
 , 
  
 $final_url 
 , 
  
 $brand_guidelines_enabled 
 ); 
 =pod 
 =head1 NAME 
 add_performance_max_retail_campaign 
 =head1 DESCRIPTION 
 This example shows how to create a Performance Max retail campaign. 
 This will be created for "All products". 
 For more information about Performance Max retail campaigns, see 
 https://developers.google.com/google-ads/api/docs/performance-max/retail. 
 Prerequisites: 
 - You need to have access to a Merchant Center account. You can find 
 instructions to create a Merchant Center account here: 
 https://support.google.com/merchants/answer/188924. 
 This account must be linked to your Google Ads account. The integration 
 instructions can be found at: 
 https://developers.google.com/google-ads/api/docs/shopping-ads/merchant-center. 
 - You need your Google Ads account to track conversions. The different ways 
 to track conversions can be found here: 
 https://support.google.com/google-ads/answer/1722054. 
 - You must have at least one conversion action in the account. For more about 
 conversion actions, see 
 https://developers.google.com/google-ads/api/docs/conversions/overview#conversion_actions. 
 =head1 SYNOPSIS 
 add_performance_max_retail_campaign.pl [options] 
 -help  
 
 -customer_id                  The Google Ads customer ID. 
 -merchant_center_account_id   The Merchant Center account ID. 
 -sales_country                [optional] The sales country of products to include in the campaign. 
 -final_url                    [optional] The final URL for the asset group of the campaign. 
 -brand_guidelines_enabled	  [optional] A boolean value indicating if the campaign is enabled for brand guidelines. Defaults to false. 
 =cut 
 add_performance_max_retail_campaign 
 . 
 pl 
  
Create a Mobile Website
View Site in Mobile | Classic
Share by: