Create experiment arms

Once you've created an experiment, you need to create multiple experiment arms in order to give the experiment more information about what exactly you're testing.

Experiment arms

The ExperimentArm represents one part of the comparison you're performing for the experiment. All experiments must always have exactly one control arm . This arm is an existing campaign that forms the basis against which you compare the other arm.

The other arms are called treatment arms, and in these arms you make changes to the campaign before beginning the experiment.

The ExperimentArm also contains the traffic_split setting. This lets you specify the percentage of traffic that is directed to each arm of the experiment. Each arm must specify a traffic split, and the sum of traffic split values in all arms must add up to 100.

Because of this traffic split restriction, all experiment arms must be created in the same request.

Code example

Java

 private 
  
 String 
  
 createExperimentArms 
 ( 
  
 GoogleAdsClient 
  
 googleAdsClient 
 , 
  
 long 
  
 customerId 
 , 
  
 long 
  
 campaignId 
 , 
  
 String 
  
 experiment 
 ) 
  
 { 
  
 List<ExperimentArmOperation> 
  
 operations 
  
 = 
  
 new 
  
 ArrayList 
<> (); 
  
 operations 
 . 
 add 
 ( 
  
 ExperimentArmOperation 
 . 
 newBuilder 
 () 
  
 . 
 setCreate 
 ( 
  
 // The "control" arm references an already-existing campaign. 
  
 ExperimentArm 
 . 
 newBuilder 
 () 
  
 . 
 setControl 
 ( 
 true 
 ) 
  
 . 
 addCampaigns 
 ( 
 ResourceNames 
 . 
 campaign 
 ( 
 customerId 
 , 
  
 campaignId 
 )) 
  
 . 
 setExperiment 
 ( 
 experiment 
 ) 
  
 . 
 setName 
 ( 
 "control arm" 
 ) 
  
 . 
 setTrafficSplit 
 ( 
 40 
 ) 
  
 . 
 build 
 ()) 
  
 . 
 build 
 ()); 
  
 operations 
 . 
 add 
 ( 
  
 ExperimentArmOperation 
 . 
 newBuilder 
 () 
  
 . 
 setCreate 
 ( 
  
 // The non-"control" arm, also called a "treatment" arm, will automatically 
  
 // generate draft campaigns that you can modify before starting the experiment. 
  
 ExperimentArm 
 . 
 newBuilder 
 () 
  
 . 
 setControl 
 ( 
 false 
 ) 
  
 . 
 setExperiment 
 ( 
 experiment 
 ) 
  
 . 
 setName 
 ( 
 "experiment arm" 
 ) 
  
 . 
 setTrafficSplit 
 ( 
 60 
 ) 
  
 . 
 build 
 ()) 
  
 . 
 build 
 ()); 
  
 try 
  
 ( 
 ExperimentArmServiceClient 
  
 experimentArmServiceClient 
  
 = 
  
 googleAdsClient 
 . 
 getLatestVersion 
 (). 
 createExperimentArmServiceClient 
 ()) 
  
 { 
  
 // Constructs the mutate request. 
  
 MutateExperimentArmsRequest 
  
 mutateRequest 
  
 = 
  
 MutateExperimentArmsRequest 
 . 
 newBuilder 
 () 
  
 . 
 setCustomerId 
 ( 
 Long 
 . 
 toString 
 ( 
 customerId 
 )) 
  
 . 
 addAllOperations 
 ( 
 operations 
 ) 
  
 // We want to fetch the draft campaign IDs from the treatment arm, so the easiest way to do 
  
 // that is to have the response return the newly created entities. 
  
 . 
 setResponseContentType 
 ( 
 ResponseContentType 
 . 
 MUTABLE_RESOURCE 
 ) 
  
 . 
 build 
 (); 
  
 // Sends the mutate request. 
  
 MutateExperimentArmsResponse 
  
 response 
  
 = 
  
 experimentArmServiceClient 
 . 
 mutateExperimentArms 
 ( 
 mutateRequest 
 ); 
  
 // Results always return in the order that you specify them in the request. Since we created 
  
 // the treatment arm last, it will be the last result.  If you don't remember which arm is the 
  
 // treatment arm, you can always filter the query in the next section with 
  
 // `experiment_arm.control = false`. 
  
 MutateExperimentArmResult 
  
 controlArmResult 
  
 = 
  
 response 
 . 
 getResults 
 ( 
 0 
 ); 
  
 MutateExperimentArmResult 
  
 treatmentArmResult 
  
 = 
  
 response 
 . 
 getResults 
 ( 
  
 response 
 . 
 getResultsCount 
 () 
  
 - 
  
 1 
 ); 
  
 System 
 . 
 out 
 . 
 printf 
 ( 
 "Created control arm with resource name '%s'%n" 
 , 
  
 controlArmResult 
 . 
 getResourceName 
 ()); 
  
 System 
 . 
 out 
 . 
 printf 
 ( 
 "Created treatment arm with resource name '%s'%n" 
 , 
  
 treatmentArmResult 
 . 
 getResourceName 
 ()); 
  
 return 
  
 treatmentArmResult 
 . 
 getExperimentArm 
 (). 
 getInDesignCampaigns 
 ( 
 0 
 ); 
  
 } 
 } 
  
  

