Campaign Drafts and Experiments

Google Ads scripts supports campaign drafts and experiments, which are used to prepare and test changes to Search and Display Network campaigns.

A draft is a clone of an existing campaign that won't serve its own ads, but can be used to stage changes without modifying the original campaign. The staged changes can then be applied to the base campaign.

An experiment runs a customizable campaign in parallel to the original campaign, and does show ads to a specified percentage of traffic. Based on the results of the experiment, you can apply the changes to the original campaign, branch the experiment to an independent campaign, or abandon the experiment campaign.

This guide explains the basic workflow for working with drafts and experiments in a script.

Drafts

Create a draft

A draft is made from an existing base campaign by using a DraftBuilder and providing a unique name. The base campaign must be a Search, Search Network campaign with Display Expansion, or Display campaign (excluding Mobile App campaign for the Display Network), and it must not have a shared budget.

const campaign = AdsApp.campaigns()
    .withCondition(`campaign.name = "${campaignName}"`)
    .get()
    .next();

const draftBuilder = campaign.newDraftBuilder()
    .withName("INSERT_DRAFT_NAME_HERE")
    .build();

const draft = draftBuilder.getResult();

DraftBuilder.build() returns a DraftOperation, a typical operation in Scripts. See our guide to builders for more details.

A draft is uniquely identified by the combination of its base campaign ID and draft ID. See DraftSelector.withIds() for more information.

Provision the draft campaign

A draft object relates a base campaign and a draft campaign. To stage updates to the base campaign, you propagate changes through the draft campaign.

A draft campaign, like any other campaign, has methods to get and set its various attributes such as criteria, ad groups, bids, and ads.

const draftCampaign = draft.getDraftCampaign();

draftCampaign.setAdRotationType("CONVERSION_OPTIMIZE");
draftCampaign.createNegativeKeyword("shoes");

Keep in mind that ad policy checks are done for a draft campaign just as they are for the base campaign. You will not be able to run an experiment from a draft campaign that has policy-violating ads.

Execute the draft

After provisioning the draft campaign, you can do one of the following:

  1. If you don't want to use the changes, you can simply remove the draft. Removing the draft is irreversible, but it can still be viewed under All drafts in the drafts tab of the Google Ads UI.

    draft.remove();
    
  2. If you decide to keep the changes you made in the draft, you can go ahead and apply them:

    draft.startApplying();
    

    This method starts the process of applying the updates to the base campaign, so the draft will have status Applying... in the Google Ads UI. However, the method will not notify you when the process completes.

  3. If you would like to test out your changes first, you can use the draft to create an experiment.

Experiments

Create an experiment

An experiment is similar to a draft, and also is created from a base campaign. You create an experiment with an ExperimentBuilder. This will automatically create an experiment with two "arms" that represent the different parts of the experiment. One arm (called the control arm) will contain the base campaign, and the other (called the treatment arm) will contain a new draft campaign which you will customize as per the steps for the draft above before scheduling the experiment.

When building an experiment, make sure to set all of the following in the builder:

withCampaign
The campaign that you want the experiment to be based on.
withTrafficSplitPercent
How much of the traffic will go to the experiment arm. For 50%, specify 50.
withStartDate and withEndDate
Specifies the start and end date of the campaign. Specify in YYYYMMdd format.
withType
Either SEARCH_CUSTOM or DISPLAY_CUSTOM, depending on which network you are using.
withSuffix
Specifies a suffix that will be added to the name of the treatment campaign when it is created.
withGoals
Specifies the goals for this experiment. This is just a reminder to yourself what your goals were when creating it. A good default value is [{metric: 'CLICKS', direction: 'INCREASE'}].

The traffic split percentage determines what portion of traffic will be shown ads from the experiment campaign instead of the base campaign. For this reason, each base campaign can have only one running experiment at a time.

const experiment = AdsApp.newExperimentBuilder()
  .withCampaign(campaign)
  .withTrafficSplitPercent(50)
  .withStartDate("20230501")
  .withEndDate("20230601")
  .withType("SEARCH_CUSTOM")
  .withSuffix("experiment")
  .withGoals([{metric: 'CLICKS', direction: 'INCREASE'}])
  .build();

// The experimentCampaign represents the customizeable draft.
const experimentCampaign = experiment.getExperimentCampaign();

