Page Summary
-
Treatment campaigns are considered new campaigns and do not copy metrics from control campaigns.
-
Control and treatment campaigns accrue and retain their metrics separately throughout an experiment, even after promotion or graduation.
-
After promotion, changes from the treatment campaign are copied to the control campaign, but metrics remain associated with their original campaigns.
-
Experiment campaigns and base campaigns can be differentiated in search queries using
campaign.experiment_type.
There are two main ways to report on experiments:
- Direct experiment reporting: Query the
experimentresource for metrics. This option provides metrics for control and treatment arms in a single response, along with statistical comparison data such as uplift and p-values. This is the only way to report on intra-campaign experiments. - Campaign reporting: Query the
campaignresource for metrics, usingcampaign.experiment_typeto distinguish between base and experiment campaigns. This option is only available for experiments that use separate control and treatment campaigns, such as system-managed experiments.
This guide focuses primarily on direct experiment reporting, which is compatible with all experiment types that support reporting.
Direct experiment reporting
You can query the experiment resource directly to retrieve performance metrics
and statistical comparisons between your control and treatment arms.
Metrics and statistical significance
For core metrics such as clicks, impressions, cost, conversions, and conversion
value, the experiment resource provides both treatment metrics (for example,
metrics.clicks) and control metrics (for example, metrics.control_clicks) in
the same row.
It also provides fields to help you evaluate the statistical significance of any difference between the arms:
metrics.*_p_value: The probability that the observed results would occur if the experiment had no actual effect on the metric. A lower p-value indicates higher statistical significance.metrics.*_point_estimate: The estimated percentage lift (positive or negative) in the given metric for the treatment arm compared to the control arm. Together withmargin_of_error, they describe a confidence interval with a prescribed confidence level for the difference being estimated. The quantity being estimated is (treatment / control - 1). The point estimate is the center of the confidence interval.metrics.*_margin_of_error: The radius of the confidence interval, which is centered atpoint_estimate. It is calculated for a prescribed confidence level, which depends on the experiment type.
The following core metric fields are supported on the experiment resource,
including a treatment group value, a control group value, and the stat fields
listed previously:
clicksimpressionscost_microsconversionscost_per_conversionconversion_valueconversion_value_per_cost
For conversions, specifically, the statistical fields are available through the
following absolute_change fields, rather than as relative values:
metrics.conversions_absolute_change_p_value: The p-value for the null hypothesis that the experiment has no effect on conversions absolute change. Ranges from 0 to 1.metrics.conversions_absolute_change_point_estimate: The point estimate when estimating the experiment's effect on conversions absolute change.metrics.conversions_absolute_change_margin_of_error: The margin of error when estimating the experiment's effect on conversions absolute change.
For assistance constructing valid queries to the experiment resource, use the
Google Ads Query Builder tool.
Example query
The following GAQL query retrieves key metrics for an experiment:
SELECT
experiment.experiment_id,
experiment.name,
experiment.type,
metrics.clicks,
metrics.control_clicks,
metrics.clicks_point_estimate,
metrics.clicks_margin_of_error,
metrics.clicks_p_value,
metrics.conversions,
metrics.control_conversions,
metrics.conversions_absolute_change_point_estimate,
metrics.conversions_absolute_change_margin_of_error,
metrics.conversions_absolute_change_p_value
FROM experiment
WHERE experiment.experiment_id = EXPERIMENT_ID
Interpret results
You can use the p-value, point estimate, and margin of error fields to determine
if your experiment has yielded statistically significant results. For example,
if conversions_absolute_change_p_value is below your chosen threshold (for
example,
0.05 for 95% confidence) and conversions_absolute_change_point_estimate -
conversions_absolute_change_margin_of_error is greater than zero, it indicates
that the treatment arm is performing significantly better than the control arm
in terms of conversions.
Here is a Python snippet demonstrating how to evaluate results based on p-value and lift estimates:
Java
private void evaluateExperiment( GoogleAdsClient googleAdsClient, long customerId, GoogleAdsRow row) { Metrics metrics = row.getMetrics(); String experimentResourceName = row.getExperiment().getResourceName(); // 1. Evaluate conversion success as a primary success signal if available. // - Point Estimate: Represents the estimated average lift or difference in conversions. // - Margin of Error: Outlines the confidence interval bounds. Note that the margin_of_error // provided by the API is calculated for a preset confidence level which is set based on the // experiment type. // - Lower Bound: (Point Estimate - Margin of Error). If this value is above 0, // we have statistical significance that performance has improved. double convPValue = metrics.getConversionsAbsoluteChangePValue(); double convLift = metrics.getConversionsAbsoluteChangePointEstimate(); double convError = metrics.getConversionsAbsoluteChangeMarginOfError(); double convLowerBound = convLift - convError; if (convPValue <= P_VALUE_THRESHOLD) { if (convLowerBound > 0) { System.out.printf( "Significant Success: Conversions increased. Even at the lower bound, the lift is %.2f." + " Promoting changes.%n", convLowerBound); promoteExperiment(googleAdsClient, customerId, experimentResourceName); return; } else if ((convLift + convError) < 0) { System.out.printf( "Significant Decline: Even the upper bound (%.2f) is below zero. Ending experiment.%n", convLift + convError); endExperiment(googleAdsClient, customerId, experimentResourceName); return; } } // 2. Fall back to evaluating click metrics if conversions are inconclusive. double clickPValue = metrics.getClicksPValue(); double clickLift = metrics.getClicksPointEstimate(); double clickError = metrics.getClicksMarginOfError(); double clickLowerBound = clickLift - clickError; if (clickPValue <= P_VALUE_THRESHOLD && clickLowerBound > 0) { System.out.printf("Click volume is significantly up (+%.1f%%).%n", clickLift * 100); // Graduation is only supported for separate campaign experiments, not // intra-campaign experiments where there is no separate treatment campaign. ExperimentType experimentType = row.getExperiment().getType(); if (experimentType != ExperimentType.ADOPT_BROAD_MATCH_KEYWORDS && experimentType != ExperimentType.ADOPT_AI_MAX) { System.out.println("Graduating treatment campaign for further manual analysis."); graduateExperiment(googleAdsClient, customerId, experimentResourceName); } else { System.out.println( "Intra-campaign trial detected: graduation is not supported. Continuing to run the" + " experiment to gather more conversion data."); } } else { // 3. Print status if no action was taken. System.out.printf( "Inconclusive: No significant lift in Conversions (p=%.2f) or Clicks (p=%.2f). Current" + " estimated lift: %.2f +/- %.2f. Allowing the experiment to continue running.%n", convPValue, clickPValue, convLift, convError); } }
C#
private static void EvaluateExperiment(GoogleAdsClient client, long customerId, GoogleAdsRow row) { // This function evaluates performance metrics and immediately takes action // to update the experiment's status (promote, end, or graduate) if // statistical significance thresholds are met. var metrics = row.Metrics; string experimentResourceName = row.Experiment.ResourceName; bool hasConvMetrics = metrics.HasConversionsAbsoluteChangePValue && metrics.HasConversionsAbsoluteChangePointEstimate && metrics.HasConversionsAbsoluteChangeMarginOfError; bool hasClickMetrics = metrics.HasClicksPValue && metrics.HasClicksPointEstimate && metrics.HasClicksMarginOfError; // 1. Evaluate conversion success as a primary success signal if available. // - Point Estimate: Represents the estimated average lift or difference in conversions. // - Margin of Error: Outlines the confidence interval bounds. Note that the margin_of_error // provided by the API is calculated for a preset confidence level which is set based on // the experiment type. // - Lower Bound: (Point Estimate - Margin of Error). If this value is above 0, // we have statistical significance that performance has improved. if (hasConvMetrics) { double convPValue = metrics.ConversionsAbsoluteChangePValue; double convLift = metrics.ConversionsAbsoluteChangePointEstimate; double convError = metrics.ConversionsAbsoluteChangeMarginOfError; double convLowerBound = convLift - convError; if (convPValue <= P_VALUE_THRESHOLD) { if (convLowerBound > 0) { Console.WriteLine( $"Significant Success: Conversions increased. Even at the lower" + $" bound, the lift is {convLowerBound:F2}. Promoting changes."); PromoteExperiment(client, customerId, experimentResourceName); return; } else if ((convLift + convError) < 0) { Console.WriteLine( $"Significant Decline: Even the upper bound ({convLift + convError:F2}) " + $"is below zero. Ending experiment."); EndExperiment(client, customerId, experimentResourceName); return; } } } // 2. Evaluate click volume as a secondary signal. // This is helpful as an early indicator or for lower-volume accounts. if (hasClickMetrics) { double clickPValue = metrics.ClicksPValue; double clickLift = metrics.ClicksPointEstimate; double clickError = metrics.ClicksMarginOfError; double clickLowerBound = clickLift - clickError; if (clickPValue <= P_VALUE_THRESHOLD && clickLowerBound > 0) { // We have a directional winner: high confidence in more traffic, // but not enough data to confirm conversion impact yet. Console.WriteLine( $"Click volume is significantly up (+{clickLift * 100:F1}%)."); // Graduation is only supported for separate campaign experiments, not // intra-campaign experiments where there is no separate treatment campaign. if (row.Experiment.Type != ExperimentType.AdoptBroadMatchKeywords && row.Experiment.Type != ExperimentType.AdoptAiMax) { Console.WriteLine("Graduating treatment campaign for further manual analysis."); GraduateExperiment(client, customerId, experimentResourceName); } else { Console.WriteLine( "Intra-campaign trial detected: graduation is not supported. " + "Continuing to run the experiment to gather more conversion data."); } return; } } // 3. Print status if no action was taken. if (hasConvMetrics || hasClickMetrics) { string convStatus = hasConvMetrics ? $"Conversions (p={metrics.ConversionsAbsoluteChangePValue:F2}, " + $"lift={metrics.ConversionsAbsoluteChangePointEstimate:F2} +/- " + $"{metrics.ConversionsAbsoluteChangeMarginOfError:F2})" : "Conversions (not populated)"; string clickStatus = hasClickMetrics ? $"Clicks (p={metrics.ClicksPValue:F2}, " + $"lift={metrics.ClicksPointEstimate:F2} +/- " + $"{metrics.ClicksMarginOfError:F2})" : "Clicks (not populated)"; Console.WriteLine( $"Inconclusive: No significant action taken. {convStatus}, {clickStatus}. " + "Allowing the experiment to continue running."); } else { Console.WriteLine( "Conversion and click performance metrics are not yet populated. " + "Allowing the experiment to continue running."); } }
PHP
This example is not yet available in PHP; you can take a look at the other languages.
Python
def evaluate_experiment( client: GoogleAdsClient, customer_id: str, row: GoogleAdsRow ) -> None: """Evaluates the performance of the experiment and updates it accordingly (for example, promotes, ends, or graduates). Checks conversion and click metrics against statistical significance thresholds to determine the appropriate action to take on the experiment. Args: client: an initialized GoogleAdsClient instance. customer_id: a client customer ID. row: a GoogleAdsRow containing the experiment and metrics. """ # This function evaluates performance metrics and immediately takes action # to update the experiment's status (promote, end, or graduate) if # statistical significance thresholds are met. metrics = row.metrics experiment_resource_name = row.experiment.resource_name has_conv_metrics = ( "conversions_absolute_change_p_value" in metrics and "conversions_absolute_change_point_estimate" in metrics and "conversions_absolute_change_margin_of_error" in metrics ) has_click_metrics = ( "clicks_p_value" in metrics and "clicks_point_estimate" in metrics and "clicks_margin_of_error" in metrics ) # 1. Evaluate conversion success as a primary success signal if available. # - Point Estimate: Represents the estimated average lift or difference in conversions. # - Margin of Error: Outlines the confidence interval bounds. Note that the margin_of_error provided by the API is calculated for a preset confidence level which is set based on the experiment type. # - Lower Bound: (Point Estimate - Margin of Error). If this value is above 0, # we have statistical significance that performance has improved. if has_conv_metrics: conv_p_value = metrics.conversions_absolute_change_p_value conv_lift = metrics.conversions_absolute_change_point_estimate conv_error = metrics.conversions_absolute_change_margin_of_error conv_lower_bound = conv_lift - conv_error if conv_p_value <= P_VALUE_THRESHOLD: if conv_lower_bound > 0: print( "Significant Success: Conversions increased. Even at the lower" f" bound, the lift is {conv_lower_bound:.2f}. Promoting" " changes." ) promote_experiment( client, customer_id, experiment_resource_name ) return elif (conv_lift + conv_error) < 0: print( "Significant Decline: Even the upper bound" f" ({conv_lift + conv_error:.2f}) is below zero. Ending" " experiment." ) end_experiment(client, customer_id, experiment_resource_name) return # 2. Evaluate click volume as a secondary signal. # This is helpful as an early indicator or for lower-volume accounts. click_p_value = metrics.clicks_p_value click_lift = metrics.clicks_point_estimate click_error = metrics.clicks_margin_of_error click_lower_bound = click_lift - click_error if click_p_value <= P_VALUE_THRESHOLD and click_lower_bound > 0: # We have a directional winner: high confidence in more traffic, # but not enough data to confirm conversion impact yet. print(f"Click volume is significantly up (+{click_lift*100:.1f}%).") # Graduation is only supported for separate campaign experiments, not # intra-campaign experiments where there is no separate treatment campaign. experiment_type_name = row.experiment.type_.name if ( experiment_type_name != "ADOPT_BROAD_MATCH_KEYWORDS" and experiment_type_name != "ADOPT_AI_MAX" ): print( "Graduating treatment campaign for further manual analysis." ) graduate_experiment( client, customer_id, experiment_resource_name ) else: print( "Intra-campaign trial detected: graduation is not supported. " "Continuing to run the experiment to gather more conversion data." ) return # 3. Print status if no action was taken. if has_conv_metrics or has_click_metrics: conv_status = ( f"Conversions (p={metrics.conversions_absolute_change_p_value:.2f}, " f"lift={metrics.conversions_absolute_change_point_estimate:.2f} +/- " f"{metrics.conversions_absolute_change_margin_of_error:.2f})" if has_conv_metrics else "Conversions (not populated)" ) click_status = ( f"Clicks (p={metrics.clicks_p_value:.2f}, " f"lift={metrics.clicks_point_estimate:.2f} +/- " f"{metrics.clicks_margin_of_error:.2f})" if has_click_metrics else "Clicks (not populated)" ) print( f"Inconclusive: No significant action taken. {conv_status}, {click_status}." " Allowing the experiment to continue running." ) else: print( "Conversion and click performance metrics are not yet populated. " "Allowing the experiment to continue running." )
Ruby
This example is not yet available in Ruby; you can take a look at the other languages.
Perl
This example is not yet available in Perl; you can take a look at the other languages.
curl
Benefits over campaign reporting
Direct experiment reporting offers several advantages over querying campaign reports separately:
- Centralized metrics: Retrieve metrics for control and treatment in a single row.
- Statistical confidence data: Provides calculated p-values, point estimates, and margins of error.
- Efficiency: Removes the need to manually join or compare results from multiple reports.
- Intra-campaign support: It is the only way to compare control versus treatment for intra-campaign experiments, where traffic is split within a single campaign.
Campaign reporting
For experiments that create separate treatment campaigns (for example,
SEARCH_CUSTOM), you can query the campaign resource and use
campaign.experiment_type to identify BASE (control) and EXPERIMENT
(treatment) campaigns. This approach is useful if you need to segment metrics at
a more granular level (for example, by ad group or keyword) or view campaign
metadata not available on the experiment resource. However, it requires you to
perform performance comparisons and statistical calculations manually.
You cannot use campaign-level reporting to compare arms for intra-campaign
experiments, as the traffic split happens internally within a single campaign.
Querying campaign for an intra-campaign experiment only returns aggregated
totals.
Brand Lift reporting
You can report on Brand Lift studies in the Google Ads API using dedicated Brand Lift measurement resources.
Brand Lift resources and breakdown views
Query the LiftMeasurementFlight
resource to retrieve flight-level Brand Lift study results, including the flight
date ranges (start_date and
end_date) in the customer's
time zone.
To analyze Brand Lift metrics across different segment dimensions, query the corresponding breakdown resources:
LiftMeasurementCampaign: Breakdown by campaign.LiftMeasurementAgeRange: Breakdown by age range.LiftMeasurementDevice: Breakdown by device.LiftMeasurementGender: Breakdown by gender.LiftMeasurementVideo: Breakdown by video asset.
The BrandLiftMeasurementType
enum specifies the measurement type for the study, such as brand awareness or
ad recall.
Example Brand Lift queries
Because flight metadata and lift statistics reside on separate resources, querying flight details and performance statistics requires separate GAQL queries.
Flight details query
To retrieve metadata for a Brand Lift flight such as its status, measurement
type, and scheduled dates, query the
LiftMeasurementFlight resource:
SELECT
lift_measurement_flight.lift_measurement_config_id,
lift_measurement_flight.lift_measurement_flight_id,
lift_measurement_flight.name,
lift_measurement_flight.status,
lift_measurement_flight.lift_type,
lift_measurement_flight.start_date,
lift_measurement_flight.end_date
FROM lift_measurement_flight
WHERE lift_measurement_flight.lift_measurement_config_id = CONFIG_ID
Statistics query
To retrieve Brand Lift metrics, query the appropriate breakdown resource (or
overall study configuration on LiftMeasurementConfig).
For example, the following query retrieves Brand Lift metrics broken down by
campaign from LiftMeasurementCampaign:
SELECT
lift_measurement_campaign.lift_measurement_config_id,
lift_measurement_campaign.campaign,
metrics.absolute_brand_lift,
metrics.relative_brand_lift
FROM lift_measurement_campaign
WHERE lift_measurement_campaign.lift_measurement_config_id = CONFIG_ID
Conversion Lift reporting
You can measure the incremental impact of your ads on conversions using Conversion Lift reporting in the Google Ads API.
Conversion Lift configuration and metrics
Query the LiftMeasurementConfig
resource to retrieve Conversion Lift study configurations and performance data.
The resource provides Conversion Lift metrics to evaluate incremental performance:
metrics.conversion_lift_baseline_conversions: Baseline conversions for the study.metrics.conversion_lift_exposed_conversions: Conversions observed in the exposed group.metrics.incremental_conversions: Incremental conversions attributed to ads.metrics.cost_per_incremental_conversion: Cost per incremental conversion.metrics.relative_conversion_lift: Relative lift in conversions.metrics.conversion_lift_baseline_conversion_value: Baseline conversion value.metrics.conversion_lift_exposed_conversion_value: Conversion value in the exposed group.metrics.incremental_conversion_value: Incremental conversion value attributed to ads.metrics.relative_conversion_value_lift: Relative lift in conversion value.
Conversion Lift reporting also enables segmenting by conversion actions and retrieving linked campaign details, experiment details, and conversion goals.
Example Conversion Lift query
The following GAQL query retrieves Conversion Lift configurations and key performance metrics:
SELECT
lift_measurement_config.lift_measurement_config_id,
segments.conversion_lift_start_date,
segments.conversion_lift_end_date,
segments.conversion_lift_included_conversion_action_types,
metrics.conversion_lift_baseline_conversions,
metrics.conversion_lift_exposed_conversions,
metrics.incremental_conversions,
metrics.cost_per_incremental_conversion,
metrics.relative_conversion_lift,
metrics.incremental_conversion_value,
metrics.relative_conversion_value_lift
FROM lift_measurement_config
WHERE segments.conversion_lift_start_date = START_DATE
AND segments.conversion_lift_end_date = END_DATE
AND lift_measurement_config.lift_measurement_config_id = CONFIG_ID
Best practices
- Select an appropriate confidence level: Setting a lower p-value threshold can provide directional guidance faster, especially with lower budgets or conversion volumes. A 95% confidence (p-value <= 0.05) is considered the academic standard and may be better for more accurate results over a longer timeframe.
- Run experiments for long enough: Run experiments for at least 4 weeks to account for weekly performance cycles, conversion delays, and learning periods.
- Give time for ramp-up: For campaigns using automated bidding or testing new features, disregard the first 1-2 weeks of data to give time for bidding models and traffic levels to recalibrate to the split.
- Use 50/50 splits: A 50/50 traffic split is generally the fastest way to achieve statistically significant results.
- Schedule in advance: Set your experiment start date 3-7 days in the future to give time for ad review and approval processes.
- You can only run one experiment per campaign at any given time.