C#

 /// <summary> 
 /// Creates the experiment arms. 
 /// </summary> 
 /// <param name="client">The Google Ads client.</param> 
 /// <param name="customerId">The customer ID for which the call is made.</param> 
 /// <param name="baseCampaignId">ID of the campaign for which the control arm is 
 /// created.</param> 
 /// <param name="experimentResourceName">Resource name of the experiment.</param> 
 /// <returns>The control and treatment arms.</returns> 
 private 
  
 static 
  
 ( 
 MutateExperimentArmResult 
 , 
  
 MutateExperimentArmResult 
 ) 
  
 CreateExperimentArms 
 ( 
 GoogleAdsClient 
  
 client 
 , 
  
 long 
  
 customerId 
 , 
  
 long 
  
 baseCampaignId 
 , 
  
 string 
  
 experimentResourceName 
 ) 
 { 
  
 // Get the ExperimentArmService. 
  
 ExperimentArmServiceClient 
  
 experimentService 
  
 = 
  
 client 
 . 
 GetService 
 ( 
  
 Services 
 . 
 V21 
 . 
 ExperimentArmService 
 ); 
  
 // Create the control arm. The control arm references an already-existing campaign. 
  
 ExperimentArmOperation 
  
 controlArmOperation 
  
 = 
  
 new 
  
 ExperimentArmOperation 
 () 
  
 { 
  
 Create 
  
 = 
  
 new 
  
 ExperimentArm 
 () 
  
 { 
  
 Control 
  
 = 
  
 true 
 , 
  
 Campaigns 
  
 = 
  
 { 
  
 ResourceNames 
 . 
 Campaign 
 ( 
 customerId 
 , 
  
 baseCampaignId 
 ) 
  
 }, 
  
 Experiment 
  
 = 
  
 experimentResourceName 
 , 
  
 Name 
  
 = 
  
 "Control Arm" 
 , 
  
 TrafficSplit 
  
 = 
  
 40 
  
 } 
  
 }; 
  
 // Create the non-control arm. The non-"control" arm, also called a "treatment" arm, 
  
 // will automatically generate draft campaigns that you can modify before starting the 
  
 // experiment. 
  
 ExperimentArmOperation 
  
 treatmentArmOperation 
  
 = 
  
 new 
  
 ExperimentArmOperation 
 () 
  
 { 
  
 Create 
  
 = 
  
 new 
  
 ExperimentArm 
 () 
  
 { 
  
 Control 
  
 = 
  
 false 
 , 
  
 Experiment 
  
 = 
  
 experimentResourceName 
 , 
  
 Name 
  
 = 
  
 "Experiment Arm" 
 , 
  
 TrafficSplit 
  
 = 
  
 60 
  
 } 
  
 }; 
  
 // We want to fetch the draft campaign IDs from the treatment arm, so the 
  
 // easiest way to do that is to have the response return the newly created 
  
 // entities. 
  
 MutateExperimentArmsRequest 
  
 request 
  
 = 
  
 new 
  
 MutateExperimentArmsRequest 
  
 { 
  
 CustomerId 
  
 = 
  
 customerId 
 . 
 ToString 
 (), 
  
 Operations 
  
 = 
  
 { 
  
 controlArmOperation 
 , 
  
 treatmentArmOperation 
  
 }, 
  
 ResponseContentType 
  
 = 
  
 ResponseContentType 
 . 
 MutableResource 
  
 }; 
  
 MutateExperimentArmsResponse 
  
 response 
  
 = 
  
 experimentService 
 . 
 MutateExperimentArms 
 ( 
  
 request 
  
 ); 
  
 // Results always return in the order that you specify them in the request. 
  
 // Since we created the treatment arm last, it will be the last result. 
  
 MutateExperimentArmResult 
  
 controlArm 
  
 = 
  
 response 
 . 
 Results 
 . 
 First 
 (); 
  
 MutateExperimentArmResult 
  
 treatmentArm 
  
 = 
  
 response 
 . 
 Results 
 . 
 Last 
 (); 
  
 Console 
 . 
 WriteLine 
 ( 
 $"Created control arm with resource name " 
  
 + 
  
 $"'{controlArm.ResourceName}." 
 ); 
  
 Console 
 . 
 WriteLine 
 ( 
 $"Created treatment arm with resource name" 
  
 + 
  
 $" '{treatmentArm.ResourceName}'." 
 ); 
  
 return 
  
 ( 
 controlArm 
 , 
  
 treatmentArm 
 ); 
 } 
  
  

