Skip to content

Commit 0d66ab6

Browse files
authored
Changes for release 24_1. (#1073)
1 parent 61b5680 commit 0d66ab6

1,692 files changed

Lines changed: 2089 additions & 406581 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

ChangeLog

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
* 31.0.0
2+
- Google Ads API v24_1 release.
3+
- Remove Google Ads API v20.
4+
- Update ansync example tests to remove unecessary mocking.
5+
16
* 30.1.0
27
- Google Ads API v24 release.
38
- Update examples to use Google Ads API v24.
Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
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+
"""This example shows how to create an OPTIMIZE_ASSETS experiment.
15+
16+
Asset optimization experiments are used to test different asset combinations
17+
within Performance Max campaigns.
18+
"""
19+
20+
import argparse
21+
import sys
22+
from typing import List, Tuple, Any
23+
from uuid import uuid4
24+
25+
from examples.utils.example_helpers import get_image_bytes_from_url
26+
from google.ads.googleads.client import GoogleAdsClient
27+
from google.ads.googleads.errors import GoogleAdsException
28+
from google.ads.googleads.v24.services.types.google_ads_service import (
29+
MutateOperation,
30+
)
31+
32+
33+
def main(
34+
client: GoogleAdsClient, customer_id: str, asset_group_id: str
35+
) -> None:
36+
"""Creates an OPTIMIZE_ASSETS experiment.
37+
38+
Args:
39+
client: An initialized GoogleAdsClient instance.
40+
customer_id: The Google Ads customer ID.
41+
asset_group_id: The base asset group ID to run the experiment on.
42+
"""
43+
googleads_service = client.get_service("GoogleAdsService")
44+
45+
# Temp IDs
46+
ASSET_1_TEMP_ID = "-1"
47+
EXPERIMENT_TEMP_ID = "-2"
48+
ASSET_2_TEMP_ID = "-3"
49+
50+
# [START create_asset_optimization_experiment_1]
51+
# 1. Create Assets with temporary resource names.
52+
# We create a text asset and an image asset to showcase different types.
53+
asset_operation_1 = create_text_asset_operation(
54+
client,
55+
customer_id,
56+
ASSET_1_TEMP_ID,
57+
"Fly to Mars with Interplanetary Cruises!",
58+
)
59+
asset_operation_2 = create_image_asset_operation(
60+
client,
61+
customer_id,
62+
ASSET_2_TEMP_ID,
63+
"https://gaagl.page.link/Eit5",
64+
"Mars Landscape View",
65+
)
66+
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
72+
)
73+
experiment.name = f"Interstellar Asset Experiment #{uuid4()}"
74+
experiment.type_ = client.enums.ExperimentTypeEnum.OPTIMIZE_ASSETS
75+
# Set the optimize assets experiment subtype to COMPARE_ASSETS.
76+
experiment.optimize_assets_experiment.optimize_assets_experiment_subtype = (
77+
client.enums.OptimizeAssetsExperimentSubtypeEnum.COMPARE_ASSETS
78+
)
79+
experiment.status = client.enums.ExperimentStatusEnum.SETUP
80+
81+
# 3. Create two ExperimentArm resources.
82+
treatment_assets = [
83+
(ASSET_1_TEMP_ID, client.enums.AssetFieldTypeEnum.HEADLINE),
84+
(ASSET_2_TEMP_ID, client.enums.AssetFieldTypeEnum.MARKETING_IMAGE),
85+
]
86+
arm_operations = create_arms_operations(
87+
client,
88+
customer_id,
89+
EXPERIMENT_TEMP_ID,
90+
asset_group_id,
91+
treatment_assets,
92+
)
93+
94+
# 4. Create AssetGroupAssets linking the assets to the asset group.
95+
asset_group_asset_operation_1 = create_asset_group_asset_operation(
96+
client,
97+
customer_id,
98+
asset_group_id,
99+
ASSET_1_TEMP_ID,
100+
client.enums.AssetFieldTypeEnum.HEADLINE,
101+
)
102+
asset_group_asset_operation_2 = create_asset_group_asset_operation(
103+
client,
104+
customer_id,
105+
asset_group_id,
106+
ASSET_2_TEMP_ID,
107+
client.enums.AssetFieldTypeEnum.MARKETING_IMAGE,
108+
)
109+
110+
# Send all operations in a single Mutate request.
111+
# The operations must be in this specific order.
112+
mutate_operations = [
113+
asset_operation_1,
114+
asset_operation_2,
115+
experiment_operation,
116+
*arm_operations,
117+
asset_group_asset_operation_1,
118+
asset_group_asset_operation_2,
119+
]
120+
121+
response = googleads_service.mutate(
122+
customer_id=customer_id,
123+
mutate_operations=mutate_operations,
124+
)
125+
# [END create_asset_optimization_experiment_1]
126+
127+
# Print the results.
128+
print(
129+
"Created headline asset:"
130+
f" {response.mutate_operation_responses[0].asset_result.resource_name}"
131+
)
132+
print(
133+
"Created image asset:"
134+
f" {response.mutate_operation_responses[1].asset_result.resource_name}"
135+
)
136+
print(
137+
"Created experiment:"
138+
f" {response.mutate_operation_responses[2].experiment_result.resource_name}"
139+
)
140+
print(
141+
"Created control arm:"
142+
f" {response.mutate_operation_responses[3].experiment_arm_result.resource_name}"
143+
)
144+
print(
145+
"Created treatment arm:"
146+
f" {response.mutate_operation_responses[4].experiment_arm_result.resource_name}"
147+
)
148+
print(
149+
"Created asset group asset for headline:"
150+
f" {response.mutate_operation_responses[5].asset_group_asset_result.resource_name}"
151+
)
152+
print(
153+
"Created asset group asset for image:"
154+
f" {response.mutate_operation_responses[6].asset_group_asset_result.resource_name}"
155+
)
156+
157+
158+
def create_text_asset_operation(
159+
client: GoogleAdsClient, customer_id: str, temp_id: str, text: str
160+
) -> MutateOperation:
161+
"""Creates a mutate operation for a text asset."""
162+
googleads_service = client.get_service("GoogleAdsService")
163+
operation = client.get_type("MutateOperation")
164+
asset = operation.asset_operation.create
165+
asset.resource_name = googleads_service.asset_path(customer_id, temp_id)
166+
asset.text_asset.text = text
167+
return operation
168+
169+
170+
def create_image_asset_operation(
171+
client: GoogleAdsClient,
172+
customer_id: str,
173+
temp_id: str,
174+
url: str,
175+
name: str,
176+
) -> MutateOperation:
177+
"""Creates a mutate operation for an image asset."""
178+
googleads_service = client.get_service("GoogleAdsService")
179+
operation = client.get_type("MutateOperation")
180+
asset = operation.asset_operation.create
181+
asset.resource_name = googleads_service.asset_path(customer_id, temp_id)
182+
asset.name = name
183+
asset.type_ = client.enums.AssetTypeEnum.IMAGE
184+
asset.image_asset.data = get_image_bytes_from_url(url)
185+
return operation
186+
187+
188+
def create_arms_operations(
189+
client: GoogleAdsClient,
190+
customer_id: str,
191+
experiment_temp_id: str,
192+
asset_group_id: str,
193+
treatment_assets: List[Tuple[str, Any]],
194+
) -> List[MutateOperation]:
195+
"""Creates mutate operations for control and treatment arms."""
196+
googleads_service = client.get_service("GoogleAdsService")
197+
experiment_arm_type = client.get_type("ExperimentArm")
198+
operations = []
199+
200+
# Control arm
201+
control_operation = client.get_type("MutateOperation")
202+
control = control_operation.experiment_arm_operation.create
203+
control.experiment = googleads_service.experiment_path(
204+
customer_id, experiment_temp_id
205+
)
206+
control.name = "Base Assets (Control)"
207+
control.control = True
208+
control.traffic_split = 50
209+
210+
asset_group_info_control = experiment_arm_type.AssetGroupInfo()
211+
asset_group_info_control.asset_group = googleads_service.asset_group_path(
212+
customer_id, asset_group_id
213+
)
214+
control.asset_groups.append(asset_group_info_control)
215+
operations.append(control_operation)
216+
217+
# Treatment arm
218+
treatment_operation = client.get_type("MutateOperation")
219+
treatment = treatment_operation.experiment_arm_operation.create
220+
treatment.experiment = googleads_service.experiment_path(
221+
customer_id, experiment_temp_id
222+
)
223+
treatment.name = "New Assets (Treatment)"
224+
treatment.control = False
225+
treatment.traffic_split = 50
226+
227+
asset_group_info_treatment = experiment_arm_type.AssetGroupInfo()
228+
asset_group_info_treatment.asset_group = googleads_service.asset_group_path(
229+
customer_id, asset_group_id
230+
)
231+
232+
for asset_temp_id, field_type in treatment_assets:
233+
asset_group_asset_info = experiment_arm_type.AssetGroupAssetInfo()
234+
asset_group_asset_info.asset = googleads_service.asset_path(
235+
customer_id, asset_temp_id
236+
)
237+
asset_group_asset_info.field_type = field_type
238+
asset_group_info_treatment.asset_group_assets.append(
239+
asset_group_asset_info
240+
)
241+
242+
treatment.asset_groups.append(asset_group_info_treatment)
243+
operations.append(treatment_operation)
244+
245+
return operations
246+
247+
248+
def create_asset_group_asset_operation(
249+
client: GoogleAdsClient,
250+
customer_id: str,
251+
asset_group_id: str,
252+
asset_temp_id: str,
253+
field_type: Any,
254+
) -> MutateOperation:
255+
"""Creates a mutate operation for an asset group asset."""
256+
googleads_service = client.get_service("GoogleAdsService")
257+
operation = client.get_type("MutateOperation")
258+
aga = operation.asset_group_asset_operation.create
259+
aga.asset_group = googleads_service.asset_group_path(
260+
customer_id, asset_group_id
261+
)
262+
aga.asset = googleads_service.asset_path(customer_id, asset_temp_id)
263+
aga.field_type = field_type
264+
return operation
265+
266+
267+
if __name__ == "__main__":
268+
parser = argparse.ArgumentParser(
269+
description="Creates an OPTIMIZE_ASSETS experiment."
270+
)
271+
parser.add_argument(
272+
"-c",
273+
"--customer_id",
274+
type=str,
275+
required=True,
276+
help="The Google Ads customer ID.",
277+
)
278+
parser.add_argument(
279+
"-a",
280+
"--asset_group_id",
281+
type=str,
282+
required=True,
283+
help="The base asset group ID to run the experiment on.",
284+
)
285+
args = parser.parse_args()
286+
287+
googleads_client = GoogleAdsClient.load_from_storage(version="v24")
288+
289+
try:
290+
main(googleads_client, args.customer_id, args.asset_group_id)
291+
except GoogleAdsException as ex:
292+
print(
293+
f'Request with ID "{ex.request_id}" failed with status '
294+
f'"{ex.error.code().name}" and includes the following errors:'
295+
)
296+
for error in ex.failure.errors:
297+
print(f'\tError with message "{error.message}".')
298+
if error.location:
299+
for field_path_element in error.location.field_path_elements:
300+
print(f"\t\tOn field: {field_path_element.field_name}")
301+
sys.exit(1)

0 commit comments

Comments
 (0)