App Campaigns

This guide describes how to create, configure, and monitor performance of App Campaigns (formerly known as a Universal App Campaigns). These campaigns enable promoting your Android or iOS apps across Google's top properties including Search, Play, YouTube, and the Google Display Network.

An App Campaign is a campaign that allows you to easily promote your Android or iOS apps across Google's top properties including Search, Play, YouTube, and the Google Display Network. This guide shows how to create one, set targeting, and run reports.

Constructing a campaign

1. Create a budget

To create an App Campaign, start by creating a budget. These campaigns don't support shared budgets, so you need to set the budget's isExplicitlyShared property to false.

Java

// Get the BudgetService.
BudgetServiceInterface budgetService =
    adWordsServices.get(session, BudgetServiceInterface.class);

// Create the campaign budget.
Budget budget = new Budget();
budget.setName("Interplanetary Cruise App Budget #" + System.currentTimeMillis());
Money budgetAmount = new Money();
budgetAmount.setMicroAmount(50000000L);
budget.setAmount(budgetAmount);
budget.setDeliveryMethod(BudgetBudgetDeliveryMethod.STANDARD);

// Universal app campaigns don't support shared budgets.
budget.setIsExplicitlyShared(false);
BudgetOperation budgetOperation = new BudgetOperation();
budgetOperation.setOperand(budget);
budgetOperation.setOperator(Operator.ADD);

// Add the budget
Budget addedBudget = budgetService.mutate(new BudgetOperation[] {budgetOperation}).getValue(0);
    

C#