PHP

 private static function createExperimentArms( 
 GoogleAdsClient $googleAdsClient, 
 int $customerId, 
 int $campaignId, 
 string $experimentResourceName 
 ): string { 
 $operations = []; 
 $experimentArm1 = new ExperimentArm([ 
 // The "control" arm references an already-existing campaign. 
 'control' => true, 
 'campaigns' => [ResourceNames::forCampaign($customerId, $campaignId)], 
 'experiment' => $experimentResourceName, 
 'name' => 'control arm', 
 'traffic_split' => 40 
 ]); 
 $operations[] = new ExperimentArmOperation(['create' => $experimentArm1]); 
 $experimentArm2 = new ExperimentArm([ 
 // The non-"control" arm, also called a "treatment" arm, will automatically 
 // generate draft campaigns that you can modify before starting the 
 // experiment. 
 'control' => false, 
 'experiment' => $experimentResourceName, 
 'name' => 'experiment arm', 
 'traffic_split' => 60 
 ]); 
 $operations[] = new ExperimentArmOperation(['create' => $experimentArm2]); 
 // Issues a request to create the experiment arms. 
 $experimentArmServiceClient = $googleAdsClient->getExperimentArmServiceClient(); 
 $response = $experimentArmServiceClient->mutateExperimentArms( 
 MutateExperimentArmsRequest::build($customerId, $operations) 
 // We want to fetch the draft campaign IDs from the treatment arm, so the easiest 
 // way to do that is to have the response return the newly created entities. 
 ->setResponseContentType(ResponseContentType::MUTABLE_RESOURCE) 
 ); 
 // Results always return in the order that you specify them in the request. 
 // Since we created the treatment arm last, it will be the last result. 
 $controlArmResourceName = $response->getResults()[0]->getResourceName(); 
 $treatmentArm = $response->getResults()[count($operations) - 1]; 
 print "Created control arm with resource name '$controlArmResourceName'" . PHP_EOL; 
 print "Created treatment arm with resource name '{$treatmentArm->getResourceName()}'" 
 . PHP_EOL; 
 return $treatmentArm->getExperimentArm()->getInDesignCampaigns()[0]; 
 }  
 

