Les tests gérés par le système permettent de tester les modifications par A/B en créant une ou plusieurs campagnes tests modifiables qui s'exécutent en parallèle d'une campagne de contrôle d'origine.
Ce workflow est compatible avec les valeurs
ExperimentType suivantes :
SEARCH_CUSTOM: test personnalisé comprenant des campagnes sur le Réseau de Recherche.DISPLAY_CUSTOM: test personnalisé comprenant des campagnes display.HOTEL_CUSTOM: test personnalisé comprenant des campagnes d'hôtel.YOUTUBE_CUSTOM: test personnalisé comprenant des 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 suit les étapes suivantes :
- Créez un
Experiment. - Créez des ressources
ExperimentArmpour le contrôle et le traitement. - Modifiez les
in_design_campaignsdans les groupes 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 certaines informations clés sur le test que vous souhaitez exécuter. Vous ne spécifiez aucune des campagnes impliquées dans le test à cette étape.
Voici un aperçu de certains champs clés d'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 l'exécution du test.suffix: le suffixe est ajouté à la fin des noms des campagnes tests afin 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. Plus tard, une fois le test lancé, ce champ vous permettra de vérifier l'état actuel.start_dateetend_date: spécifiez quand le test doit commencer et se terminer.sync_enabled: désactivé 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 savoirplus.
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. Créer des groupes de test
Ensuite, créez des ressources ExperimentArm pour définir
les groupes de contrôle et de traitement du test. Tous les groupes doivent être créés dans une seule requête.
Chaque test 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 apporter des modifications à tester.
Vous devez également spécifier traffic_split, qui correspond au pourcentage de trafic redirigé vers chaque groupe. La somme des répartitions du trafic sur tous les groupes 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( // 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
Quelques points clés :
- Exactement un groupe doit avoir la valeur
controldéfinie surtrue. - La somme des
traffic_splitsur tous les groupes doit être égale à 100. - 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 remplit son nom de ressource dans le champ in_design_campaigns du groupe de traitement. Vous pouvez traiter ces campagnes en cours de conception 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 matérialisées dans une campagne réelle et diffusée 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 les 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 groupes, et modifié les campagnes brouillons tests
, vous pouvez planifier le test à l'aide de
ExperimentService.ScheduleExperiment.
Il s'agit d'une opération asynchrone qui matérialise les campagnes en cours de conception en campagnes réelles, prêtes à être diffusées une fois la start_date du test atteinte. Pour en savoir plus sur la gestion des opérations de longue durée, consultez
Erreurs asynchrones.
Rapports 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.
Terminer, promouvoir ou valider le 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 valider à l'aide de
ExperimentService.
- Terminer : si vous souhaitez arrêter le test sans appliquer de modifications, utilisez
EndExperiment. Les campagnes tests 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 groupe de traitement et
que vous souhaitez intégrer les modifications à votre campagne d'origine, utilisez
PromoteExperiment. Cette opération copie les modifications du 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. - Valider : si vous avez aimé les modifications, mais que vous souhaitez qu'elles existent séparément
de la campagne d'origine, utilisez
GraduateExperiment. Cette opération convertit la campagne de traitement en une campagne standard 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 groupes (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 nouvelle campagne Performance Max : laissez le champ
campaignsdu groupe de traitement vide. L'API crée automatiquement une campagne en cours de conception 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 groupe de traitement. Si vous sélectionnez cette option, aucune campagne en cours de conception n'est créée, et vous pouvez ignorer l'étape 3.
- Pour créer une nouvelle campagne Performance Max : laissez le champ
- Il est recommandé d'ignorer les sept premiers jours de statistiques de votre évaluation pour laisser à la campagne le temps de terminer sa phase de montée en puissance et d'apprentissage.
- Ne peut pas être promu.
YOUTUBE_CUSTOM:
- Accepte un maximum de 10 groupes.
- Pour tester des composants, définissez
creative_asset_testing_infosur le groupe de test.