Gli esperimenti gestiti dal sistema vengono utilizzati per i test A/B delle modifiche creando una o più campagne sperimentali modificabili che vengono eseguite insieme a una campagna di controllo originale.
Questo flusso di lavoro è supportato per i seguenti
ExperimentType valori:
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 verificare il rendimento delle campagne Shopping rispetto a Performance Max.
Configurazione
La configurazione degli esperimenti gestiti dal sistema prevede i seguenti passaggi:
- Crea una risorsa
Experiment. - Crea risorse
ExperimentArmper il controllo e il trattamento. - Modifica le
in_design_campaignsnei gruppi sperimentali.
1. Crea un esperimento
Il primo passo 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 devi specificare nessuna delle campagne coinvolte nell'esperimento.
Ecco una panoramica di alcuni campi chiave per una risorsa 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ù avanti 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 avviato l'esperimento, questo campo ti consentirà di verificarne lo stato attuale.start_dateeend_date: specifica le date di inizio e di fine dell'esperimento.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. 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()) .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#
/// <summary> /// Creates the experiment. /// </summary> /// <param name="client">The Google Ads client.</param> /// <param name="customerId">The customer ID for which the call is made.</param> /// <returns>The resource name of the newly created experiment.</returns> private static string CreateAnExperiment(GoogleAdsClient client, long customerId) { // Get the ExperimentService. ExperimentServiceClient experimentService = client.GetService( Services.V24.ExperimentService); // Creates the experiment. Experiment experiment = new Experiment() { // Name must be unique. Name = $"Example Experiment #{ExampleUtilities.GetRandomString()}", 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::V24::Resources::Experiment->new({ # Name must be unique. name => "Example Experiment #" . uniqid(), type => SEARCH_CUSTOM, suffix => "[experiment]", status => SETUP }); my $operation = Google::Ads::GoogleAds::V24::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 risorse ExperimentArm per definire
i gruppi di controllo e sperimentali per l'esperimento. Tutti i gruppi 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 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( // 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.V24.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) # 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::V24::Services::ExperimentArmService::ExperimentArmOperation ->new({ create => Google::Ads::GoogleAds::V24::Resources::ExperimentArm->new({ # The "control" arm references an already-existing campaign. control => "true", campaigns => [ Google::Ads::GoogleAds::V24::Utils::ResourceNames::campaign( $customer_id, $base_campaign_id ) ], experiment => $experiment, name => "control arm", trafficSplit => 40 })}); push @$operations, Google::Ads::GoogleAds::V24::Services::ExperimentArmService::ExperimentArmOperation ->new({ create => Google::Ads::GoogleAds::V24::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
Ecco 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 relativo 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 inserisce 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 sarà interessata.
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 le in_design_campaigns di 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"
Pianifica l'esperimento
Dopo aver creato l'esperimento e i gruppi e aver modificato le bozze di campagne 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 raggiunta la start_date dell'esperimento. Per informazioni dettagliate sulla gestione delle operazioni a lunga esecuzione, consulta la sezione
Errori asincroni.
Genera report sull'esperimento
Una volta avviato l'esperimento, puoi eseguire query sulle metriche per confrontare il rendimento. Per informazioni dettagliate, consulta la guida alla creazione di report.
Completa, promuovi o termina 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 le modifiche, utilizza
EndExperiment. La pubblicazione delle campagne sperimentali viene interrotta, ma le campagne 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. Questa operazione copia le modifiche dal gruppo sperimentale alla campagna di controllo e interrompe la pubblicazione del gruppo sperimentale. Si tratta di un'operazione asincrona. Per informazioni dettagliate, consulta la sezione Errori asincroni. Nota: gli esperimenti di tipoPMAX_REPLACEMENT_SHOPPINGnon possono essere promossi. - Completa: se ti sono piaciute le modifiche, ma vuoi che esistano separatamente
dalla campagna originale, utilizza
GraduateExperiment. Questa operazione converte la campagna sperimentale 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 relativo 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 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 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 dati dei primi 7 giorni, per dare alla campagna il tempo di completare la fase di implementazione 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.