From 8ba1f425ce0b7d697f0eb1ff82b15cd9d1521224 Mon Sep 17 00:00:00 2001 From: Laura Chevalier Date: Wed, 13 May 2026 22:05:47 +0000 Subject: [PATCH 1/6] Update experiments examples per required usage flows. Change-Id: Ifba0c463bfc763cc2a9032fc800720c67f304261 --- examples/experiments/create_asset_optimization_experiment.py | 1 - examples/experiments/create_search_adopt_ai_max_experiment.py | 1 - 2 files changed, 2 deletions(-) diff --git a/examples/experiments/create_asset_optimization_experiment.py b/examples/experiments/create_asset_optimization_experiment.py index e94d872bc..7ee6a8113 100644 --- a/examples/experiments/create_asset_optimization_experiment.py +++ b/examples/experiments/create_asset_optimization_experiment.py @@ -76,7 +76,6 @@ def main( experiment.optimize_assets_experiment.optimize_assets_experiment_subtype = ( client.enums.OptimizeAssetsExperimentSubtypeEnum.COMPARE_ASSETS ) - experiment.status = client.enums.ExperimentStatusEnum.SETUP # 3. Create two ExperimentArm resources. treatment_assets = [ diff --git a/examples/experiments/create_search_adopt_ai_max_experiment.py b/examples/experiments/create_search_adopt_ai_max_experiment.py index ef1aee19d..2e842a447 100644 --- a/examples/experiments/create_search_adopt_ai_max_experiment.py +++ b/examples/experiments/create_search_adopt_ai_max_experiment.py @@ -49,7 +49,6 @@ def main(client: GoogleAdsClient, customer_id: str, campaign_id: str) -> None: experiment.resource_name = experiment_resource_name experiment.name = f"ADOPT_AI_MAX Experiment #{uuid4()}" experiment.type_ = client.enums.ExperimentTypeEnum.ADOPT_AI_MAX - experiment.status = client.enums.ExperimentStatusEnum.SETUP # Create the control arm. Both arms in an intra-campaign experiment # reference the same base campaign. From e26e566e60ed489e513b34b05447776f885e15f9 Mon Sep 17 00:00:00 2001 From: Laura Chevalier Date: Wed, 13 May 2026 22:25:25 +0000 Subject: [PATCH 2/6] Trying new things Change-Id: I78b5fceb7e6dfb88306d5521176e7ae55d6ddba9 --- .../create_asset_optimization_experiment.py | 212 +++++++++++------- 1 file changed, 134 insertions(+), 78 deletions(-) diff --git a/examples/experiments/create_asset_optimization_experiment.py b/examples/experiments/create_asset_optimization_experiment.py index 7ee6a8113..97bfd950d 100644 --- a/examples/experiments/create_asset_optimization_experiment.py +++ b/examples/experiments/create_asset_optimization_experiment.py @@ -25,6 +25,25 @@ from examples.utils.example_helpers import get_image_bytes_from_url from google.ads.googleads.client import GoogleAdsClient from google.ads.googleads.errors import GoogleAdsException +from google.ads.googleads.v24.services.types.experiment_service import ( + ExperimentOperation, + MutateExperimentsResponse, +) +from google.ads.googleads.v24.services.types.experiment_arm_service import ( + ExperimentArmOperation, + MutateExperimentArmsRequest, + MutateExperimentArmsResponse, +) +from google.ads.googleads.v24.resources.types.experiment import Experiment +from google.ads.googleads.v24.resources.types.experiment_arm import ( + ExperimentArm, +) +from google.ads.googleads.v24.services.services.experiment_service import ( + ExperimentServiceClient, +) +from google.ads.googleads.v24.services.services.experiment_arm_service import ( + ExperimentArmServiceClient, +) from google.ads.googleads.v24.services.types.google_ads_service import ( MutateOperation, ) @@ -42,14 +61,32 @@ def main( """ googleads_service = client.get_service("GoogleAdsService") - # Temp IDs + # Query the asset group to find the associated campaign resource name. + query = f""" + SELECT asset_group.campaign + FROM asset_group + WHERE asset_group.id = {asset_group_id} + """ + search_response = googleads_service.search( + customer_id=customer_id, query=query + ) + campaign_resource_name = None + for row in search_response: + campaign_resource_name = row.asset_group.campaign + break + + if not campaign_resource_name: + print(f"Asset group with ID {asset_group_id} not found.") + sys.exit(1) + + # Temp IDs for asset creation ASSET_1_TEMP_ID = "-1" - EXPERIMENT_TEMP_ID = "-2" - ASSET_2_TEMP_ID = "-3" + ASSET_2_TEMP_ID = "-2" # [START create_asset_optimization_experiment_1] - # 1. Create Assets with temporary resource names. + # 1. Create Assets. # We create a text asset and an image asset to showcase different types. + # We execute the asset creation first to get real resource names. asset_operation_1 = create_text_asset_operation( client, customer_id, @@ -64,12 +101,22 @@ def main( "Mars Landscape View", ) - # 2. Create an Experiment with a temporary resource name. - experiment_operation = client.get_type("MutateOperation") - experiment = experiment_operation.experiment_operation.create - experiment.resource_name = googleads_service.experiment_path( - customer_id, EXPERIMENT_TEMP_ID + asset_response = googleads_service.mutate( + customer_id=customer_id, + mutate_operations=[asset_operation_1, asset_operation_2], + ) + headline_asset_resource_name = ( + asset_response.mutate_operation_responses[0].asset_result.resource_name + ) + image_asset_resource_name = ( + asset_response.mutate_operation_responses[1].asset_result.resource_name + ) + + # 2. Create an Experiment using ExperimentService. + experiment_operation: ExperimentOperation = client.get_type( + "ExperimentOperation" ) + experiment: Experiment = experiment_operation.create experiment.name = f"Interstellar Asset Experiment #{uuid4()}" experiment.type_ = client.enums.ExperimentTypeEnum.OPTIMIZE_ASSETS # Set the optimize assets experiment subtype to COMPARE_ASSETS. @@ -77,80 +124,91 @@ def main( client.enums.OptimizeAssetsExperimentSubtypeEnum.COMPARE_ASSETS ) - # 3. Create two ExperimentArm resources. + experiment_service: ExperimentServiceClient = client.get_service( + "ExperimentService" + ) + experiment_response: MutateExperimentsResponse = ( + experiment_service.mutate_experiments( + customer_id=customer_id, operations=[experiment_operation] + ) + ) + experiment_resource_name: str = ( + experiment_response.results[0].resource_name + ) + + # 3. Create two ExperimentArm resources using ExperimentArmService. treatment_assets = [ - (ASSET_1_TEMP_ID, client.enums.AssetFieldTypeEnum.HEADLINE), - (ASSET_2_TEMP_ID, client.enums.AssetFieldTypeEnum.MARKETING_IMAGE), + (headline_asset_resource_name, client.enums.AssetFieldTypeEnum.HEADLINE), + (image_asset_resource_name, client.enums.AssetFieldTypeEnum.MARKETING_IMAGE), ] arm_operations = create_arms_operations( client, customer_id, - EXPERIMENT_TEMP_ID, + experiment_resource_name, + campaign_resource_name, asset_group_id, treatment_assets, ) - # 4. Create AssetGroupAssets linking the assets to the asset group. + experiment_arm_service: ExperimentArmServiceClient = client.get_service( + "ExperimentArmService" + ) + request: MutateExperimentArmsRequest = client.get_type( + "MutateExperimentArmsRequest" + ) + request.customer_id = customer_id + request.operations = arm_operations + # We want to fetch the generated asset group IDs from the treatment arm, so the + # easiest way to do that is to have the response return the newly created entities. + request.response_content_type = ( + client.enums.ResponseContentTypeEnum.MUTABLE_RESOURCE + ) + arm_response: MutateExperimentArmsResponse = ( + experiment_arm_service.mutate_experiment_arms(request=request) + ) + + control_arm_result = arm_response.results[0] + treatment_arm_result = arm_response.results[1] + treatment_asset_group_resource_name = ( + treatment_arm_result.experiment_arm.asset_groups[0].asset_group + ) + + # 4. Create AssetGroupAssets linking the assets to the treatment experiment arm's asset group. asset_group_asset_operation_1 = create_asset_group_asset_operation( client, - customer_id, - asset_group_id, - ASSET_1_TEMP_ID, + treatment_asset_group_resource_name, + headline_asset_resource_name, client.enums.AssetFieldTypeEnum.HEADLINE, ) asset_group_asset_operation_2 = create_asset_group_asset_operation( client, - customer_id, - asset_group_id, - ASSET_2_TEMP_ID, + treatment_asset_group_resource_name, + image_asset_resource_name, client.enums.AssetFieldTypeEnum.MARKETING_IMAGE, ) - # Send all operations in a single Mutate request. - # The operations must be in this specific order. - mutate_operations = [ - asset_operation_1, - asset_operation_2, - experiment_operation, - *arm_operations, - asset_group_asset_operation_1, - asset_group_asset_operation_2, - ] - - response = googleads_service.mutate( + aga_response = googleads_service.mutate( customer_id=customer_id, - mutate_operations=mutate_operations, + mutate_operations=[ + asset_group_asset_operation_1, + asset_group_asset_operation_2, + ], ) # [END create_asset_optimization_experiment_1] # Print the results. - print( - "Created headline asset:" - f" {response.mutate_operation_responses[0].asset_result.resource_name}" - ) - print( - "Created image asset:" - f" {response.mutate_operation_responses[1].asset_result.resource_name}" - ) - print( - "Created experiment:" - f" {response.mutate_operation_responses[2].experiment_result.resource_name}" - ) - print( - "Created control arm:" - f" {response.mutate_operation_responses[3].experiment_arm_result.resource_name}" - ) - print( - "Created treatment arm:" - f" {response.mutate_operation_responses[4].experiment_arm_result.resource_name}" - ) + print(f"Created headline asset: {headline_asset_resource_name}") + print(f"Created image asset: {image_asset_resource_name}") + print(f"Created experiment: {experiment_resource_name}") + print(f"Created control arm: {control_arm_result.resource_name}") + print(f"Created treatment arm: {treatment_arm_result.resource_name}") print( "Created asset group asset for headline:" - f" {response.mutate_operation_responses[5].asset_group_asset_result.resource_name}" + f" {aga_response.mutate_operation_responses[0].asset_group_asset_result.resource_name}" ) print( "Created asset group asset for image:" - f" {response.mutate_operation_responses[6].asset_group_asset_result.resource_name}" + f" {aga_response.mutate_operation_responses[1].asset_group_asset_result.resource_name}" ) @@ -187,24 +245,26 @@ def create_image_asset_operation( def create_arms_operations( client: GoogleAdsClient, customer_id: str, - experiment_temp_id: str, + experiment_resource_name: str, + campaign_resource_name: str, asset_group_id: str, treatment_assets: List[Tuple[str, Any]], -) -> List[MutateOperation]: +) -> List[ExperimentArmOperation]: """Creates mutate operations for control and treatment arms.""" googleads_service = client.get_service("GoogleAdsService") experiment_arm_type = client.get_type("ExperimentArm") - operations = [] + operations: List[ExperimentArmOperation] = [] # Control arm - control_operation = client.get_type("MutateOperation") - control = control_operation.experiment_arm_operation.create - control.experiment = googleads_service.experiment_path( - customer_id, experiment_temp_id + control_operation: ExperimentArmOperation = client.get_type( + "ExperimentArmOperation" ) + control: ExperimentArm = control_operation.create + control.experiment = experiment_resource_name control.name = "Base Assets (Control)" control.control = True control.traffic_split = 50 + control.campaigns.append(campaign_resource_name) asset_group_info_control = experiment_arm_type.AssetGroupInfo() asset_group_info_control.asset_group = googleads_service.asset_group_path( @@ -214,25 +274,25 @@ def create_arms_operations( operations.append(control_operation) # Treatment arm - treatment_operation = client.get_type("MutateOperation") - treatment = treatment_operation.experiment_arm_operation.create - treatment.experiment = googleads_service.experiment_path( - customer_id, experiment_temp_id + treatment_operation: ExperimentArmOperation = client.get_type( + "ExperimentArmOperation" ) + treatment: ExperimentArm = treatment_operation.create + treatment.experiment = experiment_resource_name treatment.name = "New Assets (Treatment)" treatment.control = False treatment.traffic_split = 50 + # NOTE: Do not set treatment.campaigns, as the backend automatically creates + # the treatment campaign for Performance Max / OPTIMIZE_ASSETS experiments. asset_group_info_treatment = experiment_arm_type.AssetGroupInfo() asset_group_info_treatment.asset_group = googleads_service.asset_group_path( customer_id, asset_group_id ) - for asset_temp_id, field_type in treatment_assets: + for asset_resource_name, field_type in treatment_assets: asset_group_asset_info = experiment_arm_type.AssetGroupAssetInfo() - asset_group_asset_info.asset = googleads_service.asset_path( - customer_id, asset_temp_id - ) + asset_group_asset_info.asset = asset_resource_name asset_group_asset_info.field_type = field_type asset_group_info_treatment.asset_group_assets.append( asset_group_asset_info @@ -246,19 +306,15 @@ def create_arms_operations( def create_asset_group_asset_operation( client: GoogleAdsClient, - customer_id: str, - asset_group_id: str, - asset_temp_id: str, + asset_group_resource_name: str, + asset_resource_name: str, field_type: Any, ) -> MutateOperation: """Creates a mutate operation for an asset group asset.""" - googleads_service = client.get_service("GoogleAdsService") operation = client.get_type("MutateOperation") aga = operation.asset_group_asset_operation.create - aga.asset_group = googleads_service.asset_group_path( - customer_id, asset_group_id - ) - aga.asset = googleads_service.asset_path(customer_id, asset_temp_id) + aga.asset_group = asset_group_resource_name + aga.asset = asset_resource_name aga.field_type = field_type return operation From 5cd2a016e34997f712ddc2fee87ad62b3e2344a4 Mon Sep 17 00:00:00 2001 From: Laura Chevalier Date: Wed, 13 May 2026 22:28:50 +0000 Subject: [PATCH 3/6] Add treatment campaign ID and shorten the asset text. Change-Id: I39ac87bcd26a9bbb346937a7f42e86668224b97d --- .../create_asset_optimization_experiment.py | 194 ++++++++---------- 1 file changed, 80 insertions(+), 114 deletions(-) diff --git a/examples/experiments/create_asset_optimization_experiment.py b/examples/experiments/create_asset_optimization_experiment.py index 97bfd950d..1c6427836 100644 --- a/examples/experiments/create_asset_optimization_experiment.py +++ b/examples/experiments/create_asset_optimization_experiment.py @@ -25,25 +25,6 @@ from examples.utils.example_helpers import get_image_bytes_from_url from google.ads.googleads.client import GoogleAdsClient from google.ads.googleads.errors import GoogleAdsException -from google.ads.googleads.v24.services.types.experiment_service import ( - ExperimentOperation, - MutateExperimentsResponse, -) -from google.ads.googleads.v24.services.types.experiment_arm_service import ( - ExperimentArmOperation, - MutateExperimentArmsRequest, - MutateExperimentArmsResponse, -) -from google.ads.googleads.v24.resources.types.experiment import Experiment -from google.ads.googleads.v24.resources.types.experiment_arm import ( - ExperimentArm, -) -from google.ads.googleads.v24.services.services.experiment_service import ( - ExperimentServiceClient, -) -from google.ads.googleads.v24.services.services.experiment_arm_service import ( - ExperimentArmServiceClient, -) from google.ads.googleads.v24.services.types.google_ads_service import ( MutateOperation, ) @@ -79,19 +60,19 @@ def main( print(f"Asset group with ID {asset_group_id} not found.") sys.exit(1) - # Temp IDs for asset creation + # Temp IDs ASSET_1_TEMP_ID = "-1" - ASSET_2_TEMP_ID = "-2" + EXPERIMENT_TEMP_ID = "-2" + ASSET_2_TEMP_ID = "-3" # [START create_asset_optimization_experiment_1] - # 1. Create Assets. + # 1. Create Assets with temporary resource names. # We create a text asset and an image asset to showcase different types. - # We execute the asset creation first to get real resource names. asset_operation_1 = create_text_asset_operation( client, customer_id, ASSET_1_TEMP_ID, - "Fly to Mars with Interplanetary Cruises!", + "Fly to Mars!", ) asset_operation_2 = create_image_asset_operation( client, @@ -101,22 +82,12 @@ def main( "Mars Landscape View", ) - asset_response = googleads_service.mutate( - customer_id=customer_id, - mutate_operations=[asset_operation_1, asset_operation_2], - ) - headline_asset_resource_name = ( - asset_response.mutate_operation_responses[0].asset_result.resource_name - ) - image_asset_resource_name = ( - asset_response.mutate_operation_responses[1].asset_result.resource_name - ) - - # 2. Create an Experiment using ExperimentService. - experiment_operation: ExperimentOperation = client.get_type( - "ExperimentOperation" + # 2. Create an Experiment with a temporary resource name. + experiment_operation = client.get_type("MutateOperation") + experiment = experiment_operation.experiment_operation.create + experiment.resource_name = googleads_service.experiment_path( + customer_id, EXPERIMENT_TEMP_ID ) - experiment: Experiment = experiment_operation.create experiment.name = f"Interstellar Asset Experiment #{uuid4()}" experiment.type_ = client.enums.ExperimentTypeEnum.OPTIMIZE_ASSETS # Set the optimize assets experiment subtype to COMPARE_ASSETS. @@ -124,91 +95,81 @@ def main( client.enums.OptimizeAssetsExperimentSubtypeEnum.COMPARE_ASSETS ) - experiment_service: ExperimentServiceClient = client.get_service( - "ExperimentService" - ) - experiment_response: MutateExperimentsResponse = ( - experiment_service.mutate_experiments( - customer_id=customer_id, operations=[experiment_operation] - ) - ) - experiment_resource_name: str = ( - experiment_response.results[0].resource_name - ) - - # 3. Create two ExperimentArm resources using ExperimentArmService. + # 3. Create two ExperimentArm resources. treatment_assets = [ - (headline_asset_resource_name, client.enums.AssetFieldTypeEnum.HEADLINE), - (image_asset_resource_name, client.enums.AssetFieldTypeEnum.MARKETING_IMAGE), + (ASSET_1_TEMP_ID, client.enums.AssetFieldTypeEnum.HEADLINE), + (ASSET_2_TEMP_ID, client.enums.AssetFieldTypeEnum.MARKETING_IMAGE), ] arm_operations = create_arms_operations( client, customer_id, - experiment_resource_name, + EXPERIMENT_TEMP_ID, campaign_resource_name, asset_group_id, treatment_assets, ) - experiment_arm_service: ExperimentArmServiceClient = client.get_service( - "ExperimentArmService" - ) - request: MutateExperimentArmsRequest = client.get_type( - "MutateExperimentArmsRequest" - ) - request.customer_id = customer_id - request.operations = arm_operations - # We want to fetch the generated asset group IDs from the treatment arm, so the - # easiest way to do that is to have the response return the newly created entities. - request.response_content_type = ( - client.enums.ResponseContentTypeEnum.MUTABLE_RESOURCE - ) - arm_response: MutateExperimentArmsResponse = ( - experiment_arm_service.mutate_experiment_arms(request=request) - ) - - control_arm_result = arm_response.results[0] - treatment_arm_result = arm_response.results[1] - treatment_asset_group_resource_name = ( - treatment_arm_result.experiment_arm.asset_groups[0].asset_group - ) - - # 4. Create AssetGroupAssets linking the assets to the treatment experiment arm's asset group. + # 4. Create AssetGroupAssets linking the assets to the asset group. asset_group_asset_operation_1 = create_asset_group_asset_operation( client, - treatment_asset_group_resource_name, - headline_asset_resource_name, + customer_id, + asset_group_id, + ASSET_1_TEMP_ID, client.enums.AssetFieldTypeEnum.HEADLINE, ) asset_group_asset_operation_2 = create_asset_group_asset_operation( client, - treatment_asset_group_resource_name, - image_asset_resource_name, + customer_id, + asset_group_id, + ASSET_2_TEMP_ID, client.enums.AssetFieldTypeEnum.MARKETING_IMAGE, ) - aga_response = googleads_service.mutate( + # Send all operations in a single Mutate request. + # The operations must be in this specific order. + mutate_operations = [ + asset_operation_1, + asset_operation_2, + experiment_operation, + *arm_operations, + asset_group_asset_operation_1, + asset_group_asset_operation_2, + ] + + response = googleads_service.mutate( customer_id=customer_id, - mutate_operations=[ - asset_group_asset_operation_1, - asset_group_asset_operation_2, - ], + mutate_operations=mutate_operations, ) # [END create_asset_optimization_experiment_1] # Print the results. - print(f"Created headline asset: {headline_asset_resource_name}") - print(f"Created image asset: {image_asset_resource_name}") - print(f"Created experiment: {experiment_resource_name}") - print(f"Created control arm: {control_arm_result.resource_name}") - print(f"Created treatment arm: {treatment_arm_result.resource_name}") + print( + "Created headline asset:" + f" {response.mutate_operation_responses[0].asset_result.resource_name}" + ) + print( + "Created image asset:" + f" {response.mutate_operation_responses[1].asset_result.resource_name}" + ) + print( + "Created experiment:" + f" {response.mutate_operation_responses[2].experiment_result.resource_name}" + ) + print( + "Created control arm:" + f" {response.mutate_operation_responses[3].experiment_arm_result.resource_name}" + ) + print( + "Created treatment arm:" + f" {response.mutate_operation_responses[4].experiment_arm_result.resource_name}" + ) print( "Created asset group asset for headline:" - f" {aga_response.mutate_operation_responses[0].asset_group_asset_result.resource_name}" + f" {response.mutate_operation_responses[5].asset_group_asset_result.resource_name}" ) print( "Created asset group asset for image:" - f" {aga_response.mutate_operation_responses[1].asset_group_asset_result.resource_name}" + f" {response.mutate_operation_responses[6].asset_group_asset_result.resource_name}" ) @@ -245,22 +206,22 @@ def create_image_asset_operation( def create_arms_operations( client: GoogleAdsClient, customer_id: str, - experiment_resource_name: str, + experiment_temp_id: str, campaign_resource_name: str, asset_group_id: str, treatment_assets: List[Tuple[str, Any]], -) -> List[ExperimentArmOperation]: +) -> List[MutateOperation]: """Creates mutate operations for control and treatment arms.""" googleads_service = client.get_service("GoogleAdsService") experiment_arm_type = client.get_type("ExperimentArm") - operations: List[ExperimentArmOperation] = [] + operations = [] # Control arm - control_operation: ExperimentArmOperation = client.get_type( - "ExperimentArmOperation" + control_operation = client.get_type("MutateOperation") + control = control_operation.experiment_arm_operation.create + control.experiment = googleads_service.experiment_path( + customer_id, experiment_temp_id ) - control: ExperimentArm = control_operation.create - control.experiment = experiment_resource_name control.name = "Base Assets (Control)" control.control = True control.traffic_split = 50 @@ -274,25 +235,26 @@ def create_arms_operations( operations.append(control_operation) # Treatment arm - treatment_operation: ExperimentArmOperation = client.get_type( - "ExperimentArmOperation" + treatment_operation = client.get_type("MutateOperation") + treatment = treatment_operation.experiment_arm_operation.create + treatment.experiment = googleads_service.experiment_path( + customer_id, experiment_temp_id ) - treatment: ExperimentArm = treatment_operation.create - treatment.experiment = experiment_resource_name treatment.name = "New Assets (Treatment)" treatment.control = False treatment.traffic_split = 50 - # NOTE: Do not set treatment.campaigns, as the backend automatically creates - # the treatment campaign for Performance Max / OPTIMIZE_ASSETS experiments. + treatment.campaigns.append(campaign_resource_name) asset_group_info_treatment = experiment_arm_type.AssetGroupInfo() asset_group_info_treatment.asset_group = googleads_service.asset_group_path( customer_id, asset_group_id ) - for asset_resource_name, field_type in treatment_assets: + for asset_temp_id, field_type in treatment_assets: asset_group_asset_info = experiment_arm_type.AssetGroupAssetInfo() - asset_group_asset_info.asset = asset_resource_name + asset_group_asset_info.asset = googleads_service.asset_path( + customer_id, asset_temp_id + ) asset_group_asset_info.field_type = field_type asset_group_info_treatment.asset_group_assets.append( asset_group_asset_info @@ -306,15 +268,19 @@ def create_arms_operations( def create_asset_group_asset_operation( client: GoogleAdsClient, - asset_group_resource_name: str, - asset_resource_name: str, + customer_id: str, + asset_group_id: str, + asset_temp_id: str, field_type: Any, ) -> MutateOperation: """Creates a mutate operation for an asset group asset.""" + googleads_service = client.get_service("GoogleAdsService") operation = client.get_type("MutateOperation") aga = operation.asset_group_asset_operation.create - aga.asset_group = asset_group_resource_name - aga.asset = asset_resource_name + aga.asset_group = googleads_service.asset_group_path( + customer_id, asset_group_id + ) + aga.asset = googleads_service.asset_path(customer_id, asset_temp_id) aga.field_type = field_type return operation From 1d9a4926827fe1506d54dda57b926ec36a103284 Mon Sep 17 00:00:00 2001 From: Laura Chevalier Date: Fri, 15 May 2026 14:12:01 +0000 Subject: [PATCH 4/6] Replace loop with indexing into response results Change-Id: Ie77ce2b6a874185ee4054c2605a31a3f9bd1f0b1 --- .../experiments/create_asset_optimization_experiment.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/examples/experiments/create_asset_optimization_experiment.py b/examples/experiments/create_asset_optimization_experiment.py index 1c6427836..1ab4dcb86 100644 --- a/examples/experiments/create_asset_optimization_experiment.py +++ b/examples/experiments/create_asset_optimization_experiment.py @@ -51,12 +51,9 @@ def main( search_response = googleads_service.search( customer_id=customer_id, query=query ) - campaign_resource_name = None - for row in search_response: - campaign_resource_name = row.asset_group.campaign - break - - if not campaign_resource_name: + if len(search_response): + campaign_resource_name = search_response[0].asset_group.campaign + else: print(f"Asset group with ID {asset_group_id} not found.") sys.exit(1) From 851e812d88836e9ab0d9d76d926ccd662ee90fd2 Mon Sep 17 00:00:00 2001 From: Laura Chevalier Date: Tue, 19 May 2026 20:28:12 +0000 Subject: [PATCH 5/6] Updating experiments examples Change-Id: I3ce0cbde3b22302127751849a7632ab337893665 --- .../create_asset_optimization_experiment.py | 9 ++-- .../experiments/get_experiment_performance.py | 53 ++++++++----------- 2 files changed, 29 insertions(+), 33 deletions(-) diff --git a/examples/experiments/create_asset_optimization_experiment.py b/examples/experiments/create_asset_optimization_experiment.py index 1ab4dcb86..1c6427836 100644 --- a/examples/experiments/create_asset_optimization_experiment.py +++ b/examples/experiments/create_asset_optimization_experiment.py @@ -51,9 +51,12 @@ def main( search_response = googleads_service.search( customer_id=customer_id, query=query ) - if len(search_response): - campaign_resource_name = search_response[0].asset_group.campaign - else: + campaign_resource_name = None + for row in search_response: + campaign_resource_name = row.asset_group.campaign + break + + if not campaign_resource_name: print(f"Asset group with ID {asset_group_id} not found.") sys.exit(1) diff --git a/examples/experiments/get_experiment_performance.py b/examples/experiments/get_experiment_performance.py index 08e9cdefc..765639ca4 100644 --- a/examples/experiments/get_experiment_performance.py +++ b/examples/experiments/get_experiment_performance.py @@ -14,7 +14,7 @@ # limitations under the License. """This example illustrates how to retrieve performance metrics for an experiment. -It shows how to query statistical significance metrics for the experiment arms, +It shows how to query statistical significance metrics for the experiment, and how to execute actions such as promoting, ending, or graduating an experiment. """ @@ -29,7 +29,8 @@ GoogleAdsServiceClient, ) from google.ads.googleads.v24.services.types.google_ads_service import ( - SearchGoogleAdsStreamResponse, + SearchGoogleAdsRequest, + SearchGoogleAdsResponse, GoogleAdsRow, ) from google.ads.googleads.v24.services.services.experiment_service import ( @@ -62,15 +63,13 @@ def main(client: GoogleAdsClient, customer_id: str, experiment_id: str) -> None: """ ga_service: GoogleAdsServiceClient = client.get_service("GoogleAdsService") - # Query to retrieve both control and treatment arms under the parent experiment. + # Query to retrieve the experiment. # Notice that we request the statistical metrics (e.g., p-value, point estimate, - # margin of error) which are populated exclusively on the treatment arm row. + # margin of error) which are populated based on the treatment arm. query = f""" SELECT - experiment_arm.resource_name, - experiment_arm.name, - experiment_arm.control, - experiment_arm.traffic_split, + experiment.resource_name, + experiment.name, experiment.resource_name, experiment.experiment_id, experiment.type, @@ -80,41 +79,35 @@ def main(client: GoogleAdsClient, customer_id: str, experiment_id: str) -> None: metrics.clicks_p_value, metrics.clicks_point_estimate, metrics.clicks_margin_of_error - FROM experiment_arm + FROM experiment WHERE experiment.experiment_id = {experiment_id} """ - # Issues a search request using streaming. - stream: Iterator[SearchGoogleAdsStreamResponse] = ga_service.search_stream( - customer_id=customer_id, query=query + # Issues a search request. + search_request: SearchGoogleAdsRequest = client.get_type( + "SearchGoogleAdsRequest" ) + search_request.customer_id = customer_id + search_request.query = query - has_results = False - for batch in stream: - rows: List[GoogleAdsRow] = batch.results - for row in rows: - has_results = True - print(f"Found experiment arm: {row.experiment_arm.name}") - print(f" Resource Name: {row.experiment_arm.resource_name}") - print(f" Control: {row.experiment_arm.control}") - print(f" Traffic Split: {row.experiment_arm.traffic_split}%") + results: SearchGoogleAdsResponse = ga_service.search(request=search_request) - # Statistical evaluation is only valid on the treatment (non-control) arm - # because significance metrics are only populated relative to the baseline. - # Note: For intra-campaign/in-campaign experiments, only a single treatment row is - # returned (with control = False), since there is no separate control campaign. - if not row.experiment_arm.control: - evaluate_experiment(client, customer_id, row) + row: GoogleAdsRow + # There should be at most one row. + for row in results: + print(f"Found experiment: {row.experiment.name}") + print(f" Resource Name: {row.experiment.resource_name}") - if not has_results: - print(f"No experiment arms found for experiment ID: {experiment_id}") + evaluate_experiment(client, customer_id, row) + else: + print(f"No experiment found for experiment ID: {experiment_id}") # [START get_experiment_performance_1] def evaluate_experiment( client: GoogleAdsClient, customer_id: str, row: GoogleAdsRow ) -> None: - """Evaluates the performance of the treatment experiment arm. + """Evaluates the performance of the experiment. Args: client: an initialized GoogleAdsClient instance. From 958bb009d1f38ade68ab3bd7f669e7e85eb4111b Mon Sep 17 00:00:00 2001 From: Laura Chevalier Date: Tue, 19 May 2026 20:58:53 +0000 Subject: [PATCH 6/6] properly handle no experiment found Change-Id: I0b55f50163ea1d99c133f7b5e925e027af52ef2e --- examples/experiments/get_experiment_performance.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/experiments/get_experiment_performance.py b/examples/experiments/get_experiment_performance.py index 765639ca4..22ebd8487 100644 --- a/examples/experiments/get_experiment_performance.py +++ b/examples/experiments/get_experiment_performance.py @@ -92,14 +92,16 @@ def main(client: GoogleAdsClient, customer_id: str, experiment_id: str) -> None: results: SearchGoogleAdsResponse = ga_service.search(request=search_request) + experiment_found = False row: GoogleAdsRow # There should be at most one row. for row in results: + experiment_found = True print(f"Found experiment: {row.experiment.name}") print(f" Resource Name: {row.experiment.resource_name}") evaluate_experiment(client, customer_id, row) - else: + if not experiment_found: print(f"No experiment found for experiment ID: {experiment_id}")