Gli esperimenti gestiti dal sistema vengono utilizzati per eseguire test A/B sulle modifiche creando una o più campagne sperimentali modificabili che vengono pubblicate insieme a una campagna di controllo originale.
Questo workflow è supportato per i seguenti valori ExperimentType:
SEARCH_CUSTOM: un esperimento personalizzato composto da campagne sulla rete di ricerca.DISPLAY_CUSTOM: un esperimento personalizzato composto da campagne display.HOTEL_CUSTOM: un esperimento personalizzato composto da campagne per hotel.YOUTUBE_CUSTOM: un esperimento personalizzato composto da campagne video.PMAX_REPLACEMENT_SHOPPING: un esperimento per testare il rendimento delle tue campagne Shopping rispetto a Performance Max.
Configurazione
La configurazione degli esperimenti gestiti dal sistema prevede i seguenti passaggi:
- Crea un
Experiment. - Crea risorse
ExperimentArmper il controllo e il trattamento. - Modifica
in_design_campaignsnei gruppi sperimentali.
1. Crea un esperimento
Il primo passaggio per eseguire un esperimento utilizzando l'API Google Ads consiste nel creare un
Experiment. Questa risorsa definisce le informazioni chiave sull'esperimento che vuoi eseguire. In questo passaggio non specifichi nessuna delle campagne coinvolte nell'esperimento.
Ecco una panoramica di alcuni campi chiave per un Experiment:
name: ogni esperimento deve avere un nome univoco.description: un campo facoltativo che puoi utilizzare per un riferimento successivo. Non influisce sulla modalità di esecuzione dell'esperimento.suffix: il suffisso viene aggiunto alla fine dei nomi delle campagne sperimentali in modo da poterle distinguere dalla campagna di controllo. Questi concetti sono spiegati in modo più dettagliato nel passaggio 2.type: il tipo di esperimento da eseguire. Per gli esperimenti gestiti dal sistema, utilizzaSEARCH_CUSTOM,DISPLAY_CUSTOM,HOTEL_CUSTOM,YOUTUBE_CUSTOMoPMAX_REPLACEMENT_SHOPPING.status: quando crei un esperimento, imposta questo campo suSETUP. In seguito, una volta avviato l'esperimento, questo campo ti consente di controllare lo stato attuale.start_dateeend_date: specifica quando l'esperimento deve iniziare e terminare.sync_enabled: disattivato per impostazione predefinita. Se impostato sutrue, le modifiche apportate alla campagna originale durante l'esecuzione dell'esperimento vengono copiate automaticamente nella campagna sperimentale. Per saperne di più, consulta l'articolo sulla sincronizzazione delle campagne nel Centro assistenza Google Ads.
Java
private String createExperimentResource(GoogleAdsClient googleAdsClient, long customerId) { ExperimentOperation operation = ExperimentOperation.newBuilder() .setCreate( Experiment.newBuilder() // Name must be unique. .setName("Example Experiment #" + getPrintableDateTime()) // We specify SEARCH_CUSTOM to create a standard search campaign experiment. // This type uses a standard draft-based workflow where the system automatically // creates a draft/in-design campaign for the treatment arm. .setType(ExperimentType.SEARCH_CUSTOM) .setSuffix("[experiment]") .setStatus(ExperimentStatus.SETUP) .build()) .build(); try (ExperimentServiceClient experimentServiceClient = googleAdsClient.getLatestVersion().createExperimentServiceClient()) { MutateExperimentsResponse response = experimentServiceClient.mutateExperiments( Long.toString(customerId), ImmutableList.of(operation)); String experiment = response.getResults(0).getResourceName(); System.out.printf("Created experiment with resource name '%s'%n", experiment); return experiment; } }
C#
private static string CreateExperimentResource(GoogleAdsClient client, long customerId) { // Get the ExperimentService. ExperimentServiceClient experimentService = client.GetService( Services.V26.ExperimentService); // Creates the experiment. Experiment experiment = new Experiment() { // Name must be unique. Name = $"Example Experiment #{ExampleUtilities.GetRandomString()}", // We specify SearchCustom to create a standard search campaign experiment. // This type uses a standard draft-based workflow where the system automatically // creates a draft/in-design campaign for the treatment arm. Type = ExperimentType.SearchCustom, Suffix = "[experiment]", Status = ExperimentStatus.Setup }; // Creates the operation. ExperimentOperation operation = new ExperimentOperation() { Create = experiment }; // Makes the API call. MutateExperimentsResponse response = experimentService.MutateExperiments( customerId.ToString(), new[] { operation }); // Displays the result. string experimentResourceName = response.Results.First().ResourceName; Console.WriteLine($"Created experiment with resource name " + $"'{experimentResourceName}'."); return experimentResourceName; }
PHP
private static function createExperimentResource( ExperimentServiceClient $experimentServiceClient, int $customerId ): string { // Creates an experiment and its operation. $experiment = new Experiment( [ // Name must be unique. 'name' => 'Example Experiment #' . Helper::getPrintableDatetime(), 'type' => ExperimentType::SEARCH_CUSTOM, 'suffix' => '[experiment]', 'status' => ExperimentStatus::SETUP ] ); $experimentOperation = new ExperimentOperation(['create' => $experiment]); // Issues a request to create the experiment. $response = $experimentServiceClient->mutateExperiments( MutateExperimentsRequest::build($customerId, [$experimentOperation]) ); $experimentResourceName = $response->getResults()[0]->getResourceName(); print "Created experiment with resource name '$experimentResourceName'" . PHP_EOL; return $experimentResourceName; }
Python
def create_experiment_resource( client: GoogleAdsClient, customer_id: str ) -> str: """Creates a new experiment resource. Args: client: an initialized GoogleAdsClient instance. customer_id: a client customer ID. Returns: the resource name for the new experiment. """ experiment_operation: ExperimentOperation = client.get_type( "ExperimentOperation" ) experiment: Experiment = experiment_operation.create experiment.name = f"Example Experiment #{uuid.uuid4()}" # We specify SEARCH_CUSTOM to create a standard search campaign experiment. # This type uses a standard draft-based workflow where the system automatically # creates a draft/in-design campaign for the treatment arm. experiment.type_ = client.enums.ExperimentTypeEnum.SEARCH_CUSTOM experiment.suffix = "[experiment]" experiment.status = client.enums.ExperimentStatusEnum.SETUP experiment_service: ExperimentServiceClient = client.get_service( "ExperimentService" ) response: MutateExperimentsResponse = experiment_service.mutate_experiments( customer_id=customer_id, operations=[experiment_operation] ) experiment_resource_name: str = response.results[0].resource_name print(f"Created experiment with resource name {experiment_resource_name}") return experiment_resource_name
Ruby
def create_experiment_resource(client, customer_id) operation = client.operation.create_resource.experiment do |e| # Name must be unique. e.name = "Example Experiment #{(Time.new.to_f * 1000).to_i}" # We specify SEARCH_CUSTOM to create a standard search campaign experiment. # This type uses a standard draft-based workflow where the system automatically # creates a draft/in-design campaign for the treatment arm. e.type = :SEARCH_CUSTOM e.suffix = '[experiment]' e.status = :SETUP end response = client.service.experiment.mutate_experiments( customer_id: customer_id, operations: [operation], ) experiment = response.results.first.resource_name puts "Created experiment with resource name #{experiment}." experiment end
Perl
sub create_experiment_resource { my ($api_client, $customer_id) = @_; my $experiment = Google::Ads::GoogleAds::V26::Resources::Experiment->new({ # Name must be unique. name => "Example Experiment #" . uniqid(), type => SEARCH_CUSTOM, suffix => "[experiment]", status => SETUP }); my $operation = Google::Ads::GoogleAds::V26::Services::ExperimentService::ExperimentOperation ->new({ create => $experiment }); my $response = $api_client->ExperimentService()->mutate({ customerId => $customer_id, operations => [$operation]}); my $resource_name = $response->{results}[0]{resourceName}; printf "Created experiment with resource name '%s'.\n", $resource_name; return $resource_name; }
curl
2. Crea gruppi sperimentali
Poi, crea le risorse ExperimentArm per definire i gruppi di controllo e sperimentali per l'esperimento. Tutti i bracci devono essere creati in un'unica richiesta.
Ogni esperimento deve avere esattamente un gruppo di controllo e uno o più gruppi sperimentali. Il gruppo di controllo identifica la campagna di base per il confronto e ogni gruppo sperimentale genera una nuova campagna in cui puoi apportare modifiche da testare.
Devi anche specificare traffic_split, ovvero la percentuale di traffico indirizzata a ciascun gruppo. La somma delle suddivisioni del traffico in tutti i gruppi deve essere pari a 100.
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( // In standard campaign experiments, creating the treatment arm automatically // generates a draft campaign 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#
private static (MutateExperimentArmResult, MutateExperimentArmResult) CreateExperimentArms(GoogleAdsClient client, long customerId, long baseCampaignId, string experimentResourceName) { // Get the ExperimentArmService. ExperimentArmServiceClient experimentService = client.GetService( Services.V26.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. // In standard campaign experiments, creating the treatment arm automatically // generates a draft campaign 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) # In standard campaign experiments, creating the treatment arm automatically # generates a draft campaign 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| # In standard campaign experiments, creating the treatment arm automatically # generates a draft campaign 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 second, it will be the second 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
Perl
sub create_experiment_arms { my ($api_client, $customer_id, $base_campaign_id, $experiment) = @_; my $operations = []; push @$operations, Google::Ads::GoogleAds::V26::Services::ExperimentArmService::ExperimentArmOperation ->new({ create => Google::Ads::GoogleAds::V26::Resources::ExperimentArm->new({ # The "control" arm references an already-existing campaign. control => "true", campaigns => [ Google::Ads::GoogleAds::V26::Utils::ResourceNames::campaign( $customer_id, $base_campaign_id ) ], experiment => $experiment, name => "control arm", trafficSplit => 40 })}); push @$operations, Google::Ads::GoogleAds::V26::Services::ExperimentArmService::ExperimentArmOperation ->new({ create => Google::Ads::GoogleAds::V26::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]; }
curl
Alcuni punti chiave:
- Esattamente un gruppo deve avere
controlimpostato sutrue. - La somma di
traffic_splitdeve essere pari a 100 in tutti i gruppi. - Il gruppo di controllo deve specificare esattamente una campagna nel campo
campaigns.
3. Modifica le campagne sperimentali
Quando crei un gruppo sperimentale (dove control è false), l'API crea automaticamente una bozza di campagna basata sulla campagna di controllo e compila il nome della risorsa nel campo in_design_campaigns del gruppo sperimentale. Puoi trattare queste campagne in fase di progettazione come campagne normali e modificarle con le modifiche che vuoi testare. La campagna di controllo non verrà modificata.
Queste modifiche vengono materializzate in una campagna reale e pubblicabile quando pianifichi l'esperimento.
Prima di poter pianificare l'esperimento, devi apportare almeno una modifica a una campagna in fase di progettazione.
Per recuperare il in_design_campaigns per un gruppo sperimentale, puoi eseguire una query su GoogleAdsService:
SELECT experiment_arm.in_design_campaigns
FROM experiment_arm
WHERE experiment_arm.resource_name = 'TREATMENT_ARM_RESOURCE_NAME'
PARAMETERS include_drafts = true
Pianifica l'esperimento
Dopo aver creato l'esperimento e i gruppi e aver modificato le campagne bozza di trattamento, puoi pianificare l'esperimento utilizzando ExperimentService.ScheduleExperiment. Si tratta di un'operazione asincrona che materializza le campagne in fase di progettazione in campagne effettive, pronte per essere pubblicate una volta raggiunta la start_date dell'esperimento. Per informazioni dettagliate sulla gestione delle operazioni a lunga esecuzione, consulta Errori asincroni.
Report sull'esperimento
Una volta avviato l'esperimento, puoi eseguire query sulle metriche per confrontare il rendimento. Per maggiori dettagli, consulta la guida ai report.
Completa, promuovi o termina l'esperimento
Dopo aver lasciato l'esperimento in esecuzione per un periodo di tempo sufficiente, puoi scegliere di terminarlo, promuoverlo o completarlo utilizzando ExperimentService.
- Termina: se vuoi interrompere l'esperimento senza applicare modifiche, utilizza
EndExperiment. La pubblicazione delle campagne sperimentali viene interrotta, ma non vengono rimosse. Si tratta di un'operazione sincrona. - Promuovi: se i risultati del gruppo sperimentale sono soddisfacenti e vuoi incorporare le modifiche nella campagna originale, utilizza
PromoteExperiment. In questo modo, le modifiche vengono copiate dal gruppo sperimentale alla campagna di controllo e la pubblicazione del gruppo sperimentale viene interrotta. Si tratta di un'operazione asincrona. Per maggiori dettagli, consulta Errori asincroni. Nota: gli esperimenti di tipoPMAX_REPLACEMENT_SHOPPINGnon possono essere promossi. - Promuovi: se le modifiche ti sono piaciute, ma vuoi che esistano separatamente dalla campagna originale, utilizza
GraduateExperiment. In questo modo, la campagna sperimentale viene convertita in una campagna standard indipendente che continua a essere pubblicata al di fuori del contesto dell'esperimento. La campagna di controllo non viene modificata. Si tratta di un'operazione sincrona.
Requisiti specifici per tipo
PMAX_REPLACEMENT_SHOPPING:
- Richiede esattamente due gruppi (uno di controllo e uno sperimentale).
- Il gruppo di controllo deve specificare una campagna Shopping nel campo
campaigns. - Per il gruppo sperimentale, hai due opzioni per configurare la campagna Performance Max:
- Per creare una nuova campagna PMax: lascia vuoto il campo
campaignsdel gruppo sperimentale. L'API crea automaticamente una campagna in fase di progettazione basata sulla campagna Shopping di controllo, come descritto nel passaggio 3. - Per utilizzare una campagna Performance Max esistente: specifica il nome della risorsa della campagna Performance Max nel campo
campaignsdel gruppo sperimentale. Se selezioni questa opzione, non viene creata alcuna campagna in fase di progettazione e puoi saltare il passaggio 3.
- Per creare una nuova campagna PMax: lascia vuoto il campo
- Ti consigliamo di escludere dalla valutazione i primi 7 giorni di statistiche per dare alla campagna il tempo di completare la fase di avvio e apprendimento.
- Impossibile promuovere.
YOUTUBE_CUSTOM:
- Supporta un massimo di 10 bracci.
- Per testare gli asset, imposta
asset_testing_infosul gruppo sperimentale.