2525from examples .utils .example_helpers import get_image_bytes_from_url
2626from google .ads .googleads .client import GoogleAdsClient
2727from google .ads .googleads .errors import GoogleAdsException
28+ from google .ads .googleads .v24 .services .types .experiment_service import (
29+ ExperimentOperation ,
30+ MutateExperimentsResponse ,
31+ )
32+ from google .ads .googleads .v24 .services .types .experiment_arm_service import (
33+ ExperimentArmOperation ,
34+ MutateExperimentArmsRequest ,
35+ MutateExperimentArmsResponse ,
36+ )
37+ from google .ads .googleads .v24 .resources .types .experiment import Experiment
38+ from google .ads .googleads .v24 .resources .types .experiment_arm import (
39+ ExperimentArm ,
40+ )
41+ from google .ads .googleads .v24 .services .services .experiment_service import (
42+ ExperimentServiceClient ,
43+ )
44+ from google .ads .googleads .v24 .services .services .experiment_arm_service import (
45+ ExperimentArmServiceClient ,
46+ )
2847from google .ads .googleads .v24 .services .types .google_ads_service import (
2948 MutateOperation ,
3049)
@@ -42,14 +61,32 @@ def main(
4261 """
4362 googleads_service = client .get_service ("GoogleAdsService" )
4463
45- # Temp IDs
64+ # Query the asset group to find the associated campaign resource name.
65+ query = f"""
66+ SELECT asset_group.campaign
67+ FROM asset_group
68+ WHERE asset_group.id = { asset_group_id }
69+ """
70+ search_response = googleads_service .search (
71+ customer_id = customer_id , query = query
72+ )
73+ campaign_resource_name = None
74+ for row in search_response :
75+ campaign_resource_name = row .asset_group .campaign
76+ break
77+
78+ if not campaign_resource_name :
79+ print (f"Asset group with ID { asset_group_id } not found." )
80+ sys .exit (1 )
81+
82+ # Temp IDs for asset creation
4683 ASSET_1_TEMP_ID = "-1"
47- EXPERIMENT_TEMP_ID = "-2"
48- ASSET_2_TEMP_ID = "-3"
84+ ASSET_2_TEMP_ID = "-2"
4985
5086 # [START create_asset_optimization_experiment_1]
51- # 1. Create Assets with temporary resource names .
87+ # 1. Create Assets.
5288 # We create a text asset and an image asset to showcase different types.
89+ # We execute the asset creation first to get real resource names.
5390 asset_operation_1 = create_text_asset_operation (
5491 client ,
5592 customer_id ,
@@ -64,93 +101,114 @@ def main(
64101 "Mars Landscape View" ,
65102 )
66103
67- # 2. Create an Experiment with a temporary resource name.
68- experiment_operation = client .get_type ("MutateOperation" )
69- experiment = experiment_operation .experiment_operation .create
70- experiment .resource_name = googleads_service .experiment_path (
71- customer_id , EXPERIMENT_TEMP_ID
104+ asset_response = googleads_service .mutate (
105+ customer_id = customer_id ,
106+ mutate_operations = [asset_operation_1 , asset_operation_2 ],
107+ )
108+ headline_asset_resource_name = (
109+ asset_response .mutate_operation_responses [0 ].asset_result .resource_name
110+ )
111+ image_asset_resource_name = (
112+ asset_response .mutate_operation_responses [1 ].asset_result .resource_name
113+ )
114+
115+ # 2. Create an Experiment using ExperimentService.
116+ experiment_operation : ExperimentOperation = client .get_type (
117+ "ExperimentOperation"
72118 )
119+ experiment : Experiment = experiment_operation .create
73120 experiment .name = f"Interstellar Asset Experiment #{ uuid4 ()} "
74121 experiment .type_ = client .enums .ExperimentTypeEnum .OPTIMIZE_ASSETS
75122 # Set the optimize assets experiment subtype to COMPARE_ASSETS.
76123 experiment .optimize_assets_experiment .optimize_assets_experiment_subtype = (
77124 client .enums .OptimizeAssetsExperimentSubtypeEnum .COMPARE_ASSETS
78125 )
79126
80- # 3. Create two ExperimentArm resources.
127+ experiment_service : ExperimentServiceClient = client .get_service (
128+ "ExperimentService"
129+ )
130+ experiment_response : MutateExperimentsResponse = (
131+ experiment_service .mutate_experiments (
132+ customer_id = customer_id , operations = [experiment_operation ]
133+ )
134+ )
135+ experiment_resource_name : str = (
136+ experiment_response .results [0 ].resource_name
137+ )
138+
139+ # 3. Create two ExperimentArm resources using ExperimentArmService.
81140 treatment_assets = [
82- (ASSET_1_TEMP_ID , client .enums .AssetFieldTypeEnum .HEADLINE ),
83- (ASSET_2_TEMP_ID , client .enums .AssetFieldTypeEnum .MARKETING_IMAGE ),
141+ (headline_asset_resource_name , client .enums .AssetFieldTypeEnum .HEADLINE ),
142+ (image_asset_resource_name , client .enums .AssetFieldTypeEnum .MARKETING_IMAGE ),
84143 ]
85144 arm_operations = create_arms_operations (
86145 client ,
87146 customer_id ,
88- EXPERIMENT_TEMP_ID ,
147+ experiment_resource_name ,
148+ campaign_resource_name ,
89149 asset_group_id ,
90150 treatment_assets ,
91151 )
92152
93- # 4. Create AssetGroupAssets linking the assets to the asset group.
153+ experiment_arm_service : ExperimentArmServiceClient = client .get_service (
154+ "ExperimentArmService"
155+ )
156+ request : MutateExperimentArmsRequest = client .get_type (
157+ "MutateExperimentArmsRequest"
158+ )
159+ request .customer_id = customer_id
160+ request .operations = arm_operations
161+ # We want to fetch the generated asset group IDs from the treatment arm, so the
162+ # easiest way to do that is to have the response return the newly created entities.
163+ request .response_content_type = (
164+ client .enums .ResponseContentTypeEnum .MUTABLE_RESOURCE
165+ )
166+ arm_response : MutateExperimentArmsResponse = (
167+ experiment_arm_service .mutate_experiment_arms (request = request )
168+ )
169+
170+ control_arm_result = arm_response .results [0 ]
171+ treatment_arm_result = arm_response .results [1 ]
172+ treatment_asset_group_resource_name = (
173+ treatment_arm_result .experiment_arm .asset_groups [0 ].asset_group
174+ )
175+
176+ # 4. Create AssetGroupAssets linking the assets to the treatment experiment arm's asset group.
94177 asset_group_asset_operation_1 = create_asset_group_asset_operation (
95178 client ,
96- customer_id ,
97- asset_group_id ,
98- ASSET_1_TEMP_ID ,
179+ treatment_asset_group_resource_name ,
180+ headline_asset_resource_name ,
99181 client .enums .AssetFieldTypeEnum .HEADLINE ,
100182 )
101183 asset_group_asset_operation_2 = create_asset_group_asset_operation (
102184 client ,
103- customer_id ,
104- asset_group_id ,
105- ASSET_2_TEMP_ID ,
185+ treatment_asset_group_resource_name ,
186+ image_asset_resource_name ,
106187 client .enums .AssetFieldTypeEnum .MARKETING_IMAGE ,
107188 )
108189
109- # Send all operations in a single Mutate request.
110- # The operations must be in this specific order.
111- mutate_operations = [
112- asset_operation_1 ,
113- asset_operation_2 ,
114- experiment_operation ,
115- * arm_operations ,
116- asset_group_asset_operation_1 ,
117- asset_group_asset_operation_2 ,
118- ]
119-
120- response = googleads_service .mutate (
190+ aga_response = googleads_service .mutate (
121191 customer_id = customer_id ,
122- mutate_operations = mutate_operations ,
192+ mutate_operations = [
193+ asset_group_asset_operation_1 ,
194+ asset_group_asset_operation_2 ,
195+ ],
123196 )
124197 # [END create_asset_optimization_experiment_1]
125198
126199 # Print the results.
127- print (
128- "Created headline asset:"
129- f" { response .mutate_operation_responses [0 ].asset_result .resource_name } "
130- )
131- print (
132- "Created image asset:"
133- f" { response .mutate_operation_responses [1 ].asset_result .resource_name } "
134- )
135- print (
136- "Created experiment:"
137- f" { response .mutate_operation_responses [2 ].experiment_result .resource_name } "
138- )
139- print (
140- "Created control arm:"
141- f" { response .mutate_operation_responses [3 ].experiment_arm_result .resource_name } "
142- )
143- print (
144- "Created treatment arm:"
145- f" { response .mutate_operation_responses [4 ].experiment_arm_result .resource_name } "
146- )
200+ print (f"Created headline asset: { headline_asset_resource_name } " )
201+ print (f"Created image asset: { image_asset_resource_name } " )
202+ print (f"Created experiment: { experiment_resource_name } " )
203+ print (f"Created control arm: { control_arm_result .resource_name } " )
204+ print (f"Created treatment arm: { treatment_arm_result .resource_name } " )
147205 print (
148206 "Created asset group asset for headline:"
149- f" { response .mutate_operation_responses [5 ].asset_group_asset_result .resource_name } "
207+ f" { aga_response .mutate_operation_responses [0 ].asset_group_asset_result .resource_name } "
150208 )
151209 print (
152210 "Created asset group asset for image:"
153- f" { response .mutate_operation_responses [6 ].asset_group_asset_result .resource_name } "
211+ f" { aga_response .mutate_operation_responses [1 ].asset_group_asset_result .resource_name } "
154212 )
155213
156214
@@ -187,24 +245,26 @@ def create_image_asset_operation(
187245def create_arms_operations (
188246 client : GoogleAdsClient ,
189247 customer_id : str ,
190- experiment_temp_id : str ,
248+ experiment_resource_name : str ,
249+ campaign_resource_name : str ,
191250 asset_group_id : str ,
192251 treatment_assets : List [Tuple [str , Any ]],
193- ) -> List [MutateOperation ]:
252+ ) -> List [ExperimentArmOperation ]:
194253 """Creates mutate operations for control and treatment arms."""
195254 googleads_service = client .get_service ("GoogleAdsService" )
196255 experiment_arm_type = client .get_type ("ExperimentArm" )
197- operations = []
256+ operations : List [ ExperimentArmOperation ] = []
198257
199258 # Control arm
200- control_operation = client .get_type ("MutateOperation" )
201- control = control_operation .experiment_arm_operation .create
202- control .experiment = googleads_service .experiment_path (
203- customer_id , experiment_temp_id
259+ control_operation : ExperimentArmOperation = client .get_type (
260+ "ExperimentArmOperation"
204261 )
262+ control : ExperimentArm = control_operation .create
263+ control .experiment = experiment_resource_name
205264 control .name = "Base Assets (Control)"
206265 control .control = True
207266 control .traffic_split = 50
267+ control .campaigns .append (campaign_resource_name )
208268
209269 asset_group_info_control = experiment_arm_type .AssetGroupInfo ()
210270 asset_group_info_control .asset_group = googleads_service .asset_group_path (
@@ -214,25 +274,25 @@ def create_arms_operations(
214274 operations .append (control_operation )
215275
216276 # Treatment arm
217- treatment_operation = client .get_type ("MutateOperation" )
218- treatment = treatment_operation .experiment_arm_operation .create
219- treatment .experiment = googleads_service .experiment_path (
220- customer_id , experiment_temp_id
277+ treatment_operation : ExperimentArmOperation = client .get_type (
278+ "ExperimentArmOperation"
221279 )
280+ treatment : ExperimentArm = treatment_operation .create
281+ treatment .experiment = experiment_resource_name
222282 treatment .name = "New Assets (Treatment)"
223283 treatment .control = False
224284 treatment .traffic_split = 50
285+ # NOTE: Do not set treatment.campaigns, as the backend automatically creates
286+ # the treatment campaign for Performance Max / OPTIMIZE_ASSETS experiments.
225287
226288 asset_group_info_treatment = experiment_arm_type .AssetGroupInfo ()
227289 asset_group_info_treatment .asset_group = googleads_service .asset_group_path (
228290 customer_id , asset_group_id
229291 )
230292
231- for asset_temp_id , field_type in treatment_assets :
293+ for asset_resource_name , field_type in treatment_assets :
232294 asset_group_asset_info = experiment_arm_type .AssetGroupAssetInfo ()
233- asset_group_asset_info .asset = googleads_service .asset_path (
234- customer_id , asset_temp_id
235- )
295+ asset_group_asset_info .asset = asset_resource_name
236296 asset_group_asset_info .field_type = field_type
237297 asset_group_info_treatment .asset_group_assets .append (
238298 asset_group_asset_info
@@ -246,19 +306,15 @@ def create_arms_operations(
246306
247307def create_asset_group_asset_operation (
248308 client : GoogleAdsClient ,
249- customer_id : str ,
250- asset_group_id : str ,
251- asset_temp_id : str ,
309+ asset_group_resource_name : str ,
310+ asset_resource_name : str ,
252311 field_type : Any ,
253312) -> MutateOperation :
254313 """Creates a mutate operation for an asset group asset."""
255- googleads_service = client .get_service ("GoogleAdsService" )
256314 operation = client .get_type ("MutateOperation" )
257315 aga = operation .asset_group_asset_operation .create
258- aga .asset_group = googleads_service .asset_group_path (
259- customer_id , asset_group_id
260- )
261- aga .asset = googleads_service .asset_path (customer_id , asset_temp_id )
316+ aga .asset_group = asset_group_resource_name
317+ aga .asset = asset_resource_name
262318 aga .field_type = field_type
263319 return operation
264320
0 commit comments