Unlike drafts, experiments are uniquely identified by a single ID. See ExperimentSelector.withIds() for more information.

Provision the experiment campaign

Similar to a draft, an experiment itself is not a campaign. Rather, it relates the base campaign, the draft, and the experiment campaign. Fields of an experiment campaign are modifiable, with the following exceptions:

  • name
  • status
  • start date
  • end date
  • budget
const experimentCampaign = experiment.getExperimentCampaign();

// Will succeed.
experimentCampaign.setAdRotationType("ROTATE_FOREVER");
experimentCampaign.createNegativeKeyword("sneakers");

// Will fail.
experimentCampaign.setName("INSERT_EXPERIMENT_NAME_HERE");

Changes to the name, start date, and end date can be made to the experiment, after which they will propagate to the experiment campaign.

// Will succeed.
experiment.setName("INSERT_EXPERIMENT_NAME_HERE");

// Will succeed if date is acceptable.
const date = "20220601";
experiment.setStartDate(date);

To start the experiment, call experiment.startScheduling(). This is an asynchronous process, as it must copy all the settings from the base campaign.

After the experiment ends

At your experiment's completion, you have a few options. We recommend letting the experiment completely finish so that it will stop serving ads but you can still interact with it. A Finished experiment can still be removed, applied, or graduated, and its campaign's performance stats are still accessible.

experiment.finish();
const stats = experimentCampaign.getStatsFor("INSERT_TIME_PERIOD_HERE");
  • If you're dissatisfied with the experiment based on the stats, you can remove the experiment, which also removes the experiment campaign. Removing the experiment is irreversible, but it can still be viewed under All experiments in the experiments tab of the Google Ads UI.

    experiment.remove();
    
  • If you're satisfied with the experiment's results, you have two options:

    1. You can start applying the changes and just as with drafts, you won't be notified when the process completes.

      experiment.startApplying();
      
    2. You can establish the experiment campaign as an independent, fully-operating campaign, without affecting the base campaign. This process, known as graduation, completes immediately and requires a new budget to be set.

      const budget = AdsApp.budgets()
          .withCondition(`campaign_budget.id = ${budgetId}`)
          .get()
          .next();
      
      experiment.graduate(budget);
      

      The new campaign can no longer share a budget with the base campaign, which necessitates a new budget. Graduated campaigns are just like normal campaigns in that all their fields are modifiable and that they can serve as a base campaign for more drafts and experiments.

Other considerations

Base entities

The introduction of drafts and experiments to Google Ads scripts also introduces the notion of base entities. Draft and experiment campaigns and the ad groups in them are distinct from their original base campaigns, which is why Campaign and AdGroup now have methods to access their base campaign and ad group: getBaseCampaign() and getBaseAdGroup().

These methods return the calling entity if called by a base campaign or ad group. Entities within campaigns and ad groups, such as keywords and ads, also have been given such methods.

To help keep track of base entities, campaigns have been given the isBaseCampaign(), isDraftCampaign(), and isExperimentCampaign() methods.

The new Campaign.draftCampaigns() and Campaign.experimentCampaigns() methods let you access all the draft and experiment campaigns that have the calling campaign as their base campaign. However, you cannot select draft campaigns with CampaignSelector.withCondition(); use AdsApp.drafts() instead.

Error handling

The following methods involving drafts and experiments proceed when the script is run, but might fail asynchronously:

  • Draft.startApplying()
  • Experiment.startApplying()
  • Experiment.startScheduling()

You should wait to check whether these operations succeed. The Google Ads UI shows the statuses Applied or Active after successful completions of startApplying() and startScheduling(), respectively. And, it indicates Unable to apply or Unable to create upon failure, letting you click to see the errors.

It's also possible that some methods fail in the preview stage, but succeed after they run; for instance, after creating a draft:

const draftCampaign = draft.getDraftCampaign();
draftCampaign.createNegativeKeyword("shoes"); // Will fail in preview.

This will fail in preview mode as it cannot access the draft campaign immediately.

Similarly, creating an experiment and immediately trying to fetch its draft campaign will fail in preview mode, since the draft isn't actually created.

For this reason, check the logs below your list of scripts after running them, and proceed with a failed-in-preview script only if you believe the cause is due to limitations in the preview mode.