// Get the BudgetService.
using (BudgetService budgetService =
    (BudgetService) user.GetService(AdWordsService.v201809.BudgetService))
{
    // Create the campaign budget.
    Budget budget = new Budget
    {
        name =
            "Interplanetary Cruise App Budget #" + ExampleUtilities.GetRandomString(),
        deliveryMethod = BudgetBudgetDeliveryMethod.STANDARD,
        amount = new Money
        {
            microAmount = 5000000
        },

        // Universal app campaigns don't support shared budgets.
        isExplicitlyShared = false
    };

    BudgetOperation budgetOperation = new BudgetOperation
    {
        @operator = Operator.ADD,
        operand = budget
    };

    BudgetReturnValue budgetRetval = budgetService.mutate(new BudgetOperation[]
    {
        budgetOperation
    });
    

Python

budget_service = client.GetService('BudgetService', version='v201809')

# Create a budget.
budget = {
    'name': 'Interplanetary Cruise App Budget #%s' % uuid.uuid4(),
    'amount': {
        'microAmount': '50000000'
    },
    'deliveryMethod': 'STANDARD',
    'isExplicitlyShared': False
}

budget_operations = [{
    'operator': 'ADD',
    'operand': budget
}]

# Create the budget and return its ID.
budget_id = budget_service.mutate(budget_operations)['value'][0]['budgetId']
    

PHP

$budgetService = $adWordsServices->get($session, BudgetService::class);

// Create the shared budget (required).
$budget = new Budget();
$budget->setName('Interplanetary Cruise Budget #' . uniqid());
$money = new Money();
$money->setMicroAmount(50000000);
$budget->setAmount($money);
$budget->setDeliveryMethod(BudgetBudgetDeliveryMethod::STANDARD);

// Universal App campaigns don't support shared budgets.
$budget->setIsExplicitlyShared(false);
$operations = [];

// Create a budget operation.
$operation = new BudgetOperation();
$operation->setOperand($budget);
$operation->setOperator(Operator::ADD);
$operations[] = $operation;

// Create the budget on the server.
$result = $budgetService->mutate($operations);
$budget = $result->getValue()[0];

printf(
    "Budget with name '%s' and ID %d was created.\n",
    $budget->getName(),
    $budget->getBudgetId()
);

    

Perl

# Create the campaign budget.
my $budget = Google::Ads::AdWords::v201809::Budget->new({
  # Required attributes.
  name => "Interplanetary Cruise App Budget #" . uniqid(),
  amount =>
    Google::Ads::AdWords::v201809::Money->new({microAmount => 5000000}),
  deliveryMethod => "STANDARD",
  # Universal app campaigns don't support shared budgets.
  isExplicitlyShared => 0
});

my $budget_operation = Google::Ads::AdWords::v201809::BudgetOperation->new({
  operator => "ADD",
  operand  => $budget
});

# Add budget.
my $addedBudget =
  $client->BudgetService()->mutate({operations => ($budget_operation)})
  ->get_value();
printf
  "Budget with name '%s' and ID %d was created.\n",
  $addedBudget->get_name(), $addedBudget->get_budgetId()->get_value();
    

Ruby

# Create a budget.
budget = {
  :name => 'Interplanetary budget #%d' % (Time.new.to_f * 1000).to_i,
  :amount => {:micro_amount => 50000000},
  :delivery_method => 'STANDARD',
  # Universal app campaigns don't support shared budgets.
  :is_explicitly_shared => false
}
budget_operation = {:operator => 'ADD', :operand => budget}

# Add the budget.
return_budget = budget_srv.mutate([budget_operation])
budget_id = return_budget[:value].first[:budget_id]
    

See our Campaign Budgets guide for more details.

2. Create the campaign

Next, create your campaign. You need to keep the following restrictions in mind when creating an App Campaign:

  1. The campaign's advertisingChannelType must be set to MULTI_CHANNEL and advertisingChannelSubType to UNIVERSAL_APP_CAMPAIGN.
  2. Only the TARGET_CPA bidding strategy type is supported.
  3. Many of the settings in normal campaigns like networkSetting, frequencyCap and trackingUrlTemplate cannot be set for App Campaigns. See the reference docs for a full list of settings that cannot be set.
  4. For version v201082 and later, you need to specify the appVendor property when creating the campaign's universalAppSetting. This property's value is inferred in older versions based on the appId property.

Java

// Get the CampaignService.
CampaignServiceInterface campaignService =
    adWordsServices.get(session, CampaignServiceInterface.class);

// Create the campaign.
Campaign campaign = new Campaign();
campaign.setName("Interplanetary Cruise App #" + System.currentTimeMillis());

// Recommendation: Set the campaign to PAUSED when creating it to prevent
// the ads from immediately serving. Set to ENABLED once you've added
// targeting and the ads are ready to serve.
campaign.setStatus(CampaignStatus.PAUSED);

// Set the advertising channel and subchannel types for universal app campaigns.
campaign.setAdvertisingChannelType(AdvertisingChannelType.MULTI_CHANNEL);
campaign.setAdvertisingChannelSubType(AdvertisingChannelSubType.UNIVERSAL_APP_CAMPAIGN);

// Set the campaign's bidding strategy. universal app campaigns
// only support TARGET_CPA bidding strategy.
BiddingStrategyConfiguration biddingConfig = new BiddingStrategyConfiguration();
biddingConfig.setBiddingStrategyType(BiddingStrategyType.TARGET_CPA);

// Set the target CPA to $1 / app install.
TargetCpaBiddingScheme biddingScheme = new TargetCpaBiddingScheme();
biddingScheme.setTargetCpa(new Money());
biddingScheme.getTargetCpa().setMicroAmount(1000000L);

biddingConfig.setBiddingScheme(biddingScheme);
campaign.setBiddingStrategyConfiguration(biddingConfig);

// Set the campaign's budget.
campaign.setBudget(new Budget());
campaign.getBudget().setBudgetId(createBudget(adWordsServices, session));

// Optional: Set the start date.
campaign.setStartDate(new DateTime().plusDays(1).toString("yyyyMMdd"));

// Optional: Set the end date.
campaign.setEndDate(new DateTime().plusYears(1).toString("yyyyMMdd"));
    

C#

using (CampaignService campaignService =
    (CampaignService) user.GetService(AdWordsService.v201809.CampaignService))
{
    // Create the campaign.
    Campaign campaign = new Campaign
    {
        name = "Interplanetary Cruise App #" + ExampleUtilities.GetRandomString(),

        // Recommendation: Set the campaign to PAUSED when creating it to prevent
        // the ads from immediately serving. Set to ENABLED once you've added
        // targeting and the ads are ready to serve.
        status = CampaignStatus.PAUSED,

        // Set the advertising channel and subchannel types for universal app campaigns.
        advertisingChannelType = AdvertisingChannelType.MULTI_CHANNEL,
        advertisingChannelSubType = AdvertisingChannelSubType.UNIVERSAL_APP_CAMPAIGN
    };

    // Set the campaign's bidding strategy. Universal app campaigns
    // only support TARGET_CPA bidding strategy.
    BiddingStrategyConfiguration biddingConfig = new BiddingStrategyConfiguration
    {
        biddingStrategyType = BiddingStrategyType.TARGET_CPA
    };

    // Set the target CPA to $1 / app install.
    TargetCpaBiddingScheme biddingScheme = new TargetCpaBiddingScheme
    {
        targetCpa = new Money
        {
            microAmount = 1000000
        }
    };

    biddingConfig.biddingScheme = biddingScheme;
    campaign.biddingStrategyConfiguration = biddingConfig;

    // Set the campaign's budget.
    campaign.budget = new Budget
    {
        budgetId = CreateBudget(user).budgetId
    };

    // Optional: Set the start date.
    campaign.startDate = DateTime.Now.AddDays(1).ToString("yyyyMMdd");

    // Optional: Set the end date.
    campaign.endDate = DateTime.Now.AddYears(1).ToString("yyyyMMdd");
    

Python

# Initialize appropriate services.
campaign_service = client.GetService('CampaignService', version='v201809')

budget_id = CreateBudget(client)

# Create the Universal App campaign.
universal_app_campaign = {
    'name': 'Interplanetary Cruise App #%s' % uuid.uuid4(),
    # Recommendation: Set the campaign to PAUSED when creating it to stop the
    # ads from immediately serving. Set to ENABLED once you've added targeting
    # and the ads are ready to serve.
    'status': 'PAUSED',
    'advertisingChannelType': 'MULTI_CHANNEL',
    'advertisingChannelSubType': 'UNIVERSAL_APP_CAMPAIGN',
    # Set the campaign's bidding strategy. Universal app campaigns only
    # support TARGET_CPA bidding strategy.
    'biddingStrategyConfiguration': {
        # Set the target CPA to $1 / app install.
        'biddingScheme': {
            'xsi_type': 'TargetCpaBiddingScheme',
            'targetCpa': {
                'microAmount': '1000000'
            }
        },
        'biddingStrategyType': 'TARGET_CPA'
    },
    # Note that only the budgetId is required
    'budget': {
        'budgetId': budget_id
    },
    # Optional fields
    'startDate': (datetime.datetime.now() +
                  datetime.timedelta(1)).strftime('%Y%m%d'),
    'endDate': (datetime.datetime.now() +
                datetime.timedelta(365)).strftime('%Y%m%d'),
}
    

PHP

$campaignService = $adWordsServices->get($session, CampaignService::class);

// Create campaign with some properties set.
$campaign = new Campaign();
$campaign->setName('Interplanetary Cruise #' . uniqid());
// Recommendation: Set the campaign to PAUSED when creating it to stop
// the ads from immediately serving. Set to ENABLED once you've added
// targeting and the ads are ready to serve.
$campaign->setStatus(CampaignStatus::PAUSED);

// Set the advertising channel and subchannel types for Universal app
// campaigns.
$campaign->setAdvertisingChannelType(AdvertisingChannelType::MULTI_CHANNEL);
$campaign->setAdvertisingChannelSubType(
    AdvertisingChannelSubType::UNIVERSAL_APP_CAMPAIGN
);

// Set the campaign's bidding strategy. Universal App campaigns
// only support TARGET_CPA bidding strategy.
$biddingStrategyConfiguration = new BiddingStrategyConfiguration();
$biddingStrategyConfiguration->setBiddingStrategyType(
    BiddingStrategyType::TARGET_CPA
);

// Set the target CPA to $1 / app install.
$biddingScheme = new TargetCpaBiddingScheme();
$money = new Money();
$money->setMicroAmount(1000000);
$biddingScheme->setTargetCpa($money);

$biddingStrategyConfiguration->setBiddingScheme($biddingScheme);
$campaign->setBiddingStrategyConfiguration($biddingStrategyConfiguration);

// Set shared budget (required).
$campaign->setBudget(new Budget());
$campaign->getBudget()->setBudgetId(
    self::createBudget($adWordsServices, $session)
);

// Optional: Set the start date.
$campaign->setStartDate(date('Ymd', strtotime('+1 day')));

// Optional: Set the end date.
$campaign->setEndDate(date('Ymd', strtotime('+1 year')));
    

Perl

my (undef, undef, undef, $mday, $mon, $year) = localtime(time + 60 * 60 * 24);
my $start_date = sprintf("%d%02d%02d", ($year + 1900), ($mon + 1), $mday);
(undef, undef, undef, $mday, $mon, $year) =
  localtime(time + 60 * 60 * 24 * 365);
my $end_date = sprintf("%d%02d%02d", ($year + 1900), ($mon + 1), $mday);

my $budgetId = create_budget($client);

my $campaign = Google::Ads::AdWords::v201809::Campaign->new({
    name => "Interplanetary Cruise App #" . uniqid(),
    # Bidding strategy (required).
    # Set the campaign's bidding strategy. Universal app campaigns
    # only support TARGET_CPA bidding strategy.
    biddingStrategyConfiguration =>
      Google::Ads::AdWords::v201809::BiddingStrategyConfiguration->new({
        biddingStrategyType => "TARGET_CPA",
        # Set the target CPA to $1 / app install.
        biddingScheme =>
          Google::Ads::AdWords::v201809::TargetCpaBiddingScheme->new({
            targetCpa => Google::Ads::AdWords::v201809::Money->new(
              {microAmount => 1000000})})}
      ),
    # Budget (required) - note only the budgetId is required.
    budget =>
      Google::Ads::AdWords::v201809::Budget->new({budgetId => $budgetId}),
    # Advertising channel type (required).
    # Set the advertising channel and subchannel types for universal
    # app campaigns.
    advertisingChannelType    => "MULTI_CHANNEL",
    advertisingChannelSubType => "UNIVERSAL_APP_CAMPAIGN",
    settings                  => [$universalAppSetting, $geoSetting],
    # Additional properties (non-required).
    startDate => $start_date,
    endDate   => $end_date,
    # Recommendation: Set the campaign to PAUSED when creating it to stop
    # the ads from immediately serving. Set to ENABLED once you've added
    # targeting and the ads are ready to serve.
    status    => "PAUSED"
  });
    

Ruby

campaign_srv = adwords.service(:CampaignService, API_VERSION)
budget_srv = adwords.service(:BudgetService, API_VERSION)

# Create a budget.
budget = {
  :name => 'Interplanetary budget #%d' % (Time.new.to_f * 1000).to_i,
  :amount => {:micro_amount => 50000000},
  :delivery_method => 'STANDARD',
  # Universal app campaigns don't support shared budgets.
  :is_explicitly_shared => false
}
budget_operation = {:operator => 'ADD', :operand => budget}

# Add the budget.
return_budget = budget_srv.mutate([budget_operation])
budget_id = return_budget[:value].first[:budget_id]

# Create campaigns.
universal_app_campaign = {
  :name => "Interplanetary Cruise #%d" % (Time.new.to_f * 1000).to_i,
  # Recommendation: Set the campaign to PAUSED when creating it to stop the
  # ads from immediately serving. Set it to ENABLED once you've added
  # targeting and the ads are ready to serve.
  :status => 'PAUSED',
  # Set the advertising channel and subchannel types for universal app
  # campaigns.
  :advertising_channel_type => 'MULTI_CHANNEL',
  :advertising_channel_sub_type => 'UNIVERSAL_APP_CAMPAIGN',
  # Set the campaign's bidding strategy. Universal app campaigns only support
  # the TARGET_CPA bidding strategy.
  :bidding_strategy_configuration => {
    :bidding_scheme => {
      :xsi_type => 'TargetCpaBiddingScheme',
      :target_cpa => {
        :micro_amount => 1000000
      }
    }
  },
  # Budget (required) - note only the budget ID is required.
  :budget => {:budget_id => budget_id},
  # Optional fields:
  :start_date =>
      DateTime.parse((Date.today + 1).to_s).strftime('%Y%m%d'),
  :end_date =>
      DateTime.parse((Date.today + 365).to_s).strftime('%Y%m%d')
}
    

3. Customize your ads

Unlike other campaign types, App Campaigns don't allow users to create ads. Instead, ads are generated across several formats and networks based on your app's store listing, additional text ideas, and assets you specify in the campaign's settings. The following snippet shows how to set your campaign's assets.

Java

// Set the campaign's assets and ad text ideas. These values will be used to
// generate ads.
UniversalAppCampaignSetting universalAppSetting = new UniversalAppCampaignSetting();
universalAppSetting.setAppId("com.labpixies.colordrips");
universalAppSetting.setAppVendor(MobileApplicationVendor.VENDOR_GOOGLE_MARKET);
universalAppSetting.setDescription1("A cool puzzle game");
universalAppSetting.setDescription2("Remove connected blocks");
universalAppSetting.setDescription3("3 difficulty levels");
universalAppSetting.setDescription4("4 colorful fun skins");

// Optional: You can set up to 20 image assets for your campaign.
// See UploadImage.java for an example on how to upload images.
//
// universalAppSetting.setImageMediaIds(new long[] { INSERT_IMAGE_MEDIA_ID_HERE });
    

C#

// Set the campaign's assets and ad text ideas. These values will be used to
// generate ads.
UniversalAppCampaignSetting universalAppSetting = new UniversalAppCampaignSetting
{
    appId = "com.labpixies.colordrips",
    appVendor = MobileApplicationVendor.VENDOR_GOOGLE_MARKET,
    description1 = "A cool puzzle game",
    description2 = "Remove connected blocks",
    description3 = "3 difficulty levels",
    description4 = "4 colorful fun skins",

    // Optional: You can set up to 20 image assets for your campaign.
    // See UploadImage.cs for an example on how to upload images.
    //
    // universalAppSetting.imageMediaIds =
    //     new long[] { INSERT_IMAGE_MEDIA_ID_HERE };
    

Python

universal_app_campaign['settings'] = [
    # Set the campaign's assets and ad text ideas. These values will
    # be used to generate ads.
    {
        'xsi_type': 'UniversalAppCampaignSetting',
        'appId': 'com.labpixies.colordrips',
        'appVendor': 'VENDOR_GOOGLE_MARKET',
        'description1': 'A cool puzzle game',
        'description2': 'Remove connected blocks',
        'description3': '3 difficulty levels',
        'description4': '4 colorful fun skins',
        # Optional: You can set up to 20 image assets for your campaign.
        # See upload_image.py for an example on how to upload images.
        #
        # 'imageMediaIds': [INSERT_IMAGE_MEDIA_ID(s)_HERE]
    }
]
    

PHP

// Set the campaign's assets and ad text ideas. These values will be used to
// generate ads.
$universalAppSetting = new UniversalAppCampaignSetting();
$universalAppSetting->setAppId('com.labpixies.colordrips');
$universalAppSetting->setAppVendor(
    MobileApplicationVendor::VENDOR_GOOGLE_MARKET
);
$universalAppSetting->setDescription1('A cool puzzle game');
$universalAppSetting->setDescription2('Remove connected blocks');
$universalAppSetting->setDescription3('3 difficulty levels');
$universalAppSetting->setDescription4('4 colorful fun skins');

// Optional: You can set up to 20 image assets for your campaign.
// See UploadImage.php for an example on how to upload images.
//
// $universalAppSetting->imageMediaIds = [INSERT_IMAGE_MEDIA_ID_HERE];
    

Perl

# Set the campaign's assets and ad text ideas. These values will be used to
# generate ads.
my $universalAppSetting =
  Google::Ads::AdWords::v201809::UniversalAppCampaignSetting->new({
    appId        => "com.labpixies.colordrips",
    appVendor    => "VENDOR_GOOGLE_MARKET",
    description1 => "A cool puzzle game",
    description2 => "Remove connected blocks",
    description3 => "3 difficulty levels",
    description4 => "4 colorful fun skins"
  });

# Optional: You can set up to 20 image assets for your campaign.
# See upload_image.pl for an example on how to upload images.
# universalAppSetting->set_imageMediaIds([INSERT_IMAGE_MEDIA_ID_HERE]);
    

Ruby

universal_app_setting = {
  # Set the campaign's assets and ad text ideas. These values will be used to
  # generate ads.
  :xsi_type => 'UniversalAppCampaignSetting',
  :app_id => 'com.labpixies.colordrips',
  :app_vendor => 'VENDOR_GOOGLE_MARKET',
  :description1 => 'A cool puzzle game',
  :description2 => 'Remove connected blocks',
  :description3 => '3 difficulty levels',
  :description4 => '4 colorful fun skins'
  # Optional: You can set up to 20 image assets for your campaign. See
  # upload_image.rb for an example on how to upload images.
  #
  # :image_media_ids => [INSERT_IMGAGE_MEDIA_ID(s)_HERE]
}
    

4. Optimize your campaign

You can optimize your campaign using two settings:

  • universalAppBiddingStrategyGoalType allows you to specify a goal type when optimizing the campaign's bidding strategy.

  • When you select your bidding strategy goal type as OPTIMIZE_FOR_INSTALL_CONVERSION_VOLUME, you can also optimize for a set of in-app conversion types using the campaign's selectiveOptimization field . You can use the ConversionTrackerService to retrieve the list of all the conversion trackers.

Java

// Optimize this campaign for getting new users for your app.
universalAppSetting.setUniversalAppBiddingStrategyGoalType(
    UniversalAppBiddingStrategyGoalType.OPTIMIZE_FOR_INSTALL_CONVERSION_VOLUME);

// If you select the OPTIMIZE_FOR_IN_APP_CONVERSION_VOLUME goal type, then also specify
// your in-app conversion types so AdWords can focus your campaign on people who are
// most likely to complete the corresponding in-app actions.
// Conversion type IDs can be retrieved using ConversionTrackerService.get.
//
// campaign.selectiveOptimization = new SelectiveOptimization();
// campaign.selectiveOptimization.conversionTypeIds =
//    new long[] { INSERT_CONVERSION_TYPE_ID_1_HERE, INSERT_CONVERSION_TYPE_ID_2_HERE };

// Optional: Set the campaign settings for Advanced location options.
GeoTargetTypeSetting geoSetting = new GeoTargetTypeSetting();
geoSetting.setPositiveGeoTargetType(
    GeoTargetTypeSettingPositiveGeoTargetType.LOCATION_OF_PRESENCE);
geoSetting.setNegativeGeoTargetType(GeoTargetTypeSettingNegativeGeoTargetType.DONT_CARE);

campaign.setSettings(new Setting[] {universalAppSetting, geoSetting});
    

C#

    // Optimize this campaign for getting new users for your app.
    universalAppBiddingStrategyGoalType = UniversalAppBiddingStrategyGoalType
        .OPTIMIZE_FOR_INSTALL_CONVERSION_VOLUME
};

// Optional: If you select the OPTIMIZE_FOR_IN_APP_CONVERSION_VOLUME goal
// type, then also specify your in-app conversion types so AdWords can
// focus your campaign on people who are most likely to complete the
// corresponding in-app actions.
// Conversion type IDs can be retrieved using ConversionTrackerService.get.
//
// campaign.selectiveOptimization = new SelectiveOptimization();
// campaign.selectiveOptimization.conversionTypeIds = new long[]
//     {
//         INSERT_CONVERSION_TYPE_ID_1_HERE,
//         INSERT_CONVERSION_TYPE_ID_2_HERE
//     };

// Optional: Set the campaign settings for Advanced location options.
GeoTargetTypeSetting geoSetting = new GeoTargetTypeSetting
{
    positiveGeoTargetType =
        GeoTargetTypeSettingPositiveGeoTargetType.LOCATION_OF_PRESENCE,
    negativeGeoTargetType = GeoTargetTypeSettingNegativeGeoTargetType.DONT_CARE
};

campaign.settings = new Setting[]
{
    universalAppSetting,
    geoSetting
};
    

Python

# Optimize this campaign for getting new users for your app.
universal_app_campaign_setting = universal_app_campaign['settings'][0]
universal_app_campaign_setting['universalAppBiddingStrategyGoalType'] = (
    'OPTIMIZE_FOR_INSTALL_CONVERSION_VOLUME')

# Optional: If you select the OPTIMIZE_FOR_IN_APP_CONVERSION_VOLUME goal type,
# then also specify your in-app conversion types so AdWords can focus your
# campaign on people who are most likely to complete the corresponding in-app
# actions.
#
# Conversions type IDs can be retrieved using ConversionTrackerService.get.
# universal_app_campaign['selectiveOptimization'] = {
#     'conversionTypeIds': [INSERT_CONVERSION_TYPE_ID(s)_HERE]
# }

# Optional: Set the campaign settings for Advanced location options.
universal_app_campaign['settings'].append({
    'xsi_type': 'GeoTargetTypeSetting',
    'positiveGeoTargetType': 'DONT_CARE',
    'negativeGeoTargetType': 'DONT_CARE'
})
    

PHP

// Optimize this campaign for getting new users for your app.
$universalAppSetting->setUniversalAppBiddingStrategyGoalType(
    UniversalAppBiddingStrategyGoalType
    ::OPTIMIZE_FOR_INSTALL_CONVERSION_VOLUME
);

// If you select bidding strategy goal type as
// OPTIMIZE_FOR_IN_APP_CONVERSION_VOLUME, then you may specify a set of
// conversion types for in-app actions to optimize the campaign towards.
// Conversion type IDs can be retrieved using ConversionTrackerService.get.
//
// $campaign->selectiveOptimization = new SelectiveOptimization();
// $campaign->selectiveOptimization->conversionTypeIds = [
//     INSERT_CONVERSION_TYPE_ID_1_HERE,
//     INSERT_CONVERSION_TYPE_ID_2_HERE
// ];

// Optional: Set the campaign settings for Advanced location options.
$geoTargetTypeSetting = new GeoTargetTypeSetting();
$geoTargetTypeSetting->setNegativeGeoTargetType(
    GeoTargetTypeSettingNegativeGeoTargetType::LOCATION_OF_PRESENCE
);
$campaign->setSettings([$universalAppSetting, $geoTargetTypeSetting]);
    

Perl

# Optimize this campaign for getting new users for your app.
$universalAppSetting->set_universalAppBiddingStrategyGoalType(
  "OPTIMIZE_FOR_INSTALL_CONVERSION_VOLUME");

# If you select the OPTIMIZE_FOR_IN_APP_CONVERSION_VOLUME goal type, then also
# specify your in-app conversion types so AdWords can focus your campaign on
# people who are most likely to complete the corresponding in-app actions.
# Conversion type IDs can be retrieved using ConversionTrackerService.get.

# my $selectiveOptimization =
# Google::Ads::AdWords::v201809::SelectiveOptimization->new({
#  conversionTypeIds =>
#    [INSERT_CONVERSION_TYPE_ID_1_HERE, INSERT_CONVERSION_TYPE_ID_2_HERE]
# });
# $campaign->set_selectiveOptimization($selectiveOptimization);

# Optional: Set the campaign settings for advanced location options.
my $geoSetting = Google::Ads::AdWords::v201809::GeoTargetTypeSetting->new({
  positiveGeoTargetType => "LOCATION_OF_PRESENCE",
  negativeGeoTargetType => "DONT_CARE"
});
    

Ruby

# Optimize this campaign for getting new users for your app.
universal_app_setting[:universal_app_bidding_strategy_goal_type] =
    'OPTIMIZE_FOR_INSTALL_CONVERSION_VOLUME'

# Optional: If you select OPTIMIZE_FOR_IN_APP_CONVERSION_VOLUME goal type,
# then also specify your in-app conversion types so AdWords can focus your
# campaign on people who are most likely to complete the corresponding in-app
# actions.
# Conversion type IDs can be retrieved using ConversionTrackerService.get.
#
# universal_app_campaign[:selective_optimization] = {
#   :conversion_type_ids => [INSERT_CONVERSION_TYPE_ID(s)_HERE]
# }

# Optional: Set the campaign settings for Advanced location options.
geo_setting = {
  :xsi_type => 'GeoTargetTypeSetting',
  :positive_geo_target_type => 'DONT_CARE',
  :negative_geo_target_type => 'DONT_CARE'
}

universal_app_campaign[:settings] = [
  universal_app_setting,
  geo_setting
]
    

Finally, create your campaign using the CampaignService.mutate method:

Java

// Create the operation.
CampaignOperation operation = new CampaignOperation();
operation.setOperand(campaign);
operation.setOperator(Operator.ADD);

CampaignOperation[] operations = new CampaignOperation[] {operation};

// Add the campaign.
CampaignReturnValue result = campaignService.mutate(operations);

// Display the results.
for (Campaign newCampaign : result.getValue()) {
  System.out.printf(
      "Universal app campaign with name '%s' and ID %d was added.%n",
      newCampaign.getName(), newCampaign.getId());

  // Optional: Set the campaign's location and language targeting. No other targeting
  // criteria can be used for universal app campaigns.
  setCampaignTargetingCriteria(newCampaign, adWordsServices, session);
}
    

C#

    // Create the operation.
    CampaignOperation operation = new CampaignOperation
    {
        @operator = Operator.ADD,
        operand = campaign
    };

    try
    {
        // Add the campaign.
        CampaignReturnValue retVal = campaignService.mutate(new CampaignOperation[]
        {
            operation
        });

        // Display the results.
        if (retVal != null && retVal.value != null && retVal.value.Length > 0)
        {
            foreach (Campaign newCampaign in retVal.value)
            {
                Console.WriteLine(
                    "Universal app campaign with name = '{0}' and id = '{1}' " +
                    "was added.", newCampaign.name, newCampaign.id);

                // Optional: Set the campaign's location and language targeting.
                // No other targeting criteria can be used for universal app campaigns.
                SetCampaignTargetingCriteria(user, newCampaign);
            }
        }
        else
        {
            Console.WriteLine("No universal app campaigns were added.");
        }
    }
    catch (Exception e)
    {
        throw new System.ApplicationException("Failed to add universal app campaigns.",
            e);
    }
}

    

Python

# Construct operations and add campaigns.
operations = [{
    'operator': 'ADD',
    'operand': universal_app_campaign
}]

campaigns = campaign_service.mutate(operations)['value']
    

PHP

// Create a campaign operation and add it to the operations list.
$operations = [];
$operation = new CampaignOperation();
$operation->setOperand($campaign);
$operation->setOperator(Operator::ADD);
$operations[] = $operation;

// Create the campaign on the server and print out some information for the
// campaign.
$result = $campaignService->mutate($operations);
foreach ($result->getValue() as $campaign) {
    printf(
        "Universal App Campaign with name '%s' and ID %d was added.\n",
        $campaign->getName(),
        $campaign->getId()
    );
    // Optional: Set the campaign's location and language targeting. No other
    // targeting criteria can be used for Universal App campaigns.
    self::setCampaignTargetingCriteria(
        $campaign->getId(),
        $adWordsServices,
        $session
    );
}
    

Perl

# Create operation.
my $campaign_operation =
  Google::Ads::AdWords::v201809::CampaignOperation->new({
    operator => "ADD",
    operand  => $campaign
  });

# Add campaigns.
my $result =
  $client->CampaignService()->mutate({operations => [$campaign_operation]});

# Display campaigns.
foreach my $new_campaign (@{$result->get_value()}) {
  printf "Universal app campaign with name \"%s\" and ID %s was added.\n",
    $new_campaign->get_name(), $new_campaign->get_id();
  # Optional: Set the campaign's location and language targeting. No other
  # targeting criteria can be used for universal app campaigns.
  set_campaign_targeting_criteria($client, $new_campaign->get_id());
}
    

Ruby

  # Construct the operation and add the campaign.
  operations = [{
    :operator => 'ADD',
    :operand => universal_app_campaign
  }]

  campaigns = campaign_srv.mutate(operations)[:value]

  if campaigns
    campaigns.each do |campaign|
      puts "Universal app campaign with name '%s' and ID %d was added." %
          [campaign[:name], campaign[:id]]
      set_campaign_targeting_criteria(adwords, campaign)
    end
  else
    raise new StandardError, 'No universal app campaigns were added.'
  end
end

def set_campaign_targeting_criteria(adwords, campaign)
  campaign_criterion_service =
      adwords.service(:CampaignCriterionService, API_VERSION)

  criteria = [
    {
      :xsi_type => 'Location',
      :id => 21137 # California
    },
    {
      :xsi_type => 'Location',
      :id => 2484 # Mexico
    },
    {
      :xsi_type => 'Language',
      :id => 1000 # English
    },
    {
      :xsi_type => 'Language',
      :id => 1003 # Spanish
    }
  ]

  operations = criteria.map do |criterion|
    {
      :operator => 'ADD',
      :operand => {
        :campaign_id => campaign[:id],
        :criterion => criterion
      }
    }
  end

  response = campaign_criterion_service.mutate(operations)

  if response and response[:value]
    # Display the added campaign targets.
    response[:value].each do |criterion|
      puts 'Campaign criteria of type "%s" and id %d was added.' % [
          criterion[:criterion][:criterion_type],
          criterion[:criterion][:id]
      ]
    end
  end
end

if __FILE__ == $0
  API_VERSION = :v201809

  begin
    add_universal_app_campaigns()

  # Authorization error.
  rescue AdsCommon::Errors::OAuth2VerificationRequired => e
    puts "Authorization credentials are not valid. Edit adwords_api.yml for " +
        "OAuth2 client ID and secret and run misc/setup_oauth2.rb example " +
        "to retrieve and store OAuth2 tokens."
    puts "See this wiki page for more details:\n\n  " +
        'https://github.com/googleads/google-api-ads-ruby/wiki/OAuth2'

  # HTTP errors.
  rescue AdsCommon::Errors::HttpError => e
    puts "HTTP Error: %s" % e

  # API errors.
  rescue AdwordsApi::Errors::ApiException => e
    puts "Message: %s" % e.message
    puts 'Errors:'
    e.errors.each_with_index do |error, index|
      puts "\tError [%d]:" % (index + 1)
      error.each do |field, value|
        puts "\t\t%s: %s" % [field, value]
      end
    end
  end
end

    

Uploading media

You can specify up to 20 image assets for an App Campaign. These assets will be used by Google Ads to create ads. You can use the MediaService.upload method to upload images.

Java

MediaServiceInterface mediaService =
    adWordsServices.get(session, MediaServiceInterface.class);

// Create image.
Image image = new Image();
image.setData(
    com.google.api.ads.common.lib.utils.Media.getMediaDataFromUrl("https://goo.gl/3b9Wfh"));
image.setType(MediaMediaType.IMAGE);

Media[] media = new Media[] {image};

// Upload image.
Media[] result = mediaService.upload(media);
    

C#

using (MediaService mediaService =
    (MediaService) user.GetService(AdWordsService.v201809.MediaService))
{
    // Create the image.
    Image image = new Image
    {
        data = MediaUtilities.GetAssetDataFromUrl("https://goo.gl/3b9Wfh", user.Config),
        type = MediaMediaType.IMAGE
    };

    try
    {
        // Upload the image.
        Media[] result = mediaService.upload(new Media[]
        {
            image
        });
    

Python

media_service = client.GetService('MediaService', version='v201809')

with open(image_filename, 'rb') as image_handle:
  image_data = image_handle.read().decode('utf-8')

# Construct media and upload image.
media = [{
    'xsi_type': 'Image',
    'data': image_data,
    'type': 'IMAGE'
}]
media = media_service.upload(media)[0]
    

PHP

$mediaService = $adWordsServices->get($session, MediaService::class);

// Create an image and add it to the images list.
$image = new Image();
$image->setData(file_get_contents('http://goo.gl/HJM3L'));
$image->setType(MediaMediaType::IMAGE);
$images = [$image];

// Upload the image to the server.
$result = $mediaService->upload($images);
    

Perl

# Create image.
my $image_data = Google::Ads::Common::MediaUtils::get_base64_data_from_url(
  "https://goo.gl/3b9Wfh");
my $image = Google::Ads::AdWords::v201809::Image->new({
    data => $image_data,
    type => "IMAGE"
  }
);

# Upload image.
$image = $client->MediaService()->upload({media => [$image]});
    

Ruby

media_srv = adwords.service(:MediaService, API_VERSION)

# This utility method retrieves the contents of a URL using all of the config
# options provided to the Api object.
image_url = 'https://goo.gl/3b9Wfh'
image_data = AdsCommon::Http.get(image_url, adwords.config)
base64_image_data = Base64.encode64(image_data)

# Create image.
image = {
  # The 'xsi_type' field allows you to specify the xsi:type of the object
  # being created. It's only necessary when you must provide an explicit
  # type that the client library can't infer.
  :xsi_type => 'Image',
  :data => base64_image_data,
  :type => 'IMAGE'
}

# Upload image.
response = media_srv.upload([image])
    

Working with ListOperations

App Campaigns use ListOperations to set list fields such as imageMediaIds. ListOperations describes the behavior of elements in a list, and will always be defined alongside some list in an API object (for example, imageMediaIdsOps describes how to update imageMediaIds). The number of operators in the ListOperations must be equal to the number of elements in the corresponding list. Each operator, together with its corresponding list element, describes an intended change.

Assume that imageMediaIds contained the initial values [1000, 1001, 1002]. The table below shows a mutate call to update imageMediaIds using ListOperations.

Item index Image Media ID ListOperation Meaning
0 1003 PUT Item ID `1003` is being added since it was missing from the original list.
1 1002 REMOVE Item ID `1002` is being removed.

imageMediaIds will contain values [1000, 1001, 1003] after the mutate call.

Targeting

App Campaigns support only two forms of targeting: language and location criteria at the campaign level. By default, the campaign targets all locations and all languages. The following code snippet targets the campaign for California and Mexico, for English and Spanish.

Java

// Get the CampaignCriterionService.
CampaignCriterionServiceInterface campaignCriterionService =
    adWordsServices.get(session, CampaignCriterionServiceInterface.class);

// Create locations. The IDs can be found in the documentation or
// retrieved with the LocationCriterionService.
Location california = new Location();
california.setId(21137L);

Location mexico = new Location();
mexico.setId(2484L);

// Create languages. The IDs can be found in the documentation or
// retrieved with the ConstantDataService.
Language english = new Language();
english.setId(1000L);

Language spanish = new Language();
spanish.setId(1003L);

List<Criterion> criteria = new ArrayList<>(Arrays.asList(california, mexico, english, spanish));

// Create operations to add each of the criteria above.
List<CampaignCriterionOperation> operations = new ArrayList<>();
for (Criterion criterion : criteria) {
  CampaignCriterionOperation operation = new CampaignCriterionOperation();

  CampaignCriterion campaignCriterion = new CampaignCriterion();
  campaignCriterion.setCampaignId(campaign.getId());
  campaignCriterion.setCriterion(criterion);
  operation.setOperand(campaignCriterion);

  operation.setOperator(Operator.ADD);

  operations.add(operation);
}

// Set the campaign targets.
CampaignCriterionReturnValue returnValue =
    campaignCriterionService.mutate(
        operations.toArray(new CampaignCriterionOperation[operations.size()]));

if (returnValue != null && returnValue.getValue() != null) {
  // Display added campaign targets.
  for (CampaignCriterion campaignCriterion : returnValue.getValue()) {
    System.out.printf(
        "Campaign criteria of type '%s' and ID %d was added.%n",
        campaignCriterion.getCriterion().getCriterionType(),
        campaignCriterion.getCriterion().getId());
  }
}
    

C#

using (CampaignCriterionService campaignCriterionService =
    (CampaignCriterionService) user.GetService(AdWordsService.v201809
        .CampaignCriterionService))
{
    // Create locations. The IDs can be found in the documentation or
    // retrieved with the LocationCriterionService.
    Location california = new Location()
    {
        id = 21137L
    };

    Location mexico = new Location()
    {
        id = 2484L
    };

    // Create languages. The IDs can be found in the documentation or
    // retrieved with the ConstantDataService.
    Language english = new Language()
    {
        id = 1000L
    };

    Language spanish = new Language()
    {
        id = 1003L
    };

    List<Criterion> criteria = new List<Criterion>()
    {
        california,
        mexico,
        english,
        spanish
    };

    // Create operations to add each of the criteria above.
    List<CampaignCriterionOperation>
        operations = new List<CampaignCriterionOperation>();
    foreach (Criterion criterion in criteria)
    {
        CampaignCriterionOperation operation = new CampaignCriterionOperation()
        {
            operand = new CampaignCriterion()
            {
                campaignId = campaign.id,
                criterion = criterion
            },
            @operator = Operator.ADD
        };

        operations.Add(operation);
    }

    // Set the campaign targets.
    CampaignCriterionReturnValue retVal =
        campaignCriterionService.mutate(operations.ToArray());

    if (retVal != null && retVal.value != null)
    {
        // Display the added campaign targets.
        foreach (CampaignCriterion criterion in retVal.value)
        {
            Console.WriteLine("Campaign criteria of type '{0}' and id '{1}' was added.",
                criterion.criterion.CriterionType, criterion.criterion.id);
        }
    }
}

    

Python

campaign_criterion_service = client.GetService('CampaignCriterionService')

# Create locations. The IDs can be found in the documentation or retrieved
# with the LocationCriterionService.
criteria = [
    {
        'xsi_type': 'Location',
        'id': 21137  # California
    },
    {
        'xsi_type': 'Location',
        'id': 2484  # Mexico
    },
    {
        'xsi_type': 'Language',
        'id': 1000  # English
    },
    {
        'xsi_type': 'Language',
        'id': 1003  # Spanish
    }
]

operations = [{
    'operator': 'ADD',
    'operand': {
        'campaignId': campaign['id'],
        'criterion': criterion
    }
} for criterion in criteria]

response = campaign_criterion_service.mutate(operations)

if response and 'value' in response:
  # Display the added campaign targets.
  for criterion in response['value']:
    print('Campaign criteria of type "%s" and id "%s" was added.'
          % (criterion['criterion']['type'],
              criterion['criterion']['id']))
    

PHP

$campaignCriterionService = $adWordsServices->get($session, CampaignCriterionService::class);

$campaignCriteria = [];
// Create locations. The IDs can be found in the documentation or retrieved
// with the LocationCriterionService.
$california = new Location();
$california->setId(21137);
$campaignCriteria[] = new CampaignCriterion($campaignId, null, $california);

$mexico = new Location();
$mexico->setId(2484);
$campaignCriteria[] = new CampaignCriterion($campaignId, null, $mexico);

// Create languages. The IDs can be found in the documentation or retrieved
// with the ConstantDataService.
$english = new Language();
$english->setId(1000);
$campaignCriteria[] = new CampaignCriterion($campaignId, null, $english);

$spanish = new Language();
$spanish->setId(1003);
$campaignCriteria[] = new CampaignCriterion($campaignId, null, $spanish);

// Create operations to add each of the criteria above.
$operations = [];
foreach ($campaignCriteria as $campaignCriterion) {
    $operation = new CampaignCriterionOperation();
    $operation->setOperand($campaignCriterion);
    $operation->setOperator(Operator::ADD);
    $operations[] = $operation;
}

// Set the campaign targets.
$result = $campaignCriterionService->mutate($operations);

// Display added campaign targets.
foreach ($result->getValue() as $campaignCriterion) {
    printf(
        "Campaign criterion of type '%s' and ID %d was added.\n",
        $campaignCriterion->getCriterion()->getType(),
        $campaignCriterion->getCriterion()->getId()
    );
}
    

Perl

# Create locations. The IDs can be found in the documentation or retrieved
# with the LocationCriterionService.
my $california = Google::Ads::AdWords::v201809::Location->new({id => 21137});
push @criteria, $california;
my $mexico = Google::Ads::AdWords::v201809::Location->new({id => 2484});
push @criteria, $mexico;

# Create languages. The IDs can be found in the documentation or retrieved
# with the ConstantDataService.
my $english = Google::Ads::AdWords::v201809::Language->new({id => 1000});
push @criteria, $english;
my $spanish = Google::Ads::AdWords::v201809::Language->new({id => 1003});
push @criteria, $spanish;

# Create operations.
my @operations = ();
foreach my $criterion (@criteria) {
  my $operation =
    Google::Ads::AdWords::v201809::CampaignCriterionOperation->new({
      operator => "ADD",
      operand  => Google::Ads::AdWords::v201809::CampaignCriterion->new({
          campaignId => $campaign_id,
          criterion  => $criterion
        })});
  push @operations, $operation;
}

# Set campaign criteria.
my $result =
  $client->CampaignCriterionService()->mutate({operations => \@operations});

# Display campaign criteria.
if ($result->get_value()) {
  foreach my $campaign_criterion (@{$result->get_value()}) {
    printf "Campaign criterion of type '%s' and ID %s was added.\n",
      $campaign_criterion->get_criterion()->get_type(),
      $campaign_criterion->get_criterion()->get_id();
  }
}
    

Ruby

campaign_criterion_service =
    adwords.service(:CampaignCriterionService, API_VERSION)

criteria = [
  {
    :xsi_type => 'Location',
    :id => 21137 # California
  },
  {
    :xsi_type => 'Location',
    :id => 2484 # Mexico
  },
  {
    :xsi_type => 'Language',
    :id => 1000 # English
  },
  {
    :xsi_type => 'Language',
    :id => 1003 # Spanish
  }
]

operations = criteria.map do |criterion|
  {
    :operator => 'ADD',
    :operand => {
      :campaign_id => campaign[:id],
      :criterion => criterion
    }
  }
end

response = campaign_criterion_service.mutate(operations)

if response and response[:value]
  # Display the added campaign targets.
  response[:value].each do |criterion|
    puts 'Campaign criteria of type "%s" and id %d was added.' % [
        criterion[:criterion][:criterion_type],
        criterion[:criterion][:id]
    ]
  end
end
    

Reporting

App Campaign stats are available through Campaign Performance report; you can filter by the campaign's advertisingChannelType and advertisingChannelSubType as follows:

string query = "Select CampaignId, CampaignName, Clicks,
   Impressions, Cost from CAMPAIGN_PERFORMANCE_REPORT where
   AdvertisingChannelType = MULTI_CHANNEL and
   AdvertisingChannelSubType = UNIVERSAL_APP_CAMPAIGN during
   LAST_7_DAYS";

string fileName = ExampleUtilities.GetHomeDir() + Path.DirectorySeparatorChar +
    "CampaignPerformanceReport.gz";

ReportUtilities utilities = new ReportUtilities(user, "v201809", query,
    DownloadFormat.GZIPPED_CSV.ToString());
utilities.GetResponse().Save(fileName);

You can also get stats from the following reports:

Code examples

Complete code examples for adding an App Campaign are available in each client library:

Java

Add an App Campaign (Java)

C#

Add an App Campaign (C#)

Python

Add an App Campaign (Python)

PHP

Add an App Campaign (PHP)

Perl

Add an App Campaign (Perl)

Ruby

Add an App Campaign (Ruby)