Skip to content

Commit 9dc7ebd

Browse files
Add asset optimization experiment example (#889)
* Add asset optimization experiment example * Address nit
1 parent 66311fb commit 9dc7ebd

1 file changed

Lines changed: 322 additions & 0 deletions

File tree

Lines changed: 322 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,322 @@
1+
// Copyright 2026 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.ads.googleads.examples.experiments;
16+
17+
import com.beust.jcommander.Parameter;
18+
import com.google.ads.googleads.examples.utils.ArgumentNames;
19+
import com.google.ads.googleads.examples.utils.CodeSampleParams;
20+
import com.google.ads.googleads.lib.GoogleAdsClient;
21+
import com.google.ads.googleads.v24.common.ImageAsset;
22+
import com.google.ads.googleads.v24.common.TextAsset;
23+
import com.google.ads.googleads.v24.enums.AssetFieldTypeEnum.AssetFieldType;
24+
import com.google.ads.googleads.v24.enums.AssetLinkStatusEnum.AssetLinkStatus;
25+
import com.google.ads.googleads.v24.enums.AssetTypeEnum.AssetType;
26+
import com.google.ads.googleads.v24.enums.ExperimentTypeEnum.ExperimentType;
27+
import com.google.ads.googleads.v24.enums.OptimizeAssetsExperimentSubtypeEnum.OptimizeAssetsExperimentSubtype;
28+
import com.google.ads.googleads.v24.errors.GoogleAdsError;
29+
import com.google.ads.googleads.v24.errors.GoogleAdsException;
30+
import com.google.ads.googleads.v24.resources.Asset;
31+
import com.google.ads.googleads.v24.resources.AssetGroupAsset;
32+
import com.google.ads.googleads.v24.resources.Experiment;
33+
import com.google.ads.googleads.v24.common.OptimizeAssetsExperimentInfo;
34+
import com.google.ads.googleads.v24.resources.ExperimentArm;
35+
import com.google.ads.googleads.v24.resources.ExperimentArm.AssetGroupAssetInfo;
36+
import com.google.ads.googleads.v24.resources.ExperimentArm.AssetGroupInfo;
37+
import com.google.ads.googleads.v24.services.AssetGroupAssetOperation;
38+
import com.google.ads.googleads.v24.services.AssetOperation;
39+
import com.google.ads.googleads.v24.services.ExperimentArmOperation;
40+
import com.google.ads.googleads.v24.services.ExperimentOperation;
41+
import com.google.ads.googleads.v24.services.GoogleAdsRow;
42+
import com.google.ads.googleads.v24.services.GoogleAdsServiceClient;
43+
import com.google.ads.googleads.v24.services.GoogleAdsServiceClient.SearchPagedResponse;
44+
import com.google.ads.googleads.v24.services.MutateGoogleAdsRequest;
45+
import com.google.ads.googleads.v24.services.MutateGoogleAdsResponse;
46+
import com.google.ads.googleads.v24.services.MutateOperation;
47+
import com.google.ads.googleads.v24.services.SearchGoogleAdsRequest;
48+
import com.google.ads.googleads.v24.utils.ResourceNames;
49+
import com.google.common.collect.ImmutableList;
50+
import com.google.common.io.ByteStreams;
51+
import com.google.protobuf.ByteString;
52+
import java.io.FileNotFoundException;
53+
import java.io.IOException;
54+
import java.net.URL;
55+
import java.util.UUID;
56+
57+
/**
58+
* Creates an OPTIMIZE_ASSETS experiment.
59+
*
60+
* <p>Asset optimization experiments are used to test different asset combinations within
61+
* Performance Max campaigns.
62+
*/
63+
public class CreateAssetOptimizationExperiment {
64+
65+
private static final String IMAGE_URL = "https://gaagl.page.link/Eit5";
66+
67+
private static class CreateAssetOptimizationExperimentParams extends CodeSampleParams {
68+
69+
@Parameter(names = ArgumentNames.CUSTOMER_ID, required = true)
70+
private Long customerId;
71+
72+
@Parameter(names = ArgumentNames.ASSET_GROUP_ID, required = true)
73+
private Long assetGroupId;
74+
}
75+
76+
public static void main(String[] args) throws IOException {
77+
CreateAssetOptimizationExperimentParams params = new CreateAssetOptimizationExperimentParams();
78+
if (!params.parseArguments(args)) {
79+
throw new IllegalArgumentException("Invalid or missing command line arguments");
80+
}
81+
82+
GoogleAdsClient googleAdsClient = null;
83+
try {
84+
googleAdsClient = GoogleAdsClient.newBuilder().fromPropertiesFile().build();
85+
} catch (FileNotFoundException fnfe) {
86+
System.err.printf(
87+
"Failed to load GoogleAdsClient configuration from file. Exception: %s%n", fnfe);
88+
System.exit(1);
89+
} catch (IOException ioe) {
90+
System.err.printf("Failed to create GoogleAdsClient. Exception: %s%n", ioe);
91+
System.exit(1);
92+
}
93+
94+
try {
95+
new CreateAssetOptimizationExperiment()
96+
.runExample(googleAdsClient, params.customerId, params.assetGroupId);
97+
} catch (GoogleAdsException gae) {
98+
System.err.printf(
99+
"Request ID %s failed due to GoogleAdsException. Underlying errors:%n",
100+
gae.getRequestId());
101+
int i = 0;
102+
for (GoogleAdsError googleAdsError : gae.getGoogleAdsFailure().getErrorsList()) {
103+
System.err.printf(" Error %d: %s%n", i++, googleAdsError);
104+
}
105+
System.exit(1);
106+
}
107+
}
108+
109+
/**
110+
* Runs the example.
111+
*
112+
* @param googleAdsClient the googleAdsClient.
113+
* @param customerId the customer ID.
114+
* @param assetGroupId the base asset group ID to run the experiment on.
115+
*/
116+
private void runExample(GoogleAdsClient googleAdsClient, long customerId, long assetGroupId)
117+
throws IOException {
118+
119+
try (GoogleAdsServiceClient googleAdsServiceClient =
120+
googleAdsClient.getLatestVersion().createGoogleAdsServiceClient()) {
121+
122+
String campaignResourceName = null;
123+
124+
// Query the asset group to find the associated campaign resource name.
125+
String query =
126+
String.format(
127+
"SELECT asset_group.campaign FROM asset_group WHERE asset_group.id = %d",
128+
assetGroupId);
129+
130+
SearchGoogleAdsRequest request =
131+
SearchGoogleAdsRequest.newBuilder()
132+
.setCustomerId(Long.toString(customerId))
133+
.setQuery(query)
134+
.build();
135+
136+
SearchPagedResponse searchResponse = googleAdsServiceClient.search(request);
137+
138+
for (GoogleAdsRow row : searchResponse.iterateAll()) {
139+
campaignResourceName = row.getAssetGroup().getCampaign();
140+
break;
141+
}
142+
143+
if (campaignResourceName == null || campaignResourceName.isEmpty()) {
144+
System.err.printf("Asset group with ID %d not found.%n", assetGroupId);
145+
System.exit(1);
146+
}
147+
148+
// Temp IDs
149+
String asset1TempId = ResourceNames.asset(customerId, -1L);
150+
String experimentTempId = ResourceNames.experiment(customerId, -2L);
151+
String asset2TempId = ResourceNames.asset(customerId, -3L);
152+
153+
String assetGroupResourceName = ResourceNames.assetGroup(customerId, assetGroupId);
154+
155+
// [START create_asset_optimization_experiment_1]
156+
// 1. Create Assets with temporary resource names.
157+
// We create a text asset and an image asset to showcase different types.
158+
Asset textAsset =
159+
Asset.newBuilder()
160+
.setResourceName(asset1TempId)
161+
.setTextAsset(TextAsset.newBuilder().setText("Fly to Mars!").build())
162+
.build();
163+
164+
MutateOperation textAssetOperation =
165+
MutateOperation.newBuilder()
166+
.setAssetOperation(AssetOperation.newBuilder().setCreate(textAsset).build())
167+
.build();
168+
169+
byte[] imageData = ByteStreams.toByteArray(new URL(IMAGE_URL).openStream());
170+
Asset imageAsset =
171+
Asset.newBuilder()
172+
.setResourceName(asset2TempId)
173+
.setName("Mars Landscape View")
174+
.setType(AssetType.IMAGE)
175+
.setImageAsset(
176+
ImageAsset.newBuilder().setData(ByteString.copyFrom(imageData)).build())
177+
.build();
178+
179+
MutateOperation imageAssetOperation =
180+
MutateOperation.newBuilder()
181+
.setAssetOperation(AssetOperation.newBuilder().setCreate(imageAsset).build())
182+
.build();
183+
184+
// 2. Create an Experiment with a temporary resource name.
185+
Experiment experiment =
186+
Experiment.newBuilder()
187+
.setResourceName(experimentTempId)
188+
.setName("Interstellar Asset Experiment #" + UUID.randomUUID())
189+
.setType(ExperimentType.OPTIMIZE_ASSETS)
190+
// Set the optimize assets experiment subtype to COMPARE_ASSETS.
191+
.setOptimizeAssetsExperiment(
192+
OptimizeAssetsExperimentInfo.newBuilder()
193+
.setOptimizeAssetsExperimentSubtype(
194+
OptimizeAssetsExperimentSubtype.COMPARE_ASSETS)
195+
.build())
196+
.build();
197+
198+
MutateOperation experimentOperation =
199+
MutateOperation.newBuilder()
200+
.setExperimentOperation(ExperimentOperation.newBuilder().setCreate(experiment).build())
201+
.build();
202+
203+
// 3. Create two ExperimentArm resources.
204+
// Control arm
205+
ExperimentArm controlArm =
206+
ExperimentArm.newBuilder()
207+
.setExperiment(experimentTempId)
208+
.setName("Base Assets (Control)")
209+
.setControl(true)
210+
.setTrafficSplit(50)
211+
.addCampaigns(campaignResourceName)
212+
.addAssetGroups(
213+
AssetGroupInfo.newBuilder().setAssetGroup(assetGroupResourceName).build())
214+
.build();
215+
216+
MutateOperation controlArmOperation =
217+
MutateOperation.newBuilder()
218+
.setExperimentArmOperation(
219+
ExperimentArmOperation.newBuilder().setCreate(controlArm).build())
220+
.build();
221+
222+
// Treatment arm
223+
ExperimentArm treatmentArm =
224+
ExperimentArm.newBuilder()
225+
.setExperiment(experimentTempId)
226+
.setName("New Assets (Treatment)")
227+
.setControl(false)
228+
.setTrafficSplit(50)
229+
.addCampaigns(campaignResourceName)
230+
.addAssetGroups(
231+
AssetGroupInfo.newBuilder()
232+
.setAssetGroup(assetGroupResourceName)
233+
.addAssetGroupAssets(
234+
AssetGroupAssetInfo.newBuilder()
235+
.setAsset(asset1TempId)
236+
.setFieldType(AssetFieldType.HEADLINE)
237+
.build())
238+
.addAssetGroupAssets(
239+
AssetGroupAssetInfo.newBuilder()
240+
.setAsset(asset2TempId)
241+
.setFieldType(AssetFieldType.MARKETING_IMAGE)
242+
.build())
243+
.build())
244+
.build();
245+
246+
MutateOperation treatmentArmOperation =
247+
MutateOperation.newBuilder()
248+
.setExperimentArmOperation(
249+
ExperimentArmOperation.newBuilder().setCreate(treatmentArm).build())
250+
.build();
251+
252+
// 4. Create AssetGroupAssets linking the assets to the asset group.
253+
AssetGroupAsset assetGroupAsset1 =
254+
AssetGroupAsset.newBuilder()
255+
.setAssetGroup(assetGroupResourceName)
256+
.setAsset(asset1TempId)
257+
.setFieldType(AssetFieldType.HEADLINE)
258+
.setStatus(AssetLinkStatus.PAUSED)
259+
.build();
260+
261+
MutateOperation assetGroupAssetOperation1 =
262+
MutateOperation.newBuilder()
263+
.setAssetGroupAssetOperation(
264+
AssetGroupAssetOperation.newBuilder().setCreate(assetGroupAsset1).build())
265+
.build();
266+
267+
AssetGroupAsset assetGroupAsset2 =
268+
AssetGroupAsset.newBuilder()
269+
.setAssetGroup(assetGroupResourceName)
270+
.setAsset(asset2TempId)
271+
.setFieldType(AssetFieldType.MARKETING_IMAGE)
272+
.setStatus(AssetLinkStatus.PAUSED)
273+
.build();
274+
275+
MutateOperation assetGroupAssetOperation2 =
276+
MutateOperation.newBuilder()
277+
.setAssetGroupAssetOperation(
278+
AssetGroupAssetOperation.newBuilder().setCreate(assetGroupAsset2).build())
279+
.build();
280+
281+
// Send all operations in a single Mutate request.
282+
// The operations must be in this specific order.
283+
MutateGoogleAdsRequest mutateRequest =
284+
MutateGoogleAdsRequest.newBuilder()
285+
.setCustomerId(Long.toString(customerId))
286+
.addMutateOperations(textAssetOperation)
287+
.addMutateOperations(imageAssetOperation)
288+
.addMutateOperations(experimentOperation)
289+
.addMutateOperations(assetGroupAssetOperation1)
290+
.addMutateOperations(assetGroupAssetOperation2)
291+
.addMutateOperations(controlArmOperation)
292+
.addMutateOperations(treatmentArmOperation)
293+
.build();
294+
295+
MutateGoogleAdsResponse response = googleAdsServiceClient.mutate(mutateRequest);
296+
// [END create_asset_optimization_experiment_1]
297+
298+
// Print the results.
299+
System.out.printf(
300+
"Created headline asset: %s%n",
301+
response.getMutateOperationResponses(0).getAssetResult().getResourceName());
302+
System.out.printf(
303+
"Created image asset: %s%n",
304+
response.getMutateOperationResponses(1).getAssetResult().getResourceName());
305+
System.out.printf(
306+
"Created experiment: %s%n",
307+
response.getMutateOperationResponses(2).getExperimentResult().getResourceName());
308+
System.out.printf(
309+
"Created asset group asset for headline: %s%n",
310+
response.getMutateOperationResponses(3).getAssetGroupAssetResult().getResourceName());
311+
System.out.printf(
312+
"Created asset group asset for image: %s%n",
313+
response.getMutateOperationResponses(4).getAssetGroupAssetResult().getResourceName());
314+
System.out.printf(
315+
"Created control arm: %s%n",
316+
response.getMutateOperationResponses(5).getExperimentArmResult().getResourceName());
317+
System.out.printf(
318+
"Created treatment arm: %s%n",
319+
response.getMutateOperationResponses(6).getExperimentArmResult().getResourceName());
320+
}
321+
}
322+
}

0 commit comments

Comments
 (0)