Gli esperimenti gestiti dal sistema vengono utilizzati per eseguire test A/B sulle modifiche creando una o più campagne sperimentali modificabili che vengono eseguite parallelamente a una campagna di controllo originale.
Questo flusso di lavoro è supportato per i seguenti valori di
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 segue questi passaggi:
- Crea un
Experiment. - Crea risorse
ExperimentArmper il gruppo di controllo e il gruppo sperimentale. - Modifica il
in_design_campaignsnei gruppi sperimentali.
1. Crea un esperimento
Il primo passaggio per eseguire un esperimento utilizzando l'API Google Ads è creare un
Experiment. Questa risorsa definisce alcune 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 come riferimento in un secondo momento. Non influisce sull'esecuzione dell'esperimento.suffix: il suffisso verrà aggiunto alla fine dei nomi delle campagne sperimentali in modo da poterle distinguere dalla campagna di controllo. Questi concetti verranno spiegati più nel dettaglio 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 un secondo momento, una volta iniziato l'esperimento, questo campo ti consentirà di controllare lo stato attuale.start_dateeend_date: specifica quando deve iniziare e terminare l'esperimento.sync_enabled: disabilitato per impostazione predefinita. Se impostata sutrue, le modifiche apportate alla campagna originale durante l'esecuzione dell'esperimento vengono copiate automaticamente nella campagna sperimentale. Scopri di più.
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.V25.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}" 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::V25::Resources::Experiment->new({ # Name must be unique. name => "Example Experiment #" . uniqid(), type => SEARCH_CUSTOM, suffix => "[experiment]", status => SETUP }); my $operation = Google::Ads::GoogleAds::V25::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. Creare gruppi sperimentali
Poi, crea 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 ogni gruppo. La somma delle suddivisioni del traffico in tutti i gruppi deve essere 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.V25.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| # 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
Perl
sub create_experiment_arms { my ($api_client, $customer_id, $base_campaign_id, $experiment) = @_; my $operations = []; push @$operations, Google::Ads::GoogleAds::V25::Services::ExperimentArmService::ExperimentArmOperation ->new({ create => Google::Ads::GoogleAds::V25::Resources::ExperimentArm->new({ # The "control" arm references an already-existing campaign. control => "true", campaigns => [ Google::Ads::GoogleAds::V25::Utils::ResourceNames::campaign( $customer_id, $base_campaign_id ) ], experiment => $experiment, name => "control arm", trafficSplit => 40 })}); push @$operations, Google::Ads::GoogleAds::V25::Services::ExperimentArmService::ExperimentArmOperation ->new({ create => Google::Ads::GoogleAds::V25::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 braccio deve avere
controlimpostato sutrue. - Il
traffic_splitdeve essere pari a 100 in tutti i gruppi. - Il gruppo di controllo deve specificare esattamente una campagna nel campo
campaigns.
3. Modificare 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-design come campagne normali e modificarle con le modifiche che vuoi testare. La campagna di controllo non sarà interessata.
Queste modifiche vengono materializzate in una campagna reale 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
GoogleAdsService:
SELECT experiment_arm.in_design_campaigns
FROM experiment_arm
WHERE experiment_arm.resource_name = "TREATMENT_ARM_RESOURCE_NAME"
Pianifica l'esperimento
Dopo aver creato l'esperimento e i gruppi e modificato le campagne bozza del gruppo sperimentale, 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 la pubblicazione una volta che arriva il start_date dell'esperimento. Per informazioni dettagliate sulla gestione delle operazioni a lunga esecuzione, consulta la sezione Errori asincroni.
Report sull'esperimento
Una volta avviato l'esperimento, puoi eseguire query per le metriche per confrontare il rendimento. Per maggiori dettagli, consulta la guida ai report.
Eseguire l'upgrade, promuovere o terminare l'esperimento
Dopo aver lasciato in esecuzione l'esperimento 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. Le campagne sperimentali smettono di essere pubblicate, ma non vengono rimosse. Si tratta di un'operazione sincrona. - Promuovi: se sei soddisfatto del rendimento del gruppo sperimentale 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 i dettagli, consulta la sezione Errori asincroni. Nota: gli esperimenti di tipoPMAX_REPLACEMENT_SHOPPINGnon possono essere promossi. - Passa a: se ti sono piaciute le modifiche, 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-design in base alla campagna Shopping di controllo, come descritto nel passaggio 3. - Per utilizzare una campagna PMax esistente: specifica il nome della risorsa della campagna PMax nel campo
campaignsdel gruppo sperimentale. Se selezioni questa opzione, non viene creata alcuna campagna in-design e puoi saltare il passaggio 3.
- Per creare una nuova campagna PMax, lascia vuoto il campo
- Ti consigliamo di escludere i primi 7 giorni di statistiche dalla tua valutazione per dare alla campagna il tempo di completare la fase di avvio e apprendimento.
- Non può essere promossa.
YOUTUBE_CUSTOM:
- Supporta un massimo di 10 gruppi.
- Per testare gli asset, imposta
creative_asset_testing_infonel gruppo sperimentale.