Ява
// 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.advancedoperations;
import static com.google.ads.googleads.examples.utils.CodeSampleHelper.getPrintableDateTime;
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.v17.common.AudienceInfo;
import com.google.ads.googleads.v17.common.ImageAsset;
import com.google.ads.googleads.v17.common.LanguageInfo;
import com.google.ads.googleads.v17.common.LocationInfo;
import com.google.ads.googleads.v17.common.MaximizeConversionValue;
import com.google.ads.googleads.v17.common.TextAsset;
import com.google.ads.googleads.v17.enums.AdvertisingChannelTypeEnum.AdvertisingChannelType;
import com.google.ads.googleads.v17.enums.AssetFieldTypeEnum.AssetFieldType;
import com.google.ads.googleads.v17.enums.AssetGroupStatusEnum.AssetGroupStatus;
import com.google.ads.googleads.v17.enums.BudgetDeliveryMethodEnum.BudgetDeliveryMethod;
import com.google.ads.googleads.v17.enums.CampaignStatusEnum.CampaignStatus;
import com.google.ads.googleads.v17.errors.GoogleAdsError;
import com.google.ads.googleads.v17.errors.GoogleAdsException;
import com.google.ads.googleads.v17.resources.Asset;
import com.google.ads.googleads.v17.resources.AssetGroup;
import com.google.ads.googleads.v17.resources.AssetGroupAsset;
import com.google.ads.googleads.v17.resources.AssetGroupSignal;
import com.google.ads.googleads.v17.resources.Campaign;
import com.google.ads.googleads.v17.resources.CampaignBudget;
import com.google.ads.googleads.v17.resources.CampaignCriterion;
import com.google.ads.googleads.v17.services.AssetGroupAssetOperation;
import com.google.ads.googleads.v17.services.AssetGroupOperation;
import com.google.ads.googleads.v17.services.AssetGroupSignalOperation;
import com.google.ads.googleads.v17.services.AssetOperation;
import com.google.ads.googleads.v17.services.CampaignBudgetOperation;
import com.google.ads.googleads.v17.services.CampaignCriterionOperation;
import com.google.ads.googleads.v17.services.CampaignOperation;
import com.google.ads.googleads.v17.services.GoogleAdsServiceClient;
import com.google.ads.googleads.v17.services.MutateGoogleAdsResponse;
import com.google.ads.googleads.v17.services.MutateOperation;
import com.google.ads.googleads.v17.services.MutateOperationResponse;
import com.google.ads.googleads.v17.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 campaign.
*
* <p>For more information about Performance Max campaigns, see
* https://developers.google.com/google-ads/api/docs/performance-max/overview
*
* <p>Prerequisites: - 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
*
* <p>This example uses the default customer conversion goals. For an example of setting
* campaign-specific conversion goals, see {@link
* com.google.ads.googleads.examples.shoppingads.AddPerformanceMaxRetailCampaign}.
*/
public class AddPerformanceMaxCampaign {
// We specify temporary IDs that are specific to a single mutate request. Temporary IDs are always
// negative and unique within one mutate request.
//
// <p>See https://developers.google.com/google-ads/api/docs/mutating/best-practices for further
// details.
//
// <p>These 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 AddPerformanceMaxCampaignParams extends CodeSampleParams {
@Parameter(names = ArgumentNames.CUSTOMER_ID, required = true)
private Long customerId;
@Parameter(
names = ArgumentNames.AUDIENCE_ID,
description =
"An audience ID to use to improve the targeting of the Performance Max campaign")
private Long audienceId;
}
public static void main(String[] args) throws IOException {
AddPerformanceMaxCampaignParams params = new AddPerformanceMaxCampaignParams();
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");
// Optional: Specify an audience ID.
// params.audienceId = Long.parseLong("INSERT_AUDIENCE_ID_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 AddPerformanceMaxCampaign()
.runExample(googleAdsClient, params.customerId, params.audienceId);
} 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 audienceId the optional audience ID.
*/
private void runExample(GoogleAdsClient googleAdsClient, long customerId, Long audienceId)
throws IOException {
// 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.
List<String> headlines = ImmutableList.of("Travel", "Travel Reviews", "Book travel");
List<String> headlineAssetResourceNames =
createMultipleTextAssets(googleAdsClient, customerId, headlines);
// Creates the descriptions.
List<String> descriptions = ImmutableList.of("Take to the air!", "Fly to the sky!");
List<String> 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 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
List<MutateOperation> mutateOperations = new ArrayList<>();
mutateOperations.add(createCampaignBudgetOperation(customerId));
mutateOperations.add(createPerformanceMaxCampaignOperation(customerId));
mutateOperations.addAll(createCampaignCriterionOperations(customerId));
String assetGroupResourceName = ResourceNames.assetGroup(customerId, ASSET_GROUP_TEMPORARY_ID);
mutateOperations.addAll(
createAssetGroupOperations(
customerId,
assetGroupResourceName,
headlineAssetResourceNames,
descriptionAssetResourceNames));
if (audienceId != null) {
mutateOperations.addAll(
createAssetGroupSignalOperations(customerId, assetGroupResourceName, audienceId));
}
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 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) {
Campaign performanceMaxCampaign =
Campaign.newBuilder()
.setName("Performance Max 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.
.setMaximizeConversionValue(
MaximizeConversionValue.newBuilder().setTargetRoas(3.5).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.
.setUrlExpansionOptOut(false)
// 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))
// Optional fields.
.setStartDate(new DateTime().plusDays(1).toString("yyyyMMdd"))
.setEndDate(new DateTime().plusDays(365).toString("yyyyMMdd"))
.build();
return MutateOperation.newBuilder()
.setCampaignOperation(
CampaignOperation.newBuilder().setCreate(performanceMaxCampaign).build())
.build();
}
/** Creates a list of MutateOperations that create new campaign criteria. */
private List<MutateOperation> createCampaignCriterionOperations(long customerId) {
String campaignResourceName =
ResourceNames.campaign(customerId, PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID);
List<CampaignCriterion> 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
//
// We will add one positive location target for New York City (ID=1023191)
// and one negative location target for Brooklyn (ID=1022762).
// First, adds the positive (negative = False) for New York City.
campaignCriteria.add(
CampaignCriterion.newBuilder()
.setCampaign(campaignResourceName)
.setLocation(
LocationInfo.newBuilder()
.setGeoTargetConstant(ResourceNames.geoTargetConstant(1023191))
.build())
.setNegative(false)
.build());
// Next adds the negative target for Brooklyn.
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(
LanguageInfo.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.newBuilder()
.setCampaignCriterionOperation(
CampaignCriterionOperation.newBuilder().setCreate(criterion).build())
.build())
.collect(Collectors.toList());
}
/** Creates multiple text assets and returns the list of resource names. */
private List<String> createMultipleTextAssets(
GoogleAdsClient googleAdsClient, long customerId, List<String> texts) {
List<MutateOperation> mutateOperations = new ArrayList<>();
for (String text : texts) {
Asset asset = Asset.newBuilder().setTextAsset(TextAsset.newBuilder().setText(text)).build();
AssetOperation assetOperation = AssetOperation.newBuilder().setCreate(asset).build();
mutateOperations.add(MutateOperation.newBuilder().setAssetOperation(assetOperation).build());
}
List<String> 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().getResourceName());
}
}
printResponseDetails(response);
}
return assetResourceNames;
}
/** Creates a list of MutateOperations that create a new AssetGroup. */
private List<MutateOperation> createAssetGroupOperations(
long customerId,
String assetGroupResourceName,
List<String> headlineAssetResourceNames,
List<String> descriptionAssetResourceNames)
throws IOException {
List<MutateOperation> mutateOperations = new ArrayList<>();
String campaignResourceName =
ResourceNames.campaign(customerId, PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID);
// Creates the AssetGroup.
AssetGroup assetGroup =
AssetGroup.newBuilder()
.setName("Performance Max asset group #" + getPrintableDateTime())
.setCampaign(campaignResourceName)
.addFinalUrls("http://www.example.com")
.addFinalMobileUrls("http://www.example.com")
.setStatus(AssetGroupStatus.PAUSED)
.setResourceName(assetGroupResourceName)
.build();
AssetGroupOperation assetGroupOperation =
AssetGroupOperation.newBuilder().setCreate(assetGroup).build();
mutateOperations.add(
MutateOperation.newBuilder().setAssetGroupOperation(assetGroupOperation).build());
// 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) {
AssetGroupAsset assetGroupAsset =
AssetGroupAsset.newBuilder()
.setFieldType(AssetFieldType.HEADLINE)
.setAssetGroup(assetGroupResourceName)
.setAsset(resourceName)
.build();
AssetGroupAssetOperation assetGroupAssetOperation =
AssetGroupAssetOperation.newBuilder().setCreate(assetGroupAsset).build();
mutateOperations.add(
MutateOperation.newBuilder()
.setAssetGroupAssetOperation(assetGroupAssetOperation)
.build());
}
// Links the description assets.
for (String resourceName : descriptionAssetResourceNames) {
AssetGroupAsset assetGroupAsset =
AssetGroupAsset.newBuilder()
.setFieldType(AssetFieldType.DESCRIPTION)
.setAssetGroup(assetGroupResourceName)
.setAsset(resourceName)
.build();
AssetGroupAssetOperation assetGroupAssetOperation =
AssetGroupAssetOperation.newBuilder().setCreate(assetGroupAsset).build();
mutateOperations.add(
MutateOperation.newBuilder()
.setAssetGroupAssetOperation(assetGroupAssetOperation)
.build());
}
// Creates and links the long headline text asset.
List<MutateOperation> createAndLinkTextAssetOperations =
createAndLinkTextAsset(customerId, "Travel the World", AssetFieldType.LONG_HEADLINE);
mutateOperations.addAll(createAndLinkTextAssetOperations);
// Creates and links the business name text asset.
createAndLinkTextAssetOperations =
createAndLinkTextAsset(customerId, "Interplanetary Cruises", AssetFieldType.BUSINESS_NAME);
mutateOperations.addAll(createAndLinkTextAssetOperations);
// Creates and links the image assets.
// Creates and links the Logo Asset.
createAndLinkTextAssetOperations =
createAndLinkImageAsset(
customerId, "https://gaagl.page.link/bjYi", AssetFieldType.LOGO, "Marketing Logo");
mutateOperations.addAll(createAndLinkTextAssetOperations);
// Creates and links the Marketing Image Asset.
createAndLinkTextAssetOperations =
createAndLinkImageAsset(
customerId,
"https://gaagl.page.link/Eit5",
AssetFieldType.MARKETING_IMAGE,
"Marketing Image");
mutateOperations.addAll(createAndLinkTextAssetOperations);
// Creates and links the Square Marketing Image Asset.
createAndLinkTextAssetOperations =
createAndLinkImageAsset(
customerId,
"https://gaagl.page.link/bjYi",
AssetFieldType.SQUARE_MARKETING_IMAGE,
"Square Marketing Image");
mutateOperations.addAll(createAndLinkTextAssetOperations);
return mutateOperations;
}
/** Creates a list of MutateOperations that create a new linked text asset. */
List<MutateOperation> createAndLinkTextAsset(
long customerId, String text, AssetFieldType assetFieldType) {
List<MutateOperation> 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(MutateOperation.newBuilder().setAssetOperation(assetOperation).build());
// Creates an AssetGroupAsset to link the Asset to the AssetGroup.
AssetGroupAsset assetGroupAsset =
AssetGroupAsset.newBuilder()
.setFieldType(assetFieldType)
.setAssetGroup(ResourceNames.assetGroup(customerId, ASSET_GROUP_TEMPORARY_ID))
.setAsset(assetResourceName)
.build();
AssetGroupAssetOperation assetGroupAssetOperation =
AssetGroupAssetOperation.newBuilder().setCreate(assetGroupAsset).build();
mutateOperations.add(
MutateOperation.newBuilder().setAssetGroupAssetOperation(assetGroupAssetOperation).build());
return mutateOperations;
}
/** Creates a list of MutateOperations that create a new linked image asset. */
List<MutateOperation> createAndLinkImageAsset(
long customerId, String url, AssetFieldType assetFieldType, String assetName)
throws IOException {
List<MutateOperation> 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(MutateOperation.newBuilder().setAssetOperation(assetOperation).build());
// Creates an AssetGroupAsset to link the Asset to the AssetGroup.
AssetGroupAsset assetGroupAsset =
AssetGroupAsset.newBuilder()
.setFieldType(assetFieldType)
.setAssetGroup(ResourceNames.assetGroup(customerId, ASSET_GROUP_TEMPORARY_ID))
.setAsset(assetResourceName)
.build();
AssetGroupAssetOperation assetGroupAssetOperation =
AssetGroupAssetOperation.newBuilder().setCreate(assetGroupAsset).build();
mutateOperations.add(
MutateOperation.newBuilder().setAssetGroupAssetOperation(assetGroupAssetOperation).build());
return mutateOperations;
}
/**
* Creates a list of MutateOperations that create {@link
* com.google.ads.googleads.v17.resources.AssetGroupSignal} objects.
*/
private List<MutateOperation> createAssetGroupSignalOperations(
long customerId, String assetGroupResourceName, Long audienceId) {
List<MutateOperation> mutateOperations = new ArrayList<>();
AssetGroupSignal assetGroupSignal =
AssetGroupSignal.newBuilder()
.setAssetGroup(assetGroupResourceName)
.setAudience(
AudienceInfo.newBuilder()
.setAudience(ResourceNames.audience(customerId, audienceId)))
.build();
// Adds an operation to the list to create the asset group signal.
mutateOperations.add(
MutateOperation.newBuilder()
.setAssetGroupSignalOperation(
AssetGroupSignalOperation.newBuilder().setCreate(assetGroupSignal))
.build());
return mutateOperations;
}
/**
* Prints the details of a MutateGoogleAdsResponse.
*
* <p>Parses the "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 (Entry<FieldDescriptor, Object> responseFields : result.getAllFields().entrySet()) {
String fieldName = responseFields.getKey().getName();
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--;
}
}
С#
// 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.V17.Common;
using Google.Ads.GoogleAds.V17.Errors;
using Google.Ads.GoogleAds.V17.Resources;
using Google.Ads.GoogleAds.V17.Services;
using Google.Protobuf;
using System;
using System.Collections.Generic;
using System.Threading;
using static Google.Ads.GoogleAds.V17.Enums.AdvertisingChannelTypeEnum.Types;
using static Google.Ads.GoogleAds.V17.Enums.AssetFieldTypeEnum.Types;
using static Google.Ads.GoogleAds.V17.Enums.AssetGroupStatusEnum.Types;
using static Google.Ads.GoogleAds.V17.Enums.BudgetDeliveryMethodEnum.Types;
using static Google.Ads.GoogleAds.V17.Enums.CampaignStatusEnum.Types;
namespace Google.Ads.GoogleAds.Examples.V17
{
/// <summary>
/// This example shows how to create a Performance Max campaign.
///
/// For more information about Performance Max campaigns, see
/// https://developers.google.com/google-ads/api/docs/performance-max/overview
///
/// Prerequisites:
/// - 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
///
/// This example uses the default customer conversion goals. For an example
/// of setting campaign-specific conversion goals, see
/// ShoppingAds/AddPerformanceMaxRetailCampaign.cs
/// </summary>
public class AddPerformanceMaxCampaign : ExampleBase
{
/// <summary>
/// Command line options for running the <see cref="AddPerformanceMaxCampaign"/> example.
/// </summary>
public class Options : OptionsBase
{
/// <summary>
/// The Google Ads customer ID.
/// </summary>
[Option("customerId", Required = true, HelpText =
"The Google Ads customer ID.")]
public long CustomerId { get; set; }
/// <summary>
/// Optional: An audience ID to use to improve the targeting of the Performance Max
/// campaign.
/// </summary>
[Option("audienceId", Required = false, HelpText = "The ID of an audience.")]
public long? AudienceId { get; set; }
}
/// <summary>
/// Main method, to run this code example as a standalone application.
/// </summary>
/// <param name="args">The command line arguments.</param>
public static void Main(string[] args)
{
Options options = ExampleUtilities.ParseCommandLine<Options>(args);
AddPerformanceMaxCampaign codeExample = new AddPerformanceMaxCampaign();
Console.WriteLine(codeExample.Description);
codeExample.Run(
new GoogleAdsClient(),
options.CustomerId,
options.AudienceId
);
}
// 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 AssetGroupAssetTemporaryResourceNameGenerator
{
private long customerId;
private long assetGroupId;
private long next;
public AssetGroupAssetTemporaryResourceNameGenerator(long customerId, long assetGroupId)
{
this.customerId = customerId;
this.assetGroupId = assetGroupId;
this.next = assetGroupId - 1;
}
public string Next()
{
long i = next;
Interlocked.Decrement(ref next);
return ResourceNames.Asset(customerId, i);
}
}
/// <summary>
/// Returns a description about the code example.
/// </summary>
public override string Description =>
"This example shows how to create a Performance Max campaign.";
/// <summary>
/// Runs the code example.
/// </summary>
/// <param name="client">The Google Ads client.</param>
/// <param name="customerId">The Google Ads customer ID.</param>
/// <param name="audienceId">The optional audience ID.</param>
public void Run(GoogleAdsClient client, long customerId, long? audienceId)
{
try
{
GoogleAdsServiceClient googleAdsServiceClient =
client.GetService(Services.V17.GoogleAdsService);
// 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.
List<string> headlineAssetResourceNames = CreateMultipleTextAssets(
client,
customerId,
new[] {
"Travel",
"Travel Reviews",
"Book travel"
}
);
// Create the descriptions.
List<string> descriptionAssetResourceNames = CreateMultipleTextAssets(
client,
customerId,
new[] {
"Take to the air!",
"Fly to the sky!"
}
);
string tempResourceNameCampaignBudget = ResourceNames.CampaignBudget(
customerId,
TEMPORARY_ID_BUDGET
);
// 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 is 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
);
List<MutateOperation> campaignCriterionOperations =
CreateCampaignCriterionOperations(tempResourceNameCampaign);
List<MutateOperation> assetGroupOperations =
CreateAssetGroupOperations(
tempResourceNameCampaign,
ResourceNames.AssetGroup(customerId, TEMPORARY_ID_ASSET_GROUP),
headlineAssetResourceNames,
descriptionAssetResourceNames,
new AssetGroupAssetTemporaryResourceNameGenerator(
customerId,
TEMPORARY_ID_ASSET_GROUP
),
client.Config
);
List<MutateOperation> assetGroupSignalOperations =
CreateAssetGroupSignalOperations(
customerId,
ResourceNames.AssetGroup(customerId, TEMPORARY_ID_ASSET_GROUP),
audienceId
);
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(assetGroupSignalOperations);
MutateGoogleAdsResponse response = googleAdsServiceClient.Mutate(request);
PrintResponseDetails(response);
}
catch (GoogleAdsException e)
{
Console.WriteLine("Failure:");
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 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.
/// </summary>
/// <param name="budgetResourceName">The temporary resource name of the budget to
/// create.</param>
/// <returns>A 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 later steps.
ResourceName = budgetResourceName
}
}
};
return operation;
}
/// Creates a MutateOperation that creates a new Performance Max campaign.
/// <param name="campaignResourceName">The campaign resource name.</param>
/// <param name="campaignBudgetResourceName">The campaign budget resource name.</param>
/// <returns>A MutateOperations that will create this new campaign.</returns>
private MutateOperation CreatePerformanceMaxCampaignOperation(
string campaignResourceName,
string campaignBudgetResourceName)
{
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 AdvertisingChannelType of
// PerformanceMax. The AdvertisingChannelSubType 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
},
// 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.
UrlExpansionOptOut = false,
// Use the temporary resource name created earlier
ResourceName = campaignResourceName,
// Set the budget using the given budget resource name.
CampaignBudget = campaignBudgetResourceName,
// Optional fields
StartDate = DateTime.Now.AddDays(1).ToString("yyyyMMdd"),
EndDate = DateTime.Now.AddDays(365).ToString("yyyyMMdd")
}
}
};
return operation;
}
/// <summary>
/// Creates a list of MutateOperations that create new campaign criteria.
/// </summary>
/// <param name="campaignResourceName">The campaign resource name.</param>
/// <returns>A list of MutateOperations that create new campaign criteria.</returns>
private List<MutateOperation> CreateCampaignCriterionOperations(
string campaignResourceName)
{
List<MutateOperation> operations = new 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
//
// 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:
// https://developers.google.com/google-ads/api/reference/data/codes-formats#expandable-7
Language = new LanguageInfo()
{
LanguageConstant = ResourceNames.LanguageConstant(1000) // English
},
}
}
};
operations.Add(operation3);
return operations;
}
/// <summary>
/// Creates multiple text assets and returns the list of resource names.
/// </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>
/// <returns>A list of asset resource names.</returns>
private List<string> CreateMultipleTextAssets(
GoogleAdsClient client,
long customerId,
string[] texts)
{
// Get the GoogleAdsService.
GoogleAdsServiceClient googleAdsServiceClient =
client.GetService(Services.V17.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 = googleAdsServiceClient.Mutate(request);
List<string> assetResourceNames = new List<string>();
foreach (MutateOperationResponse operationResponse in response.MutateOperationResponses)
{
MutateAssetResult assetResult = operationResponse.AssetResult;
assetResourceNames.Add(assetResult.ResourceName);
}
PrintResponseDetails(response);
return assetResourceNames;
}
/// <summary>
/// Creates a list of MutateOperations that create a new asset_group.
/// </summary>
/// <param name="campaignResourceName">The campaign resource name.</param>
/// <param name="assetGroupResourceName">The asset group resource name.</param>
/// <param name="headlineAssetResourceNames">The headline asset resource names.</param>
/// <param name="descriptionAssetResourceNames">The description asset resource
/// names.</param>
/// <param name="resourceNameGenerator">A generator for unique temporary ID's.</param>
/// <param name="config">The Google Ads config.</param>
/// <returns>A list of MutateOperations that create the new asset group.</returns>
private List<MutateOperation> CreateAssetGroupOperations(
string campaignResourceName,
string assetGroupResourceName,
List<string> headlineAssetResourceNames,
List<string> descriptionAssetResourceNames,
AssetGroupAssetTemporaryResourceNameGenerator resourceNameGenerator,
GoogleAdsConfig config)
{
List<MutateOperation> operations = new List<MutateOperation>();
// Create the AssetGroup
operations.Add(
new MutateOperation()
{
AssetGroupOperation = new AssetGroupOperation()
{
Create = new AssetGroup()
{
Name = "Performance Max asset group #" +
ExampleUtilities.GetRandomString(),
Campaign = campaignResourceName,
FinalUrls = { "http://www.example.com" },
FinalMobileUrls = { "http://www.example.com" },
Status = AssetGroupStatus.Paused,
ResourceName = assetGroupResourceName
}
}
}
);
// 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.
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
}
}
}
);
}
// Create and link the long headline text asset.
operations.AddRange(
CreateAndLinkTextAsset(
assetGroupResourceName,
resourceNameGenerator.Next(),
"Travel the World",
AssetFieldType.LongHeadline
)
);
// Create and link the business name text asset.
operations.AddRange(
CreateAndLinkTextAsset(
assetGroupResourceName,
resourceNameGenerator.Next(),
"Interplanetary Cruises",
AssetFieldType.BusinessName
)
);
// Create and link the image assets.
// Create and link the Logo Asset.
operations.AddRange(
CreateAndLinkImageAsset(
assetGroupResourceName,
resourceNameGenerator.Next(),
"https://gaagl.page.link/bjYi",
AssetFieldType.Logo,
"Marketing Logo",
config
)
);
// Create and link the Marketing Image Asset.
operations.AddRange(
CreateAndLinkImageAsset(
assetGroupResourceName,
resourceNameGenerator.Next(),
"https://gaagl.page.link/Eit5",
AssetFieldType.MarketingImage,
"Marketing Image",
config
)
);
// Create and link the Square Marketing Image Asset.
operations.AddRange(
CreateAndLinkImageAsset(
assetGroupResourceName,
resourceNameGenerator.Next(),
"https://gaagl.page.link/bjYi",
AssetFieldType.SquareMarketingImage,
"Square Marketing Image",
config
)
);
return operations;
}
/// <summary>
/// Creates a list of MutateOperations that create a new linked text asset.
/// </summary>
/// <param name="assetGroupResourceName">The resource name of the asset group to be
/// created.</param>
/// <param name="assetResourceName">The resource name of the text asset to be
/// created.</param>
/// <param name="text">The text of the asset to be created.</param>
/// <param name="fieldType">The field type of the asset to be created.</param>
/// <returns>A list of MutateOperations that create the new linked text asset.</returns>
private List<MutateOperation> CreateAndLinkTextAsset(
string assetGroupResourceName,
string assetResourceName,
string text,
AssetFieldType fieldType)
{
List<MutateOperation> operations = new List<MutateOperation>();
// Create the Text Asset.
operations.Add(
new MutateOperation()
{
AssetOperation = new AssetOperation()
{
Create = new Asset()
{
ResourceName = assetResourceName,
TextAsset = new TextAsset()
{
Text = text
}
}
}
}
);
// Create an AssetGroupAsset to link the Asset to the AssetGroup.
operations.Add(
new MutateOperation()
{
AssetGroupAssetOperation = new AssetGroupAssetOperation()
{
Create = new AssetGroupAsset()
{
FieldType = fieldType,
AssetGroup = assetGroupResourceName,
Asset = assetResourceName
}
}
}
);
return operations;
}
/// <summary>
/// Creates a list of MutateOperations that create a new linked image asset.
/// </summary>
/// <param name="assetGroupResourceName">The resource name of the asset group to be
/// created.</param>
/// <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="fieldType">The field type of the asset to be created.</param>
/// <param name="assetName">The asset name.</param>
/// <param name="config">The Google Ads Config.</param>
/// <returns>A list of MutateOperations that create a new linked image asset.</returns>
private List<MutateOperation> CreateAndLinkImageAsset(
string assetGroupResourceName,
string assetResourceName,
string url,
AssetFieldType fieldType,
string assetName, GoogleAdsConfig config)
{
List<MutateOperation> operations = new List<MutateOperation>();
// Create the Image Asset.
operations.Add(
new MutateOperation()
{
AssetOperation = new AssetOperation()
{
Create = new Asset()
{
ResourceName = assetResourceName,
ImageAsset = new ImageAsset()
{
Data =
ByteString.CopyFrom(
MediaUtilities.GetAssetDataFromUrl(url, config)
)
},
// 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
}
}
}
);
// Create an AssetGroupAsset to link the Asset to the AssetGroup.
operations.Add(
new MutateOperation()
{
AssetGroupAssetOperation = new AssetGroupAssetOperation()
{
Create = new AssetGroupAsset()
{
FieldType = fieldType,
AssetGroup = assetGroupResourceName,
Asset = assetResourceName
}
}
}
);
return operations;
}
/// <summary>
/// Creates a list of MutateOperations that may create AssetGroupSignals
/// </summary>
/// <param name="customerId">The customer ID.</param>
/// <param name="assetGroupResourceName">The resource name of the asset group to be
/// created.</param>
/// <param name="audienceId">The optional audience ID.</param>
/// <returns>A list of MutateOperations that create may create AssetGroupSignals.</returns>
private List<MutateOperation> CreateAssetGroupSignalOperations(
long customerId,
string assetGroupResourceName,
long? audienceId)
{
List<MutateOperation> operations = new List<MutateOperation>();
if (!audienceId.HasValue)
{
return operations;
}
operations.Add(
new MutateOperation()
{
AssetGroupSignalOperation = new AssetGroupSignalOperation()
{
// To learn more about Audience Signals, see
// https://developers.google.com/google-ads/api/docs/performance-max/asset-groups#audience_signals
Create = new AssetGroupSignal()
{
AssetGroup = assetGroupResourceName,
Audience = new AudienceInfo()
{
Audience = ResourceNames.Audience(customerId, audienceId.Value)
}
}
}
}
);
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 entityName = operationResponse.ResponseCase.ToString();
// Trim the substring "Result" from the end of the entity name.
entityName = entityName.Remove(entityName.Length - 6);
string resourceName;
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.AssetGroupResult:
resourceName = operationResponse.AssetGroupResult.ResourceName;
break;
case MutateOperationResponse.ResponseOneofCase.AssetGroupAssetResult:
resourceName = operationResponse.AssetGroupAssetResult.ResourceName;
break;
default:
resourceName = "<not found>";
break;
}
Console.WriteLine(
$"Created a(n) {entityName} with resource name: '{resourceName}'.");
}
}
}
}
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\AdvancedOperations;
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\V17\GoogleAdsClient;
use Google\Ads\GoogleAds\Lib\V17\GoogleAdsClientBuilder;
use Google\Ads\GoogleAds\Lib\V17\GoogleAdsException;
use Google\Ads\GoogleAds\Util\V17\ResourceNames;
use Google\Ads\GoogleAds\V17\Common\AudienceInfo;
use Google\Ads\GoogleAds\V17\Common\ImageAsset;
use Google\Ads\GoogleAds\V17\Common\LanguageInfo;
use Google\Ads\GoogleAds\V17\Common\LocationInfo;
use Google\Ads\GoogleAds\V17\Common\MaximizeConversionValue;
use Google\Ads\GoogleAds\V17\Common\TextAsset;
use Google\Ads\GoogleAds\V17\Enums\AdvertisingChannelTypeEnum\AdvertisingChannelType;
use Google\Ads\GoogleAds\V17\Enums\AssetFieldTypeEnum\AssetFieldType;
use Google\Ads\GoogleAds\V17\Enums\AssetGroupStatusEnum\AssetGroupStatus;
use Google\Ads\GoogleAds\V17\Enums\BudgetDeliveryMethodEnum\BudgetDeliveryMethod;
use Google\Ads\GoogleAds\V17\Enums\CampaignStatusEnum\CampaignStatus;
use Google\Ads\GoogleAds\V17\Errors\GoogleAdsError;
use Google\Ads\GoogleAds\V17\Resources\Asset;
use Google\Ads\GoogleAds\V17\Resources\AssetGroup;
use Google\Ads\GoogleAds\V17\Resources\AssetGroupAsset;
use Google\Ads\GoogleAds\V17\Resources\AssetGroupSignal;
use Google\Ads\GoogleAds\V17\Resources\Campaign;
use Google\Ads\GoogleAds\V17\Resources\CampaignBudget;
use Google\Ads\GoogleAds\V17\Resources\CampaignCriterion;
use Google\Ads\GoogleAds\V17\Services\AssetGroupAssetOperation;
use Google\Ads\GoogleAds\V17\Services\AssetGroupOperation;
use Google\Ads\GoogleAds\V17\Services\AssetGroupSignalOperation;
use Google\Ads\GoogleAds\V17\Services\AssetOperation;
use Google\Ads\GoogleAds\V17\Services\CampaignBudgetOperation;
use Google\Ads\GoogleAds\V17\Services\CampaignCriterionOperation;
use Google\Ads\GoogleAds\V17\Services\CampaignOperation;
use Google\Ads\GoogleAds\V17\Services\MutateGoogleAdsRequest;
use Google\Ads\GoogleAds\V17\Services\MutateGoogleAdsResponse;
use Google\Ads\GoogleAds\V17\Services\MutateOperation;
use Google\Ads\GoogleAds\V17\Services\MutateOperationResponse;
use Google\ApiCore\ApiException;
use Google\ApiCore\Serializer;
/**
* This example shows how to create a Performance Max campaign.
*
* For more information about Performance Max campaigns, see
* https://developers.google.com/google-ads/api/docs/performance-max/overview.
*
* Prerequisites:
* - 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.
*
* This example uses the default customer conversion goals. For an example of setting
* campaign-specific conversion goals, see ShoppingAds/AddPerformanceMaxRetailCampaign.php.
*/
class AddPerformanceMaxCampaign
{
private const CUSTOMER_ID = 'INSERT_CUSTOMER_ID_HERE';
// Optional: An audience ID to use to improve the targeting of the Performance Max campaign.
private const AUDIENCE_ID = null;
// 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 the constants above.
$options = (new ArgumentParser())->parseCommandArguments([
ArgumentNames::CUSTOMER_ID => GetOpt::REQUIRED_ARGUMENT,
ArgumentNames::AUDIENCE_ID => GetOpt::OPTIONAL_ARGUMENT
]);
// Generate a refreshable OAuth2 credential for authentication.
$oAuth2Credential = (new OAuth2TokenBuilder())->fromFile()->build();
// Construct a Google Ads client configured from a properties file and the
// OAuth2 credentials above.
$googleAdsClient = (new GoogleAdsClientBuilder())
->fromFile()
->withOAuth2Credential($oAuth2Credential)
->build();
try {
self::runExample(
$googleAdsClient,
$options[ArgumentNames::CUSTOMER_ID] ?: self::CUSTOMER_ID,
$options[ArgumentNames::AUDIENCE_ID] ?: self::AUDIENCE_ID
);
} catch (GoogleAdsException $googleAdsException) {
printf(
"Request with ID '%s' has failed.%sGoogle Ads failure details:%s",
$googleAdsException->getRequestId(),
PHP_EOL,
PHP_EOL
);
foreach ($googleAdsException->getGoogleAdsFailure()->getErrors() as $error) {
/** @var GoogleAdsError $error */
printf(
"\t%s: %s%s",
$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|null $audienceId the audience ID
*/
public static function runExample(
GoogleAdsClient $googleAdsClient,
int $customerId,
?int $audienceId
) {
// 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);
$operations =
array_merge($operations, self::createCampaignCriterionOperations($customerId));
$operations = array_merge($operations, self::createAssetGroupOperations(
$customerId,
$headlineAssetResourceNames,
$descriptionAssetResourceNames
));
$operations = array_merge($operations, self::createAssetGroupSignalOperations(
$customerId,
ResourceNames::forAssetGroup($customerId, self::ASSET_GROUP_TEMPORARY_ID),
$audienceId
));
// Issues a mutate request to create 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): MutateOperation
{
// Creates a mutate operation that creates 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 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
* @return MutateOperation the mutate operation that creates the campaign
*/
private static function createPerformanceMaxCampaignOperation(int $customerId): MutateOperation
{
// Creates a mutate operation that creates a campaign operation.
return new MutateOperation([
'campaign_operation' => new CampaignOperation([
'create' => new Campaign([
'name' => 'Performance Max 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 campaign 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 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.
'maximize_conversion_value' => new MaximizeConversionValue([
'target_roas' => 3.5
]),
// 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.
'url_expansion_opt_out' => false,
// 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 = [];
// 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, adds the positive (negative = false) for New York City.
$operations[] = new MutateOperation([
'campaign_criterion_operation' => new CampaignCriterionOperation([
'create' => new CampaignCriterion([
'campaign' => ResourceNames::forCampaign(
$customerId,
self::PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID
),
'location' => new LocationInfo([
'geo_target_constant' => ResourceNames::forGeoTargetConstant(1023191)
]),
'negative' => false
])
])
]);
// Next adds the negative target for Brooklyn.
$operations[] = new MutateOperation([
'campaign_criterion_operation' => new CampaignCriterionOperation([
'create' => new CampaignCriterion([
'campaign' => ResourceNames::forCampaign(
$customerId,
self::PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID
),
'location' => new LocationInfo([
'geo_target_constant' => ResourceNames::forGeoTargetConstant(1022762)
]),
'negative' => true
])
])
]);
// Sets the LANGUAGE campaign criterion.
$operations[] = new MutateOperation([
'campaign_criterion_operation' => new CampaignCriterionOperation([
'create' => new CampaignCriterion([
'campaign' => ResourceNames::forCampaign(
$customerId,
self::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' => new LanguageInfo([
'language_constant' => ResourceNames::forLanguageConstant(1000) // English
])
])
])
]);
return $operations;
}
/**
* Creates multiple text assets and returns the list of resource names.
*
* @param GoogleAdsClient $googleAdsClient the Google Ads API client
* @param int $customerId the customer ID
* @param string[] $texts a list of strings, each of which will be used to create a text asset
* @return string[] a list of asset resource 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([
'asset_operation' => new AssetOperation([
'create' => new Asset(['text_asset' => new TextAsset(['text' => $text])])
])
]);
}
// Issues a mutate request to add all assets.
$googleAdsService = $googleAdsClient->getGoogleAdsServiceClient();
/** @var MutateGoogleAdsResponse $mutateGoogleAdsResponse */
$mutateGoogleAdsResponse =
$googleAdsService->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 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.
*
* @param GoogleAdsClient $googleAdsClient the Google Ads API client
* @param int $customerId the customer ID
* @param string[] $headlineAssetResourceNames a list of headline resource names
* @param string[] $descriptionAssetResourceNames a list of description resource names
* @return MutateOperation[] a list of MutateOperations that create new asset group
*/
private static function createAssetGroupOperations(
int $customerId,
array $headlineAssetResourceNames,
array $descriptionAssetResourceNames
): array {
$operations = [];
// Creates a new mutate operation that creates an asset group operation.
$operations[] = new MutateOperation([
'asset_group_operation' => new AssetGroupOperation([
'create' => new AssetGroup([
'resource_name' => ResourceNames::forAssetGroup(
$customerId,
self::ASSET_GROUP_TEMPORARY_ID
),
'name' => 'Performance Max asset group #' . Helper::getPrintableDatetime(),
'campaign' => ResourceNames::forCampaign(
$customerId,
self::PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID
),
'final_urls' => ['http://www.example.com'],
'final_mobile_urls' => ['http://www.example.com'],
'status' => AssetGroupStatus::PAUSED
])
])
]);
// 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.
foreach ($headlineAssetResourceNames 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::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::createAndLinkTextAsset(
$customerId,
'Interplanetary Cruises',
AssetFieldType::BUSINESS_NAME
));
// Creates and links the image assets.
// Creates and links the Logo Asset.
$operations = array_merge($operations, self::createAndLinkImageAsset(
$customerId,
'https://gaagl.page.link/bjYi',
AssetFieldType::LOGO,
'Marketing Logo'
));
// 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'
));
return $operations;
}
/**
* 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 the field type of the new asset in the AssetGroupAsset
* @return MutateOperation[] a list of MutateOperations that create a new linked text asset
*/
private static function createAndLinkTextAsset(
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
),
'field_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 = [];
// Creates a new mutate operation that creates an image asset.
$operations[] = new MutateOperation([
'asset_operation' => new AssetOperation([
'create' => new Asset([
'resource_name' => ResourceNames::forAsset($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::$nextTempId--;
return $operations;
}
/**
* Creates a list of MutateOperations that may create asset group signals.
*
* @param int $customerId the customer ID
* @param string $assetGroupResourceName the resource name of the asset group
* @param int|null $audienceId the audience ID
* @return MutateOperation[] a list of MutateOperations that may create asset group signals
*/
private static function createAssetGroupSignalOperations(
int $customerId,
string $assetGroupResourceName,
?int $audienceId
): array {
$operations = [];
if (is_null($audienceId)) {
return $operations;
}
$operations[] = new MutateOperation([
'asset_group_signal_operation' => new AssetGroupSignalOperation([
// To learn more about Audience Signals, see
// https://developers.google.com/google-ads/api/docs/performance-max/asset-groups#audience_signals.
'create' => new AssetGroupSignal([
'asset_group' => $assetGroupResourceName,
'audience' => new AudienceInfo([
'audience' => ResourceNames::forAudience($customerId, $audienceId)
])
])
])
]);
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
);
}
}
}
AddPerformanceMaxCampaign::main();
Питон
#!/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 campaign.
For more information about Performance Max campaigns, see
https://developers.google.com/google-ads/api/docs/performance-max/overview
Prerequisites:
- 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
This example uses the default customer conversion goals. For an example
of setting campaign-specific conversion goals, see
shopping_ads/add_performance_max_retail_campaign.py
"""
import argparse
from datetime import datetime, timedelta
import sys
from uuid import uuid4
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
import requests
# 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.
next_temp_id = int(_ASSET_GROUP_TEMPORARY_ID) - 1
def main(client, customer_id, audience_id):
"""The main method that creates all necessary entities for the example.
Args:
client: an initialized GoogleAdsClient instance.
customer_id: a client customer ID.
audience_id: an optional audience ID.
"""
googleads_service = client.get_service("GoogleAdsService")
# 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,
)
)
campaign_criterion_operations = create_campaign_criterion_operations(
client,
customer_id,
)
asset_group_operations = create_asset_group_operation(
client,
customer_id,
headline_asset_resource_names,
description_asset_resource_names,
)
asset_group_signal_operations = create_asset_group_signal_operations(
client, customer_id, audience_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_operations,
*asset_group_signal_operations,
]
# Send the operations in a single Mutate request.
response = googleads_service.mutate(
customer_id=customer_id, mutate_operations=mutate_operations
)
print_response_details(response)
def create_campaign_budget_operation(
client,
customer_id,
):
"""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 = client.get_type("MutateOperation")
campaign_budget_operation = mutate_operation.campaign_budget_operation
campaign_budget = campaign_budget_operation.create
campaign_budget.name = f"Performance Max 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.resource_name = client.get_service(
"CampaignBudgetService"
).campaign_budget_path(customer_id, _BUDGET_TEMPORARY_ID)
return mutate_operation
def create_performance_max_campaign_operation(
client,
customer_id,
):
"""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.
Returns:
a MutateOperation that creates a campaign.
"""
mutate_operation = client.get_type("MutateOperation")
campaign = mutate_operation.campaign_operation.create
campaign.name = f"Performance Max 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 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.
campaign.bidding_strategy_type = (
client.enums.BiddingStrategyTypeEnum.MAXIMIZE_CONVERSION_VALUE
)
campaign.maximize_conversion_value.target_roas = 3.5
# 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.
campaign.url_expansion_opt_out = False
# Assign the resource name with a temporary ID.
campaign_service = 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.campaign_budget = campaign_service.campaign_budget_path(
customer_id, _BUDGET_TEMPORARY_ID
)
# 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,
customer_id,
):
"""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 = client.get_service("CampaignService")
geo_target_constant_service = client.get_service("GeoTargetConstantService")
googleads_service = client.get_service("GoogleAdsService")
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
#
# 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.
mutate_operation = client.get_type("MutateOperation")
campaign_criterion = mutate_operation.campaign_criterion_operation.create
campaign_criterion.campaign = campaign_service.campaign_path(
customer_id, _PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID
)
campaign_criterion.location.geo_target_constant = (
geo_target_constant_service.geo_target_constant_path("1023191")
)
campaign_criterion.negative = False
operations.append(mutate_operation)
# Next add the negative target for Brooklyn.
mutate_operation = client.get_type("MutateOperation")
campaign_criterion = mutate_operation.campaign_criterion_operation.create
campaign_criterion.campaign = campaign_service.campaign_path(
customer_id, _PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID
)
campaign_criterion.location.geo_target_constant = (
geo_target_constant_service.geo_target_constant_path("1022762")
)
campaign_criterion.negative = True
operations.append(mutate_operation)
# Set the LANGUAGE campaign criterion.
mutate_operation = client.get_type("MutateOperation")
campaign_criterion = mutate_operation.campaign_criterion_operation.create
campaign_criterion.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.language.language_constant = (
googleads_service.language_constant_path("1000")
) # English
operations.append(mutate_operation)
return operations
def create_multiple_text_assets(client, customer_id, texts):
"""Creates multiple text assets and returns the list of resource names.
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 = client.get_service("GoogleAdsService")
operations = []
for text in texts:
mutate_operation = client.get_type("MutateOperation")
asset = mutate_operation.asset_operation.create
asset.text_asset.text = text
operations.append(mutate_operation)
# Send the operations in a single Mutate request.
response = googleads_service.mutate(
customer_id=customer_id,
mutate_operations=operations,
)
asset_resource_names = []
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,
customer_id,
headline_asset_resource_names,
description_asset_resource_names,
):
"""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.
Returns:
MutateOperations that create a new asset group and related assets.
"""
asset_group_service = client.get_service("AssetGroupService")
campaign_service = client.get_service("CampaignService")
operations = []
# Create the AssetGroup
mutate_operation = client.get_type("MutateOperation")
asset_group = mutate_operation.asset_group_operation.create
asset_group.name = f"Performance Max asset group #{uuid4()}"
asset_group.campaign = campaign_service.campaign_path(
customer_id, _PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID
)
asset_group.final_urls.append("http://www.example.com")
asset_group.final_mobile_urls.append("http://www.example.com")
asset_group.status = client.enums.AssetGroupStatusEnum.PAUSED
asset_group.resource_name = asset_group_service.asset_group_path(
customer_id,
_ASSET_GROUP_TEMPORARY_ID,
)
operations.append(mutate_operation)
# 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 = client.get_type("MutateOperation")
asset_group_asset = 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 = client.get_type("MutateOperation")
asset_group_asset = 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 = create_and_link_text_asset(
client,
customer_id,
"Travel the World",
client.enums.AssetFieldTypeEnum.LONG_HEADLINE,
)
operations.extend(mutate_operations)
# Create and link the business name text asset.
mutate_operations = create_and_link_text_asset(
client,
customer_id,
"Interplanetary Cruises",
client.enums.AssetFieldTypeEnum.BUSINESS_NAME,
)
operations.extend(mutate_operations)
# Create and link the image assets.
# Create and link the Logo Asset.
mutate_operations = create_and_link_image_asset(
client,
customer_id,
"https://gaagl.page.link/bjYi",
client.enums.AssetFieldTypeEnum.LOGO,
"Marketing Logo",
)
operations.extend(mutate_operations)
# Create and link the Marketing Image Asset.
mutate_operations = create_and_link_image_asset(
client,
customer_id,
"https://gaagl.page.link/Eit5",
client.enums.AssetFieldTypeEnum.MARKETING_IMAGE,
"Marketing Image",
)
operations.extend(mutate_operations)
# Create and link the Square Marketing Image Asset.
mutate_operations = 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)
return operations
def create_and_link_text_asset(client, customer_id, text, field_type):
"""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 = []
asset_service = client.get_service("AssetService")
asset_group_service = client.get_service("AssetGroupService")
# Create the Text Asset.
mutate_operation = client.get_type("MutateOperation")
asset = mutate_operation.asset_operation.create
asset.resource_name = asset_service.asset_path(customer_id, next_temp_id)
asset.text_asset.text = text
operations.append(mutate_operation)
# Create an AssetGroupAsset to link the Asset to the AssetGroup.
mutate_operation = client.get_type("MutateOperation")
asset_group_asset = mutate_operation.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_service.asset_path(
customer_id, next_temp_id
)
operations.append(mutate_operation)
next_temp_id -= 1
return operations
def create_and_link_image_asset(
client, customer_id, url, field_type, asset_name
):
"""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 = []
asset_service = client.get_service("AssetService")
asset_group_service = client.get_service("AssetGroupService")
# Create the Image Asset.
mutate_operation = client.get_type("MutateOperation")
asset = mutate_operation.asset_operation.create
asset.resource_name = asset_service.asset_path(customer_id, next_temp_id)
# 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.type_ = client.enums.AssetTypeEnum.IMAGE
asset.image_asset.data = get_image_bytes(url)
operations.append(mutate_operation)
# Create an AssetGroupAsset to link the Asset to the AssetGroup.
mutate_operation = client.get_type("MutateOperation")
asset_group_asset = mutate_operation.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_service.asset_path(
customer_id, next_temp_id
)
operations.append(mutate_operation)
next_temp_id -= 1
return operations
def get_image_bytes(url):
"""Loads image data from a URL.
Args:
url: a URL str.
Returns:
Images bytes loaded from the given URL.
"""
response = requests.get(url)
return response.content
def print_response_details(response):
"""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 = "_result"
for result in response.mutate_operation_responses:
for field_descriptor, value in result._pb.ListFields():
if field_descriptor.name.endswith(suffix):
name = field_descriptor.name[: -len(suffix)]
else:
name = field_descriptor.name
print(
f"Created a(n) {convert_snake_case_to_upper_case(name)} with "
f"{str(value).strip()}."
)
def create_asset_group_signal_operations(client, customer_id, audience_id):
"""Creates a list of MutateOperations that may create asset group signals.
Args:
client: an initialized GoogleAdsClient instance.
customer_id: a client customer ID.
audience_id: an optional audience ID.
Returns:
MutateOperations that create new asset group signals.
"""
googleads_service = client.get_service("GoogleAdsService")
asset_group_resource_name = googleads_service.asset_group_path(
customer_id, _ASSET_GROUP_TEMPORARY_ID
)
operations = []
if audience_id:
# Create an audience asset group signal.
# To learn more about Audience Signals, see:
# https://developers.google.com/google-ads/api/performance-max/asset-group-signals#audiences
mutate_operation = client.get_type("MutateOperation")
operation = mutate_operation.asset_group_signal_operation.create
operation.asset_group = asset_group_resource_name
operation.audience.audience = googleads_service.audience_path(
customer_id, audience_id
)
operations.append(mutate_operation)
# Create a search theme asset group signal.
# To learn more about Search Themes Signals, see:
# https://developers.google.com/google-ads/api/performance-max/asset-group-signals#search_themes
mutate_operation = client.get_type("MutateOperation")
operation = mutate_operation.asset_group_signal_operation.create
operation.asset_group = asset_group_resource_name
operation.search_theme.text = "travel"
operations.append(mutate_operation)
return operations
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description=("Creates a Performance Max 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(
"-a",
"--audience_id",
type=str,
help="The ID of an audience.",
)
args = parser.parse_args()
# GoogleAdsClient will read the google-ads.yaml configuration file in the
# home directory if none is specified.
googleads_client = GoogleAdsClient.load_from_storage(version="v17")
try:
main(googleads_client, args.customer_id, args.audience_id)
except GoogleAdsException as ex:
print(
f'Request with ID "{ex.request_id}" failed with status '
f'"{ex.error.code().name}" and includes the following errors:'
)
for error in ex.failure.errors:
print(f'Error with message "{error.message}".')
if error.location:
for field_path_element in error.location.field_path_elements:
print(f"\t\tOn field: {field_path_element.field_name}")
sys.exit(1)
Руби
#!/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 campaign.
#
# For more information about Performance Max campaigns, see
# https://developers.google.com/google-ads/api/docs/performance-max/overview
#
# Prerequisites:
# - 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
#
# This example uses the default customer conversion goals. For an example
# of setting campaign-specific conversion goals, see
# shopping_ads/add_performance_max_retail_campaign.rb
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_campaign(customer_id, audience_id)
# GoogleAdsClient will read a config file from
# ENV['HOME']/google_ads_config.rb when called without parameters
client = Google::Ads::GoogleAds::GoogleAdsClient.new
# 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,
)
campaign_criterion_operations = create_campaign_criterion_operations(
client,
customer_id,
)
asset_group_operations = create_asset_group_operation(
client,
customer_id,
headline_asset_resource_names,
description_asset_resource_names,
)
asset_group_signal_operations = create_asset_group_signal_operations(
client,
customer_id,
audience_id,
)
# 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_operations,
asset_group_signal_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)
client.operation.mutate do |m|
m.campaign_operation = client.operation.create_resource.campaign do |c|
c.name = "Performance Max 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 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.
c.url_expansion_opt_out = false
# 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)
# 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
#
# 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.
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)
cc.location = client.resource.location_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.
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)
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.
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 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_group_operation(
client,
customer_id,
headline_asset_resource_names,
description_asset_resource_names)
operations = []
# Create the AssetGroup
operations << client.operation.mutate do |m|
m.asset_group_operation = client.operation.create_resource.asset_group do |ag|
ag.name = "Performance Max asset group #{SecureRandom.uuid}"
ag.campaign = client.path.campaign(
customer_id,
PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID)
ag.final_urls << "http://www.example.com"
ag.final_mobile_urls << "http://www.example.com"
ag.status = :PAUSED
ag.resource_name = client.path.asset_group(
customer_id,
ASSET_GROUP_TEMPORARY_ID)
end
end
# 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.
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 text asset.
operations += create_and_link_text_asset(
client,
customer_id,
"Interplanetary Cruises",
:BUSINESS_NAME)
# Create and link the image assets.
# Create and link the Logo Asset.
operations += create_and_link_image_asset(
client,
customer_id,
"https://gaagl.page.link/bjYi",
:LOGO,
"Marketing Logo")
# 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")
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.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.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_GROUP_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)
# 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.
a.name = asset_name
a.type = :IMAGE
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
# Create a list of MutateOperations that create AssetGroupSignals.
def create_asset_group_signal_operations(client, customer_id, audience_id)
operations = []
return operations if audience_id.nil?
operations << client.operation.mutate do |m|
m.asset_group_signal_operation = client.operation.create_resource.
asset_group_signal do |ags|
ags.asset_group = client.path.asset_group(
customer_id,
ASSET_GROUP_TEMPORARY_ID,
)
ags.audience = client.resource.audience_info do |ai|
ai.audience = client.path.audience(customer_id, audience_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[:audience_id] = nil
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('-D', '--audience-id AUDIENCE-ID', String, 'Audience ID (optional)') do |v|
options[:audience_id] = v
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_campaign(
options.fetch(:customer_id).tr("-", ""),
options[:audience_id],
)
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("\tOn 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("\tType: %s\n\tCode: %s\n", k, v)
end
end
raise
end
end
Перл
#!/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 campaign.
#
# For more information about Performance Max campaigns, see
# https://developers.google.com/google-ads/api/docs/performance-max/overview.
#
# Prerequisites:
# - 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.
#
# This example uses the default customer conversion goals. For an example of
# setting campaign-specific conversion goals, see
# shopping_ads/add_performance_max_retail_campaign.pl.
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::V17::Resources::CampaignBudget;
use Google::Ads::GoogleAds::V17::Resources::Campaign;
use Google::Ads::GoogleAds::V17::Resources::CampaignCriterion;
use Google::Ads::GoogleAds::V17::Resources::Asset;
use Google::Ads::GoogleAds::V17::Resources::AssetGroup;
use Google::Ads::GoogleAds::V17::Resources::AssetGroupAsset;
use Google::Ads::GoogleAds::V17::Resources::AssetGroupSignal;
use Google::Ads::GoogleAds::V17::Common::MaximizeConversionValue;
use Google::Ads::GoogleAds::V17::Common::LocationInfo;
use Google::Ads::GoogleAds::V17::Common::LanguageInfo;
use Google::Ads::GoogleAds::V17::Common::TextAsset;
use Google::Ads::GoogleAds::V17::Common::ImageAsset;
use Google::Ads::GoogleAds::V17::Common::AudienceInfo;
use Google::Ads::GoogleAds::V17::Enums::BudgetDeliveryMethodEnum qw(STANDARD);
use Google::Ads::GoogleAds::V17::Enums::CampaignStatusEnum;
use Google::Ads::GoogleAds::V17::Enums::AdvertisingChannelTypeEnum
qw(PERFORMANCE_MAX);
use Google::Ads::GoogleAds::V17::Enums::AssetGroupStatusEnum;
use Google::Ads::GoogleAds::V17::Enums::AssetFieldTypeEnum
qw(HEADLINE DESCRIPTION LONG_HEADLINE BUSINESS_NAME LOGO MARKETING_IMAGE SQUARE_MARKETING_IMAGE);
use Google::Ads::GoogleAds::V17::Services::GoogleAdsService::MutateOperation;
use
Google::Ads::GoogleAds::V17::Services::CampaignBudgetService::CampaignBudgetOperation;
use Google::Ads::GoogleAds::V17::Services::CampaignService::CampaignOperation;
use
Google::Ads::GoogleAds::V17::Services::CampaignCriterionService::CampaignCriterionOperation;
use Google::Ads::GoogleAds::V17::Services::AssetService::AssetOperation;
use
Google::Ads::GoogleAds::V17::Services::AssetGroupService::AssetGroupOperation;
use
Google::Ads::GoogleAds::V17::Services::AssetGroupAssetService::AssetGroupAssetOperation;
use
Google::Ads::GoogleAds::V17::Services::AssetGroupSignalService::AssetGroupSignalOperation;
use Google::Ads::GoogleAds::V17::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;
# 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.
my $customer_id = "INSERT_CUSTOMER_ID_HERE";
my $audience_id = undef;
sub add_performance_max_campaign {
my ($api_client, $customer_id, $audience_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);
push @$operations, @{create_campaign_criterion_operations($customer_id)};
push @$operations,
@{
create_asset_group_operations(
$customer_id, $headline_asset_resource_names,
$description_asset_resource_names
)};
push @$operations,
@{create_asset_group_signal_operations($customer_id, $audience_id)};
# Issue a mutate request to create everything 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::GoogleAds::V17::Services::GoogleAdsService::MutateOperation->
new({
campaignBudgetOperation =>
Google::Ads::GoogleAds::V17::Services::CampaignBudgetService::CampaignBudgetOperation
->new({
create => Google::Ads::GoogleAds::V17::Resources::CampaignBudget->new(
{
# Set a temporary ID in the budget's resource name so it can be
# referenced by the campaign in later steps.
resourceName =>
Google::Ads::GoogleAds::V17::Utils::ResourceNames::campaign_budget(
$customer_id, BUDGET_TEMPORARY_ID
),
name => "Performance Max 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) = @_;
# Create a mutate operation that creates a campaign operation.
return
Google::Ads::GoogleAds::V17::Services::GoogleAdsService::MutateOperation->
new({
campaignOperation =>
Google::Ads::GoogleAds::V17::Services::CampaignService::CampaignOperation
->new({
create => Google::Ads::GoogleAds::V17::Resources::Campaign->new({
# Assign the resource name with a temporary ID.
resourceName =>
Google::Ads::GoogleAds::V17::Utils::ResourceNames::campaign(
$customer_id, PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID
),
name => "Performance Max campaign #" . uniqid(),
# Set the budget using the given budget resource name.
campaignBudget =>
Google::Ads::GoogleAds::V17::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::V17::Enums::CampaignStatusEnum::PAUSED,
# All Performance Max campaigns have an advertisingChannelType 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 Maximize 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 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.
maximizeConversionValue =>
Google::Ads::GoogleAds::V17::Common::MaximizeConversionValue->
new({
targetRoas => 3.5
}
),
# 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.
urlExpansionOptOut => "false",
# 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 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.
push @$operations,
Google::Ads::GoogleAds::V17::Services::GoogleAdsService::MutateOperation->
new({
campaignCriterionOperation =>
Google::Ads::GoogleAds::V17::Services::CampaignCriterionService::CampaignCriterionOperation
->new({
create =>
Google::Ads::GoogleAds::V17::Resources::CampaignCriterion->new({
campaign =>
Google::Ads::GoogleAds::V17::Utils::ResourceNames::campaign(
$customer_id, PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID
),
location =>
Google::Ads::GoogleAds::V17::Common::LocationInfo->new({
geoTargetConstant =>
Google::Ads::GoogleAds::V17::Utils::ResourceNames::geo_target_constant(
1023191)}
),
negative => "false"
})})});
# Next add the negative target for Brooklyn.
push @$operations,
Google::Ads::GoogleAds::V17::Services::GoogleAdsService::MutateOperation->
new({
campaignCriterionOperation =>
Google::Ads::GoogleAds::V17::Services::CampaignCriterionService::CampaignCriterionOperation
->new({
create =>
Google::Ads::GoogleAds::V17::Resources::CampaignCriterion->new({
campaign =>
Google::Ads::GoogleAds::V17::Utils::ResourceNames::campaign(
$customer_id, PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID
),
location =>
Google::Ads::GoogleAds::V17::Common::LocationInfo->new({
geoTargetConstant =>
Google::Ads::GoogleAds::V17::Utils::ResourceNames::geo_target_constant(
1022762)}
),
negative => "true"
})})});
# Set the LANGUAGE campaign criterion.
push @$operations,
Google::Ads::GoogleAds::V17::Services::GoogleAdsService::MutateOperation->
new({
campaignCriterionOperation =>
Google::Ads::GoogleAds::V17::Services::CampaignCriterionService::CampaignCriterionOperation
->new({
create =>
Google::Ads::GoogleAds::V17::Resources::CampaignCriterion->new({
campaign =>
Google::Ads::GoogleAds::V17::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::V17::Common::LanguageInfo->new({
languageConstant =>
Google::Ads::GoogleAds::V17::Utils::ResourceNames::language_constant(
1000) # English
})})})});
return $operations;
}
# Creates multiple text assets and returns the list of resource names.
sub create_multiple_text_assets {
my ($api_client, $customer_id, $texts) = @_;
# Here again we use the GoogleAdService to create multiple text assets in a
# single request.
my $operations = [];
foreach my $text (@$texts) {
# Create a mutate operation for a text asset.
push @$operations,
Google::Ads::GoogleAds::V17::Services::GoogleAdsService::MutateOperation
->new({
assetOperation =>
Google::Ads::GoogleAds::V17::Services::AssetService::AssetOperation->
new({
create => Google::Ads::GoogleAds::V17::Resources::Asset->new({
textAsset =>
Google::Ads::GoogleAds::V17::Common::TextAsset->new({
text => $text
})})})});
}
# Issue a mutate request to add all assets.
my $mutate_google_ads_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 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_group_operations {
my (
$customer_id,
$headline_asset_resource_names,
$description_asset_resource_names
) = @_;
my $operations = [];
# Create a mutate operation that creates an asset group operation.
push @$operations,
Google::Ads::GoogleAds::V17::Services::GoogleAdsService::MutateOperation->
new({
assetGroupOperation =>
Google::Ads::GoogleAds::V17::Services::AssetGroupService::AssetGroupOperation
->new({
create => Google::Ads::GoogleAds::V17::Resources::AssetGroup->new({
resourceName =>
Google::Ads::GoogleAds::V17::Utils::ResourceNames::asset_group(
$customer_id, ASSET_GROUP_TEMPORARY_ID
),
name => "Performance Max asset group #" . uniqid(),
campaign =>
Google::Ads::GoogleAds::V17::Utils::ResourceNames::campaign(
$customer_id, PERFORMANCE_MAX_CAMPAIGN_TEMPORARY_ID
),
finalUrls => ["http://www.example.com"],
finalMobileUrls => ["http://www.example.com"],
status =>
Google::Ads::GoogleAds::V17::Enums::AssetGroupStatusEnum::PAUSED
})})});
# 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 text assets.
# Link the headline assets.
foreach my $resource_name (@$headline_asset_resource_names) {
push @$operations,
Google::Ads::GoogleAds::V17::Services::GoogleAdsService::MutateOperation
->new({
assetGroupAssetOperation =>
Google::Ads::GoogleAds::V17::Services::AssetGroupAssetService::AssetGroupAssetOperation
->new({
create =>
Google::Ads::GoogleAds::V17::Resources::AssetGroupAsset->new({
asset => $resource_name,
assetGroup =>
Google::Ads::GoogleAds::V17::Utils::ResourceNames::asset_group(
$customer_id, ASSET_GROUP_TEMPORARY_ID
),
fieldType => HEADLINE
})})});
}
# Link the description assets.
foreach my $resource_name (@$description_asset_resource_names) {
push @$operations,
Google::Ads::GoogleAds::V17::Services::GoogleAdsService::MutateOperation
->new({
assetGroupAssetOperation =>
Google::Ads::GoogleAds::V17::Services::AssetGroupAssetService::AssetGroupAssetOperation
->new({
create =>
Google::Ads::GoogleAds::V17::Resources::AssetGroupAsset->new({
asset => $resource_name,
assetGroup =>
Google::Ads::GoogleAds::V17::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 text asset.
push @$operations,
@{
create_and_link_text_asset($customer_id, "Interplanetary Cruises",
BUSINESS_NAME)};
# Create and link the image assets.
# Create and link the logo asset.
push @$operations,
@{
create_and_link_image_asset($customer_id, "https://gaagl.page.link/bjYi",
LOGO, "Marketing Logo")};
# 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"
)};
return $operations;
}
# Creates a list of MutateOperations that create a new linked text asset.
sub create_and_link_text_asset {
my ($customer_id, $text, $field_type) = @_;
my $operations = [];
# Create a new mutate operation for a text asset.
push @$operations,
Google::Ads::GoogleAds::V17::Services::GoogleAdsService::MutateOperation->
new({
assetOperation =>
Google::Ads::GoogleAds::V17::Services::AssetService::AssetOperation->
new({
create => Google::Ads::GoogleAds::V17::Resources::Asset->new({
resourceName =>
Google::Ads::GoogleAds::V17::Utils::ResourceNames::asset(
$customer_id, $next_temp_id
),
textAsset => Google::Ads::GoogleAds::V17::Common::TextAsset->new({
text => $text
})})})});
# Create an asset group asset to link the asset to the asset group.
push @$operations,
Google::Ads::GoogleAds::V17::Services::GoogleAdsService::MutateOperation->
new({
assetGroupAssetOperation =>
Google::Ads::GoogleAds::V17::Services::AssetGroupAssetService::AssetGroupAssetOperation
->new({
create =>
Google::Ads::GoogleAds::V17::Resources::AssetGroupAsset->new({
asset => Google::Ads::GoogleAds::V17::Utils::ResourceNames::asset(
$customer_id, $next_temp_id
),
assetGroup =>
Google::Ads::GoogleAds::V17::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 ($customer_id, $url, $field_type, $asset_name) = @_;
my $operations = [];
# Create a new mutate operation for an image asset.
push @$operations,
Google::Ads::GoogleAds::V17::Services::GoogleAdsService::MutateOperation->
new({
assetOperation =>
Google::Ads::GoogleAds::V17::Services::AssetService::AssetOperation->
new({
create => Google::Ads::GoogleAds::V17::Resources::Asset->new({
resourceName =>
Google::Ads::GoogleAds::V17::Utils::ResourceNames::asset(
$customer_id, $next_temp_id
),
# 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 => $asset_name,
imageAsset =>
Google::Ads::GoogleAds::V17::Common::ImageAsset->new({
data => get_base64_data_from_url($url)})})})});
# Create an asset group asset to link the asset to the asset group.
push @$operations,
Google::Ads::GoogleAds::V17::Services::GoogleAdsService::MutateOperation->
new({
assetGroupAssetOperation =>
Google::Ads::GoogleAds::V17::Services::AssetGroupAssetService::AssetGroupAssetOperation
->new({
create =>
Google::Ads::GoogleAds::V17::Resources::AssetGroupAsset->new({
asset => Google::Ads::GoogleAds::V17::Utils::ResourceNames::asset(
$customer_id, $next_temp_id
),
assetGroup =>
Google::Ads::GoogleAds::V17::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 asset group signals.
sub create_asset_group_signal_operations {
my ($customer_id, $audience_id) = @_;
my $operations = [];
return $operations if not defined $audience_id;
push @$operations,
Google::Ads::GoogleAds::V17::Services::GoogleAdsService::MutateOperation->
new({
assetGroupSignalOperation =>
Google::Ads::GoogleAds::V17::Services::AssetGroupSignalService::AssetGroupSignalOperation
->new({
# To learn more about Audience Signals, see:
# https://developers.google.com/google-ads/api/docs/performance-max/asset-groups#audience_signals
create =>
Google::Ads::GoogleAds::V17::Resources::AssetGroupSignal->new({
assetGroup =>
Google::Ads::GoogleAds::V17::Utils::ResourceNames::asset_group(
$customer_id, ASSET_GROUP_TEMPORARY_ID
),
audience =>
Google::Ads::GoogleAds::V17::Common::AudienceInfo->new({
audience =>
Google::Ads::GoogleAds::V17::Utils::ResourceNames::audience(
$customer_id, $audience_id
)})})})});
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.
sub print_response_details {
my ($mutate_google_ads_response) = @_;
foreach
my $response (@{$mutate_google_ads_response->{mutateOperationResponses}})
{
my $result_type = [keys %$response]->[0];
printf "Created a(n) %s with '%s'.\n",
ucfirst $result_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 any server returned fault.
$api_client->set_die_on_faults(1);
# Parameters passed on the command line will override any parameters set in code.
GetOptions(
"customer_id=s" => \$customer_id,
"audience_id=i" => \$audience_id
);
# Print the help message if the parameters are not initialized in the code nor
# in the command line.
pod2usage(2) if not check_params($customer_id);
# Call the example.
add_performance_max_campaign($api_client, $customer_id =~ s/-//gr,
$audience_id);
=pod
=head1 NAME
add_performance_max_campaign
=head1 DESCRIPTION
This example shows how to create a Performance Max campaign.
For more information about Performance Max campaigns, see
https://developers.google.com/google-ads/api/docs/performance-max/overview.
Prerequisites:
- 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.
This example uses the default customer conversion goals. For an example of
setting campaign-specific conversion goals, see
shopping_ads/add_performance_max_retail_campaign.pl.
=head1 SYNOPSIS
add_performance_max_campaign.pl [options]
-help Show the help message.
-customer_id The Google Ads customer ID.
-audience_id [optional] An audience ID to use to improve the
targeting of the Performance Max campaign.
=cut