Python

 def 
  
 create_experiment_arms 
 ( 
 client 
 : 
 GoogleAdsClient 
 , 
 customer_id 
 : 
 str 
 , 
 base_campaign_id 
 : 
 str 
 , 
 experiment 
 : 
 str 
 , 
 ) 
 - 
> str 
 : 
  
 """Creates a control and treatment experiment arms. 
 Args: 
 client: an initialized GoogleAdsClient instance. 
 customer_id: a client customer ID. 
 base_campaign_id: the campaign ID to associate with the control arm of 
 the experiment. 
 experiment: the resource name for an experiment. 
 Returns: 
 the resource name for the new treatment experiment arm. 
 """ 
 operations 
 : 
 List 
 [ 
 ExperimentArmOperation 
 ] 
 = 
 [] 
 campaign_service 
 : 
 CampaignServiceClient 
 = 
 client 
 . 
 get_service 
 ( 
 "CampaignService" 
 ) 
 # The "control" arm references an already-existing campaign. 
 operation_1 
 : 
 ExperimentArmOperation 
 = 
 client 
 . 
 get_type 
 ( 
 "ExperimentArmOperation" 
 ) 
 exa_1 
 : 
 ExperimentArm 
 = 
 operation_1 
 . 
 create 
 exa_1 
 . 
 control 
 = 
 True 
 exa_1 
 . 
 campaigns 
 . 
 append 
 ( 
 campaign_service 
 . 
 campaign_path 
 ( 
 customer_id 
 , 
 base_campaign_id 
 ) 
 ) 
 exa_1 
 . 
 experiment 
 = 
 experiment 
 exa_1 
 . 
 name 
 = 
 "control arm" 
 exa_1 
 . 
 traffic_split 
 = 
 40 
 operations 
 . 
 append 
 ( 
 operation_1 
 ) 
 # The non-"control" arm, also called a "treatment" arm, will automatically 
 # generate draft campaigns that you can modify before starting the 
 # experiment. 
 operation_2 
 : 
 ExperimentArmOperation 
 = 
 client 
 . 
 get_type 
 ( 
 "ExperimentArmOperation" 
 ) 
 exa_2 
 : 
 ExperimentArm 
 = 
 operation_2 
 . 
 create 
 exa_2 
 . 
 control 
 = 
 False 
 exa_2 
 . 
 experiment 
 = 
 experiment 
 exa_2 
 . 
 name 
 = 
 "experiment arm" 
 exa_2 
 . 
 traffic_split 
 = 
 60 
 operations 
 . 
 append 
 ( 
 operation_2 
 ) 
 experiment_arm_service 
 : 
 ExperimentArmServiceClient 
 = 
 client 
 . 
 get_service 
 ( 
 "ExperimentArmService" 
 ) 
 request 
 : 
 MutateExperimentArmsRequest 
 = 
 client 
 . 
 get_type 
 ( 
 "MutateExperimentArmsRequest" 
 ) 
 request 
 . 
 customer_id 
 = 
 customer_id 
 request 
 . 
 operations 
 = 
 operations 
 # We want to fetch the draft campaign 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 
 ) 
 response 
 : 
 MutateExperimentArmsResponse 
 = 
 ( 
 experiment_arm_service 
 . 
 mutate_experiment_arms 
 ( 
 request 
 = 
 request 
 ) 
 ) 
 # Results always return in the order that you specify them in the request. 
 # Since we created the treatment arm second, it will be the second result. 
 control_arm_result 
 : 
 Any 
 = 
 response 
 . 
 results 
 [ 
 0 
 ] 
 treatment_arm_result 
 : 
 Any 
 = 
 response 
 . 
 results 
 [ 
 1 
 ] 
 print 
 ( 
 f 
 "Created control arm with resource name 
 { 
 control_arm_result 
 . 
 resource_name 
 } 
 " 
 ) 
 print 
 ( 
 f 
 "Created treatment arm with resource name 
 { 
 treatment_arm_result 
 . 
 resource_name 
 } 
 " 
 ) 
 return 
 treatment_arm_result 
 . 
 experiment_arm 
 . 
 in_design_campaigns 
 [ 
 0 
 ] 
  

