Les tests gérés par le système permettent de tester les modifications par A/B en créant une ou plusieurs campagnes de traitement modifiables qui sont diffusées en même temps qu'une campagne de contrôle d'origine.
Ce workflow est compatible avec les valeurs ExperimentType suivantes :
SEARCH_CUSTOM: test personnalisé composé de campagnes sur le Réseau de Recherche.DISPLAY_CUSTOM: test personnalisé composé de campagnes display.HOTEL_CUSTOM: test personnalisé composé de campagnes d'hôtel.YOUTUBE_CUSTOM: test personnalisé composé de campagnes vidéo.PMAX_REPLACEMENT_SHOPPING: test permettant de comparer les performances de vos campagnes Shopping à celles de Performance Max.
Configuration
La configuration des tests gérés par le système se déroule comme suit :
- Créez un
Experiment. - Créez des ressources
ExperimentArmpour le contrôle et le traitement. - Modifiez le
in_design_campaignsdans les bras de traitement.
1. Créer un test
La première étape pour exécuter un test à l'aide de l'API Google Ads consiste à créer un Experiment. Cette ressource définit des informations clés sur le test que vous souhaitez exécuter. À cette étape, vous ne spécifiez aucune des campagnes concernées par le test.
Voici un aperçu de certains champs clés pour un Experiment :
name: chaque test doit avoir un nom unique.description: champ facultatif que vous pouvez utiliser comme référence ultérieurement. N'a aucune incidence sur le déroulement du test.suffix: le suffixe sera ajouté à la fin du nom des campagnes de traitement pour que vous puissiez les distinguer de la campagne de contrôle. Ces concepts seront expliqués plus en détail à l'étape 2.type: type de test à exécuter. Pour les tests gérés par le système, utilisezSEARCH_CUSTOM,DISPLAY_CUSTOM,HOTEL_CUSTOM,YOUTUBE_CUSTOMouPMAX_REPLACEMENT_SHOPPING.status: lorsque vous créez un test, définissez ce champ surSETUP. Une fois le test lancé, ce champ vous permettra de vérifier son état actuel.start_dateetend_date: spécifiez quand le test doit commencer et se terminer.sync_enabled: cette option est désactivée par défaut. Si la valeur est définie surtrue, les modifications apportées à la campagne d'origine pendant l'exécution du test sont automatiquement copiées dans la campagne test. En savoir plus
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. Créer des bras de test
Créez ensuite des ressources ExperimentArm pour définir les groupes de contrôle et de traitement du test. Tous les bras doivent être créés dans une seule requête.
Chaque expérience doit comporter exactement un groupe de contrôle et un ou plusieurs groupes de traitement. Le groupe de contrôle identifie la campagne de base à comparer, et chaque groupe de traitement génère une nouvelle campagne dans laquelle vous pouvez effectuer des modifications à tester.
Vous devez également spécifier traffic_split, qui correspond au pourcentage de trafic dirigé vers chaque bras. La somme des répartitions du trafic pour tous les bras doit être égale à 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
Voici quelques points clés :
- Un seul bras doit avoir
controldéfini surtrue. - La somme des
traffic_splitdoit être égale à 100 pour tous les bras. - Le groupe de contrôle doit spécifier exactement une campagne dans son champ
campaigns.
3. Modifier les campagnes tests
Lorsque vous créez un groupe de traitement (où control est false), l'API crée automatiquement une campagne brouillon basée sur la campagne de contrôle et insère son nom de ressource dans le champ in_design_campaigns du groupe de traitement. Vous pouvez traiter ces campagnes intégrées comme des campagnes standards et les modifier avec les changements que vous souhaitez tester. La campagne de contrôle ne sera pas affectée.
Ces modifications sont concrétisées dans une campagne réelle et diffusable lorsque vous planifiez le test.
Vous devez apporter au moins une modification à une campagne en cours de conception avant de pouvoir planifier le test.
Pour récupérer le in_design_campaigns d'un groupe de traitement, vous pouvez interroger GoogleAdsService :
SELECT experiment_arm.in_design_campaigns
FROM experiment_arm
WHERE experiment_arm.resource_name = "TREATMENT_ARM_RESOURCE_NAME"
Planifier le test
Après avoir créé le test et les bras, et modifié les campagnes brouillons de traitement, vous pouvez planifier le test à l'aide de ExperimentService.ScheduleExperiment.
Il s'agit d'une opération asynchrone qui concrétise les campagnes en cours de conception en campagnes réelles, prêtes à être diffusées une fois que la start_date du test arrive. Pour en savoir plus sur la gestion des opérations de longue durée, consultez Erreurs asynchrones.
Rapport sur le test
Une fois le test en cours d'exécution, vous pouvez interroger les métriques pour comparer les performances. Pour en savoir plus, consultez le guide sur les rapports.
Faire évoluer, promouvoir ou mettre fin au test
Après avoir laissé le test s'exécuter pendant une durée suffisante, vous pouvez choisir de le terminer, de le promouvoir ou de le faire passer à la phase suivante à l'aide de ExperimentService.
- Terminer : si vous souhaitez arrêter le test sans appliquer de modifications, utilisez
EndExperiment. Les campagnes test cessent d'être diffusées, mais ne sont pas supprimées. Il s'agit d'une opération synchrone. - Promouvoir : si vous êtes satisfait des performances du bras de traitement et que vous souhaitez intégrer les modifications à votre campagne d'origine, utilisez
PromoteExperiment. Cette option copie les modifications apportées au groupe de traitement dans la campagne de contrôle et arrête la diffusion du groupe de traitement. Il s'agit d'une opération asynchrone. Pour en savoir plus, consultez Erreurs asynchrones. Remarque : Les tests de typePMAX_REPLACEMENT_SHOPPINGne peuvent pas être promus. - Terminer : si vous avez aimé les modifications, mais que vous souhaitez qu'elles soient distinctes de la campagne d'origine, utilisez
GraduateExperiment. La campagne de traitement est alors convertie en campagne standard et indépendante, qui continue d'être diffusée en dehors du contexte du test. La campagne de contrôle n'est pas modifiée. Il s'agit d'une opération synchrone.
Exigences spécifiques au type
PMAX_REPLACEMENT_SHOPPING :
- Nécessite exactement deux bras (un de contrôle et un de traitement).
- Le groupe de contrôle doit spécifier une campagne Shopping dans son champ
campaigns. - Pour le groupe de traitement, vous avez deux options pour configurer la campagne Performance Max :
- Pour créer une campagne PMax , laissez le champ
campaignsdu bras de traitement vide. L'API crée automatiquement une campagne In-Design basée sur la campagne Shopping de contrôle, comme décrit à l'étape 3. - Pour utiliser une campagne Performance Max existante : spécifiez le nom de ressource de la campagne Performance Max dans le champ
campaignsdu bras de traitement. Si vous sélectionnez cette option, aucune campagne intégrée n'est créée et vous pouvez ignorer l'étape 3.
- Pour créer une campagne PMax , laissez le champ
- Nous vous recommandons d'ignorer les statistiques des sept premiers jours de votre évaluation pour laisser à la campagne le temps de terminer sa phase de montée en puissance et d'apprentissage.
- Promotion impossible.
YOUTUBE_CUSTOM :
- Il accepte un maximum de 10 bras.
- Pour tester des composants, définissez
creative_asset_testing_infodans le groupe de test.