Ruby

 def 
  
 create_experiment_arms 
 ( 
 client 
 , 
  
 customer_id 
 , 
  
 base_campaign_id 
 , 
  
 experiment 
 ) 
  
 operations 
  
 = 
  
 [] 
  
 operations 
 << 
 client 
 . 
 operation 
 . 
 create_resource 
 . 
 experiment_arm 
  
 do 
  
 | 
 ea 
 | 
  
 # The "control" arm references an already-existing campaign. 
  
 ea 
 . 
 control 
  
 = 
  
 true 
  
 ea 
 . 
 campaigns 
 << 
 client 
 . 
 path 
 . 
 campaign 
 ( 
 customer_id 
 , 
  
 base_campaign_id 
 ) 
  
 ea 
 . 
 experiment 
  
 = 
  
 experiment 
  
 ea 
 . 
 name 
  
 = 
  
 'control arm' 
  
 ea 
 . 
 traffic_split 
  
 = 
  
 40 
  
 end 
  
 operations 
 << 
 client 
 . 
 operation 
 . 
 create_resource 
 . 
 experiment_arm 
  
 do 
  
 | 
 ea 
 | 
  
 # The non-"control" arm, also called a "treatment" arm, will automatically 
  
 # generate draft campaigns that you can modify before starting the 
  
 # experiment. 
  
 ea 
 . 
 control 
  
 = 
  
 false 
  
 ea 
 . 
 experiment 
  
 = 
  
 experiment 
  
 ea 
 . 
 name 
  
 = 
  
 'experiment arm' 
  
 ea 
 . 
 traffic_split 
  
 = 
  
 60 
  
 end 
  
 response 
  
 = 
  
 client 
 . 
 service 
 . 
 experiment_arm 
 . 
 mutate_experiment_arms 
 ( 
  
 customer_id 
 : 
  
 customer_id 
 , 
  
 operations 
 : 
  
 operations 
 , 
  
 # We want to fetch the draft campaign IDs from the treatment arm, so the 
  
 # easiest way to do that is to have the response return the newly created 
  
 # entities. 
  
 response_content_type 
 : 
  
 :MUTABLE_RESOURCE 
 , 
  
 ) 
  
 # Results always return in the order that you specify them in the request. 
  
 # Since we created the treatment arm last, it will be the last result. 
  
 control_arm_result 
  
 = 
  
 response 
 . 
 results 
 . 
 first 
  
 treatment_arm_result 
  
 = 
  
 response 
 . 
 results 
 . 
 last 
  
 puts 
  
 "Created control arm with resource name 
 #{ 
 control_arm_result 
 . 
 resource_name 
 } 
 ." 
  
 puts 
  
 "Created treatment arm with resource name 
 #{ 
 treatment_arm_result 
 . 
 resource_name 
 } 
 ." 
  
 treatment_arm_result 
 . 
 experiment_arm 
 . 
 in_design_campaigns 
 . 
 first 
 end  
 
 . 
 rb 
  

Perl

 sub 
  
 create_experiment_arms 
  
 { 
  
 my 
  
 ( 
 $api_client 
 , 
  
 $customer_id 
 , 
  
 $base_campaign_id 
 , 
  
 $experiment 
 ) 
  
 = 
  
 @_ 
 ; 
  
 my 
  
 $operations 
  
 = 
  
 [] 
 ; 
  
 push 
  
 @$operations 
 , 
  
 Google::Ads::GoogleAds::V21::Services::ExperimentArmService:: 
 ExperimentArmOperation 
  
 - 
> new 
 ({ 
  
 create 
  
 = 
>  
 Google::Ads::GoogleAds::V21::Resources:: 
 ExperimentArm 
 - 
> new 
 ({ 
  
 # The "control" arm references an already-existing campaign. 
  
 control 
  
 = 
>  
 "true" 
 , 
  
 campaigns 
  
 = 
>  
 [ 
  
 Google::Ads::GoogleAds::V21::Utils::ResourceNames:: 
 campaign 
 ( 
  
 $customer_id 
 , 
  
 $base_campaign_id 
  
 ) 
  
 ], 
  
 experiment 
  
 = 
>  
 $experiment 
 , 
  
 name 
  
 = 
>  
 "control arm" 
 , 
  
 trafficSplit 
  
 = 
>  
 40 
  
 })}); 
  
 push 
  
 @$operations 
 , 
  
 Google::Ads::GoogleAds::V21::Services::ExperimentArmService:: 
 ExperimentArmOperation 
  
 - 
> new 
 ({ 
  
 create 
  
 = 
>  
 Google::Ads::GoogleAds::V21::Resources:: 
 ExperimentArm 
 - 
> new 
 ({ 
  
 # The non-"control" arm, also called a "treatment" arm, will automatically 
  
 # generate draft campaigns that you can modify before starting the 
  
 # experiment. 
  
 control 
  
 = 
>  
 "false" 
 , 
  
 experiment 
  
 = 
>  
 $experiment 
 , 
  
 name 
  
 = 
>  
 "experiment arm" 
 , 
  
 trafficSplit 
  
 = 
>  
 60 
  
 })}); 
  
 my 
  
 $response 
  
 = 
  
 $api_client 
 - 
> ExperimentArmService 
 () 
 - 
> mutate 
 ({ 
  
 customerId 
  
 = 
>  
 $customer_id 
 , 
  
 operations 
  
 = 
>  
 $operations 
 , 
  
 # We want to fetch the draft campaign IDs from the treatment arm, so the 
  
 # easiest way to do that is to have the response return the newly created 
  
 # entities. 
  
 responseContentType 
  
 = 
>  
 MUTABLE_RESOURCE 
  
 }); 
  
 # Results always return in the order that you specify them in the request. 
  
 # Since we created the treatment arm last, it will be the last result. 
  
 my 
  
 $control_arm_result 
  
 = 
  
 $response 
 - 
> { 
 results 
 }[ 
 0 
 ]; 
  
 my 
  
 $treatment_arm_result 
  
 = 
  
 $response 
 - 
> { 
 results 
 }[ 
 1 
 ]; 
  
 printf 
  
 "Created control arm with resource name '%s'.\n" 
 , 
  
 $control_arm_result 
 - 
> { 
 resourceName 
 }; 
  
 printf 
  
 "Created treatment arm with resource name '%s'.\n" 
 , 
  
 $treatment_arm_result 
 - 
> { 
 resourceName 
 }; 
  
 return 
  
 $treatment_arm_result 
 - 
> { 
 experimentArm 
 }{ 
 inDesignCampaigns 
 }[ 
 0 
 ]; 
 } 
  
  

A few key points about the example above:

  • The name of each arm must be unique within the Experiment .
  • The traffic_split must add up to 100 across all arms.
  • Exactly one arm must have control set to true ; all other arms must have it set to false .

    Only the control arm specifies a campaigns array, which holds only one campaign.

Treatment arms

Once you've created all the experiment arms, the treatment arms—the arms where control is set to false —automatically populate their in_design_campaigns field. You can retrieve the field from the API response by setting the response content type to MUTABLE_RESOURCE like in the code example. You can also fetch it through a GoogleAdsService query:

  SELECT 
  
 experiment_arm 
 . 
 in_design_campaigns 
 FROM 
  
 experiment_arm 
 WHERE 
  
 experiment_arm 
 . 
 resource_name 
  
 = 
  
 "TREATMENT_ARM_RESOURCE_NAME" 
 

In-design campaigns

You can treat these in-design campaigns as regular campaigns. Make whatever changes you want to test in your experiment to these campaigns; the control campaign won't be affected. Once you schedule the experiment, these changes are materialized into a real campaign that can serve ads.

These in-design campaigns are technically draft campaigns. If you want to find them in GoogleAdsService , add the include_drafts=true parameter to the query.

At least one change must be made to the in-design campaign before you can schedule the experiment.

Design a Mobile Site
View Site in Mobile | Classic
Share by: