Add App Campaign

Java

// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.ads.googleads.examples.advancedoperations;

import com.beust.jcommander.Parameter;
import com.google.ads.googleads.examples.utils.ArgumentNames;
import com.google.ads.googleads.examples.utils.CodeSampleParams;
import com.google.ads.googleads.lib.GoogleAdsClient;
import com.google.ads.googleads.v5.common.AdTextAsset;
import com.google.ads.googleads.v5.common.AppAdInfo;
import com.google.ads.googleads.v5.common.LanguageInfo;
import com.google.ads.googleads.v5.common.LocationInfo;
import com.google.ads.googleads.v5.common.TargetCpa;
import com.google.ads.googleads.v5.enums.AdGroupAdStatusEnum.AdGroupAdStatus;
import com.google.ads.googleads.v5.enums.AdGroupStatusEnum.AdGroupStatus;
import com.google.ads.googleads.v5.enums.AdvertisingChannelSubTypeEnum.AdvertisingChannelSubType;
import com.google.ads.googleads.v5.enums.AdvertisingChannelTypeEnum.AdvertisingChannelType;
import com.google.ads.googleads.v5.enums.AppCampaignAppStoreEnum.AppCampaignAppStore;
import com.google.ads.googleads.v5.enums.AppCampaignBiddingStrategyGoalTypeEnum.AppCampaignBiddingStrategyGoalType;
import com.google.ads.googleads.v5.enums.BudgetDeliveryMethodEnum.BudgetDeliveryMethod;
import com.google.ads.googleads.v5.enums.CampaignStatusEnum.CampaignStatus;
import com.google.ads.googleads.v5.enums.CriterionTypeEnum.CriterionType;
import com.google.ads.googleads.v5.errors.GoogleAdsError;
import com.google.ads.googleads.v5.errors.GoogleAdsException;
import com.google.ads.googleads.v5.resources.Ad;
import com.google.ads.googleads.v5.resources.AdGroup;
import com.google.ads.googleads.v5.resources.AdGroupAd;
import com.google.ads.googleads.v5.resources.Campaign;
import com.google.ads.googleads.v5.resources.Campaign.AppCampaignSetting;
import com.google.ads.googleads.v5.resources.CampaignBudget;
import com.google.ads.googleads.v5.resources.CampaignCriterion;
import com.google.ads.googleads.v5.services.AdGroupAdOperation;
import com.google.ads.googleads.v5.services.AdGroupAdServiceClient;
import com.google.ads.googleads.v5.services.AdGroupOperation;
import com.google.ads.googleads.v5.services.AdGroupServiceClient;
import com.google.ads.googleads.v5.services.CampaignBudgetOperation;
import com.google.ads.googleads.v5.services.CampaignBudgetServiceClient;
import com.google.ads.googleads.v5.services.CampaignCriterionOperation;
import com.google.ads.googleads.v5.services.CampaignCriterionServiceClient;
import com.google.ads.googleads.v5.services.CampaignOperation;
import com.google.ads.googleads.v5.services.CampaignServiceClient;
import com.google.ads.googleads.v5.services.MutateAdGroupAdsResponse;
import com.google.ads.googleads.v5.services.MutateAdGroupsResponse;
import com.google.ads.googleads.v5.services.MutateCampaignBudgetsResponse;
import com.google.ads.googleads.v5.services.MutateCampaignCriteriaResponse;
import com.google.ads.googleads.v5.services.MutateCampaignCriterionResult;
import com.google.ads.googleads.v5.services.MutateCampaignsResponse;
import com.google.ads.googleads.v5.utils.ResourceNames;
import com.google.common.collect.ImmutableList;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.joda.time.DateTime;

/** Adds a new App Campaign. */
public class AddAppCampaign {
  private static class AddAppCampaignParams extends CodeSampleParams {

    @Parameter(names = ArgumentNames.CUSTOMER_ID, required = true)
    private Long customerId;
  }

  public static void main(String[] args) {
    AddAppCampaignParams params = new AddAppCampaignParams();
    if (!params.parseArguments(args)) {

      // Either pass the required parameters for this example on the command line, or insert them
      // into the code here. See the parameter class definition above for descriptions.
      params.customerId = Long.parseLong("INSERT_CUSTOMER_ID_HERE");
    }

    GoogleAdsClient googleAdsClient = null;
    try {
      googleAdsClient = GoogleAdsClient.newBuilder().fromPropertiesFile().build();
    } catch (FileNotFoundException fnfe) {
      System.err.printf(
          "Failed to load GoogleAdsClient configuration from file. Exception: %s%n", fnfe);
      System.exit(1);
    } catch (IOException ioe) {
      System.err.printf("Failed to create GoogleAdsClient. Exception: %s%n", ioe);
      System.exit(1);
    }

    try {
      new AddAppCampaign().runExample(googleAdsClient, params.customerId);
    } catch (GoogleAdsException gae) {
      // GoogleAdsException is the base class for most exceptions thrown by an API request.
      // Instances of this exception have a message and a GoogleAdsFailure that contains a
      // collection of GoogleAdsErrors that indicate the underlying causes of the
      // GoogleAdsException.
      System.err.printf(
          "Request ID %s failed due to GoogleAdsException. Underlying errors:%n",
          gae.getRequestId());
      int i = 0;
      for (GoogleAdsError googleAdsError : gae.getGoogleAdsFailure().getErrorsList()) {
        System.err.printf("  Error %d: %s%n", i++, googleAdsError);
      }
      System.exit(1);
    }
  }

  private void runExample(GoogleAdsClient googleAdsClient, long customerId) {
    // Creates a budget for the campaign.
    String budgetResourceName = createBudget(googleAdsClient, customerId);

    // Creates the campaign.
    String campaignResourceName = createCampaign(googleAdsClient, customerId, budgetResourceName);

    // Sets campaign targeting.
    setCampaignTargetingCriteria(googleAdsClient, customerId, campaignResourceName);

    // Creates an ad group.
    String adGroupResourceName = createAdGroup(googleAdsClient, customerId, campaignResourceName);

    // Creates ad App ad.
    createAppAd(googleAdsClient, customerId, adGroupResourceName);
  }

  /**
   * Creates a budget under the given customer ID.
   *
   * @param googleAdsClient the Google Ads API client.
   * @param customerId the customer ID.
   * @return the resource name of the newly created campaign budget.
   */
  private String createBudget(GoogleAdsClient googleAdsClient, long customerId) {
    // Creates a campaign budget.
    CampaignBudget campaignBudget =
        CampaignBudget.newBuilder()
            .setName("Interplanetary Cruise #" + System.currentTimeMillis())
            .setAmountMicros(50_000_000)
            .setDeliveryMethod(BudgetDeliveryMethod.STANDARD)
            // An App campaign cannot use a shared campaign budget.
            // explicitly_shared must be set to false.
            .setExplicitlyShared(false)
            .build();

    // Creates a campaign budget operation.
    CampaignBudgetOperation operation =
        CampaignBudgetOperation.newBuilder().setCreate(campaignBudget).build();

    // Creates the campaign budget service client.
    try (CampaignBudgetServiceClient campaignBudgetServiceClient =
        googleAdsClient.getLatestVersion().createCampaignBudgetServiceClient()) {
      // Adds the campaign budget.
      MutateCampaignBudgetsResponse response =
          campaignBudgetServiceClient.mutateCampaignBudgets(
              Long.toString(customerId), ImmutableList.of(operation));
      // Prints and returns the resource name.
      String budgetResourceName = response.getResults(0).getResourceName();
      System.out.printf("Created campaign budget with resource name '%s'.%n", budgetResourceName);
      return budgetResourceName;
    }
  }

  /**
   * Creates an App campaign under the given customer ID.
   *
   * @param googleAdsClient the Google Ads API client.
   * @param customerId the customer ID.
   * @param budgetResourceName the resource name of the budget to associate with the campaign.
   * @return the resource name of the newly created App campaign.
   */
  private String createCampaign(
      GoogleAdsClient googleAdsClient, long customerId, String budgetResourceName) {
    // Creates a campaign.
    Campaign campaign =
        Campaign.newBuilder()
            .setName("Interplanetary Cruise App #" + System.currentTimeMillis())
            .setCampaignBudget(budgetResourceName)
            // 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.
            .setStatus(CampaignStatus.PAUSED)
            // All App campaigns have an advertising_channel_type of
            // MULTI_CHANNEL to reflect the fact that ads from these campaigns are
            // eligible to appear on multiple channels.
            .setAdvertisingChannelType(AdvertisingChannelType.MULTI_CHANNEL)
            .setAdvertisingChannelSubType(AdvertisingChannelSubType.APP_CAMPAIGN)
            // Sets the target CPA to $1 / app install.
            //
            // campaign_bidding_strategy is a 'oneof' message so setting target_cpa
            // is mutually exclusive with other bidding strategies such as
            // manual_cpc, commission, maximize_conversions, etc.
            // See https://developers.google.com/google-ads/api/reference/rpc
            // under current version / resources / Campaign.
            .setTargetCpa(TargetCpa.newBuilder().setTargetCpaMicros(1000000).build())
            // Sets the App campaign settings.
            .setAppCampaignSetting(
                AppCampaignSetting.newBuilder()
                    .setAppId("com.google.android.apps.adwords")
                    .setAppStore(AppCampaignAppStore.GOOGLE_APP_STORE)
                    // Optional: Optimize this campaign for getting new users for your app.
                    .setBiddingStrategyGoalType(
                        AppCampaignBiddingStrategyGoalType.OPTIMIZE_INSTALLS_TARGET_INSTALL_COST)
                    .build())
            // Optional fields.
            .setStartDate(new DateTime().plusDays(1).toString("yyyyMMdd"))
            .setEndDate(new DateTime().plusDays(365).toString("yyyyMMdd"))
            // If you select the
            // OPTIMIZE_IN_APP_CONVERSIONS_TARGET_INSTALL_COST goal type, then also
            // specify your in-app conversion types so the Google Ads API can focus
            // your campaign on people who are most likely to complete the
            // corresponding in-app actions.
            // .setSelectiveOptimization(SelectiveOptimization.newBuilder()
            //     .addConversionActions(StringValue.of("INSERT_CONVERSION_TYPE_ID_HERE"))
            //     .build())
            .build();

    // Creates a campaign operation.
    CampaignOperation operation = CampaignOperation.newBuilder().setCreate(campaign).build();

    // Create a campaign service client.
    try (CampaignServiceClient campaignServiceClient =
        googleAdsClient.getLatestVersion().createCampaignServiceClient()) {
      // Adds the campaign.
      MutateCampaignsResponse response =
          campaignServiceClient.mutateCampaigns(
              Long.toString(customerId), ImmutableList.of(operation));
      // Prints and returns the campaign resource name.
      String campaignResourceName = response.getResults(0).getResourceName();
      System.out.printf("Created App campaign with resource name '%s'.%n", campaignResourceName);
      return campaignResourceName;
    }
  }

  /**
   * Sets campaign targeting criteria for a given campaign.
   *
   * <p>Both location and language targeting are illustrated.
   *
   * @param googleAdsClient the Google Ads API client.
   * @param customerId the customer ID.
   * @param campaignResourceName the resource name of the campaign to apply targeting to.
   */
  private void setCampaignTargetingCriteria(
      GoogleAdsClient googleAdsClient, long customerId, String campaignResourceName) {
    List<CampaignCriterionOperation> operations = new ArrayList<>();

    // Creates the location campaign criteria.
    // Besides using location_id, you can also search by location names from
    // GeoTargetConstantService.suggestGeoTargetConstants() and directly
    // apply GeoTargetConstant.resource_name here. An example can be found
    // in GetGeoTargetConstantByNames.java.
    List<Integer> locationIds =
        Arrays.asList(
            21137, // California
            2484 // Mexico
            );

    for (int locationId : locationIds) {
      // Creates a campaign criterion.
      CampaignCriterion campaignCriterion =
          CampaignCriterion.newBuilder()
              .setCampaign(campaignResourceName)
              .setType(CriterionType.LOCATION)
              .setLocation(
                  LocationInfo.newBuilder()
                      .setGeoTargetConstant(ResourceNames.geoTargetConstant(locationId))
                      .build())
              .build();

      // Creates a campaign criterion operation.
      CampaignCriterionOperation operation =
          CampaignCriterionOperation.newBuilder().setCreate(campaignCriterion).build();

      operations.add(operation);
    }

    // Creates the language campaign criteria.
    List<Integer> languageIds =
        Arrays.asList(
            1000, // English
            1003 // Spanish
            );

    for (int languageId : languageIds) {
      // Creates a campaign criterion.
      CampaignCriterion campaignCriterion =
          CampaignCriterion.newBuilder()
              .setCampaign(campaignResourceName)
              .setType(CriterionType.LANGUAGE)
              .setLanguage(
                  LanguageInfo.newBuilder()
                      .setLanguageConstant(ResourceNames.languageConstant(languageId))
                      .build())
              .build();

      // Creates a campaign criterion operation.
      CampaignCriterionOperation operation =
          CampaignCriterionOperation.newBuilder().setCreate(campaignCriterion).build();

      operations.add(operation);
    }

    // Creates the campaign criterion service client.
    try (CampaignCriterionServiceClient campaignCriterionServiceClient =
        googleAdsClient.getLatestVersion().createCampaignCriterionServiceClient()) {
      // Submits the criteria operations and prints their information.
      MutateCampaignCriteriaResponse response =
          campaignCriterionServiceClient.mutateCampaignCriteria(
              Long.toString(customerId), operations);
      System.out.printf(
          "Created %d campaign criteria with resource names:%n", response.getResultsCount());
      for (MutateCampaignCriterionResult result : response.getResultsList()) {
        System.out.println(result.getResourceName());
      }
    }
  }

  /**
   * Creates an ad group for a given campaign
   *
   * @param googleAdsClient the Google Ads API client.
   * @param customerId the customer ID.
   * @param campaignResourceName resource name of the campaign to add the ad group to.
   * @return the resource name of the newly created ad group.
   */
  private String createAdGroup(
      GoogleAdsClient googleAdsClient, long customerId, String campaignResourceName) {
    // Creates an ad group.
    // Note that the ad group type must not be set.
    // Since the advertising_channel_sub_type is APP_CAMPAIGN,
    //   1. you cannot override bid settings at the ad group level.
    //   2. you cannot add ad group criteria.
    AdGroup adGroup =
        AdGroup.newBuilder()
            .setName("Earth to Mars cruises #" + System.currentTimeMillis())
            .setStatus(AdGroupStatus.ENABLED)
            .setCampaign(campaignResourceName)
            .build();

    // Creates an ad group operation.
    AdGroupOperation operation = AdGroupOperation.newBuilder().setCreate(adGroup).build();

    // Creates the ad group service client.
    try (AdGroupServiceClient adGroupServiceClient =
        googleAdsClient.getLatestVersion().createAdGroupServiceClient()) {
      // Submits the ad group operation to add the ad group and prints the results.
      MutateAdGroupsResponse response =
          adGroupServiceClient.mutateAdGroups(
              Long.toString(customerId), ImmutableList.of(operation));
      // Prints and returns the ad group resource name.
      String adGroupResourceName = response.getResults(0).getResourceName();
      System.out.printf("Created an ad group with resource name '%s'.%n", adGroupResourceName);
      return adGroupResourceName;
    }
  }

  /**
   * Creates an App ad for a given ad group
   *
   * @param googleAdsClient the Google Ads API client.
   * @param customerId the customer ID.
   * @param adGroupResourceName the resource name of the ad group to add the App ad to.
   */
  private void createAppAd(
      GoogleAdsClient googleAdsClient, long customerId, String adGroupResourceName) {
    // Creates an ad group ad.
    AdGroupAd adGroupAd =
        AdGroupAd.newBuilder()
            .setStatus(AdGroupAdStatus.ENABLED)
            .setAdGroup(adGroupResourceName)
            .setAd(
                // ad_data is a 'oneof' message so setting app_ad
                // is mutually exclusive with ad data fields such as
                // text_ad, gmail_ad, etc.
                Ad.newBuilder()
                    .setAppAd(
                        AppAdInfo.newBuilder()
                            .addAllHeadlines(
                                ImmutableList.of(
                                    AdTextAsset.newBuilder().setText("A cool puzzle game").build(),
                                    AdTextAsset.newBuilder()
                                        .setText("Remove connected blocks")
                                        .build()))
                            .addAllDescriptions(
                                ImmutableList.of(
                                    AdTextAsset.newBuilder().setText("3 difficulty levels").build(),
                                    AdTextAsset.newBuilder()
                                        .setText("4 colorful fun skins")
                                        .build()))
                            // Optional: You can set up to 20 image assets for your campaign.
                            // .addAllImages(
                            //     ImmutableList.of(
                            //         AdImageAsset.newBuilder()
                            //             .setAsset("INSERT_AD_IMAGE_ASSET_ID")
                            //             .build()))
                            .build())
                    .build())
            .build();

    // Creates an ad group ad operation.
    AdGroupAdOperation operation = AdGroupAdOperation.newBuilder().setCreate(adGroupAd).build();

    // Creates the ad group ad service client.
    try (AdGroupAdServiceClient adGroupAdServiceClient =
        googleAdsClient.getLatestVersion().createAdGroupAdServiceClient()) {
      // Submits the ad group ad operation to add the ad group ad and prints the results.
      MutateAdGroupAdsResponse response =
          adGroupAdServiceClient.mutateAdGroupAds(
              Long.toString(customerId), ImmutableList.of(operation));
      System.out.printf(
          "Created an ad group ad with ad with resource name '%s'%n",
          response.getResults(0).getResourceName());
    }
  }
}

C#

// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Google.Ads.GoogleAds.Lib;
using Google.Ads.GoogleAds.V5.Common;
using Google.Ads.GoogleAds.V5.Errors;
using Google.Ads.GoogleAds.V5.Resources;
using Google.Ads.GoogleAds.V5.Services;

using System;
using System.Collections.Generic;
using static Google.Ads.GoogleAds.V5.Enums.AdGroupAdStatusEnum.Types;
using static Google.Ads.GoogleAds.V5.Enums.AdGroupStatusEnum.Types;
using static Google.Ads.GoogleAds.V5.Enums.AdvertisingChannelSubTypeEnum.Types;
using static Google.Ads.GoogleAds.V5.Enums.AdvertisingChannelTypeEnum.Types;
using static Google.Ads.GoogleAds.V5.Enums.AppCampaignAppStoreEnum.Types;
using static Google.Ads.GoogleAds.V5.Enums.AppCampaignBiddingStrategyGoalTypeEnum.Types;
using static Google.Ads.GoogleAds.V5.Enums.BudgetDeliveryMethodEnum.Types;
using static Google.Ads.GoogleAds.V5.Enums.CampaignStatusEnum.Types;
using static Google.Ads.GoogleAds.V5.Enums.CriterionTypeEnum.Types;
using static Google.Ads.GoogleAds.V5.Resources.Campaign.Types;

namespace Google.Ads.GoogleAds.Examples.V5
{
    /// <summary>
    /// This code example adds a new App Campaign.
    /// </summary>
    public class AddAppCampaign : ExampleBase
    {
        /// <summary>
        /// Main method, to run this code example as a standalone application.
        /// </summary>
        /// <param name="args">The command line arguments.</param>
        public static void Main(string[] args)
        {
            AddAppCampaign codeExample = new AddAppCampaign();
            Console.WriteLine(codeExample.Description);

            // The Google Ads customer ID for which the call is made.
            long customerId = long.Parse("INSERT_CUSTOMER_ID_HERE");

            codeExample.Run(new GoogleAdsClient(), customerId);
        }

        /// <summary>
        /// Returns a description about the code example.
        /// </summary>
        public override string Description => "This code example adds a new App Campaign.";

        /// <summary>
        /// Runs the code example.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The Google Ads customer ID for which the call is made.</param>
        public void Run(GoogleAdsClient client, long customerId)
        {
            try
            {
                // Creates a budget for the campaign.
                string budgetResourceName = CreateBudget(client, customerId);

                // Creates the campaign.
                string campaignResourceName = CreateCampaign(client, customerId, budgetResourceName);

                // Sets campaign targeting.
                SetCampaignTargetingCriteria(client, customerId, campaignResourceName);

                // Creates an ad group.
                string adGroupResourceName = CreateAdGroup(client, customerId, campaignResourceName);

                // Creates an App ad.
                CreateAppAd(client, customerId, adGroupResourceName);
            }
            catch (GoogleAdsException e)
            {
                Console.WriteLine("Failure:");
                Console.WriteLine($"Message: {e.Message}");
                Console.WriteLine($"Failure: {e.Failure}");
                Console.WriteLine($"Request ID: {e.RequestId}");
                throw;
            }
        }

        /// <summary>
        /// Creates the budget for the campaign.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The Google Ads customer ID for which the call is made.</param>
        /// <returns>The resource name of the newly created campaign budget.</returns>
        private string CreateBudget(GoogleAdsClient client, long customerId)
        {
            // Get the BudgetService.
            CampaignBudgetServiceClient budgetService = client.GetService(
                Services.V5.CampaignBudgetService);

            // Creates a campaign budget.
            CampaignBudget budget = new CampaignBudget()
            {
                Name = "Interplanetary Cruise Budget #" + ExampleUtilities.GetRandomString(),
                DeliveryMethod = BudgetDeliveryMethod.Standard,
                AmountMicros = 50_000_000,
                // An App campaign cannot use a shared campaign budget.
                // explicitly_shared must be set to false.
                ExplicitlyShared = false
            };

            // Create the operation.
            CampaignBudgetOperation budgetOperation = new CampaignBudgetOperation()
            {
                Create = budget
            };

            // Create the campaign budget.
            MutateCampaignBudgetsResponse response = budgetService.MutateCampaignBudgets(
                customerId.ToString(), new CampaignBudgetOperation[] { budgetOperation });

            string budgetResourceName = response.Results[0].ResourceName;
            Console.WriteLine($"Created campaign budget with resource name " +
                $"'{budgetResourceName}'.");

            return budgetResourceName;
        }

        /// <summary>
        /// Creates an App campaign under the given customer ID.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The Google Ads customer ID for which the call is made.</param>
        /// <param name="budgetResourceName">The budget resource name.</param>
        /// <returns>Resource name of the newly created campaign.</returns>
        private string CreateCampaign(GoogleAdsClient client, long customerId,
            string budgetResourceName)
        {
            // Get the CampaignService.
            CampaignServiceClient campaignService = client.GetService(Services.V5.CampaignService);

            // Create the campaign.
            Campaign campaign = new Campaign()
            {
                Name = "Interplanetary Cruise #" + ExampleUtilities.GetRandomString(),
                CampaignBudget = budgetResourceName,

                // 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,

                // All App campaigns have an advertising_channel_type of
                // MULTI_CHANNEL to reflect the fact that ads from these campaigns are
                // eligible to appear on multiple channels.
                AdvertisingChannelType = AdvertisingChannelType.MultiChannel,
                AdvertisingChannelSubType = AdvertisingChannelSubType.AppCampaign,

                // Sets the target CPA to $1 / app install.
                //
                // campaign_bidding_strategy is a 'oneof' message so setting target_cpa
                // is mutually exclusive with other bidding strategies such as
                // manual_cpc, commission, maximize_conversions, etc.
                // See https://developers.google.com/google-ads/api/reference/rpc
                // under current version / resources / Campaign.
                TargetCpa = new TargetCpa()
                {
                    TargetCpaMicros = 1000000
                },

                // Sets the App campaign settings.
                AppCampaignSetting = new AppCampaignSetting()
                {
                    AppId = "com.google.android.apps.adwords",
                    AppStore = AppCampaignAppStore.GoogleAppStore,
                    // Optional: Optimize this campaign for getting new users for your app.
                    BiddingStrategyGoalType =
                        AppCampaignBiddingStrategyGoalType.OptimizeInstallsTargetInstallCost
                },

                // Optional: Set the start date.
                StartDate = DateTime.Now.AddDays(1).ToString("yyyyMMdd"),

                // Optional: Set the end date.
                EndDate = DateTime.Now.AddYears(1).ToString("yyyyMMdd"),
            };

            // Creates a campaign operation.
            CampaignOperation operation = new CampaignOperation()
            {
                Create = campaign
            };

            // Add the campaigns.
            MutateCampaignsResponse response = campaignService.MutateCampaigns(
                customerId.ToString(), new CampaignOperation[] { operation });

            // Display the results.
            string campaignResourceName = response.Results[0].ResourceName;
            Console.WriteLine($"Created App campaign with resource name '{campaignResourceName}'.");

            return campaignResourceName;
        }

        /// <summary>
        /// Sets campaign targeting criteria for a given campaign. Both location and language
        /// targeting are illustrated.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The Google Ads customer ID for which the call is made.</param>
        /// <param name="campaignResourceName">The resource name of the campaign to apply
        /// targeting to.</param>
        private void SetCampaignTargetingCriteria(GoogleAdsClient client, long customerId,
            string campaignResourceName)
        {
            // Get the CampaignCriterionService.
            CampaignCriterionServiceClient campaignCriterionService = client.GetService(
                Services.V5.CampaignCriterionService);

            List<CampaignCriterionOperation> operations = new List<CampaignCriterionOperation>();

            // Creates the location campaign criteria.
            // Besides using location_id, you can also search by location names from
            // GeoTargetConstantService.suggestGeoTargetConstants() and directly
            // apply GeoTargetConstant.resource_name here. An example can be found
            // in GetGeoTargetConstantByNames.cs.
            int[] locationIds = new int[]
            {
                21137, // California
                2484 // Mexico
            };

            foreach (int locationId in locationIds)
            {
                // Creates a campaign criterion.
                CampaignCriterion campaignCriterion = new CampaignCriterion()
                {
                    Campaign = campaignResourceName,
                    Type = CriterionType.Location,
                    Location = new LocationInfo()
                    {
                        GeoTargetConstant = ResourceNames.GeoTargetConstant(locationId)
                    }
                };

                // Creates a campaign criterion operation.
                CampaignCriterionOperation operation = new CampaignCriterionOperation()
                {
                    Create = campaignCriterion
                };

                operations.Add(operation);
            }

            // Creates the language campaign criteria.
            int[] languageIds = new int[]
            {
                1000, // English
                1003 // Spanish
            };

            foreach (int languageId in languageIds)
            {
                // Creates a campaign criterion.
                CampaignCriterion campaignCriterion = new CampaignCriterion()
                {
                    Campaign = campaignResourceName,
                    Type = CriterionType.Language,
                    Language = new LanguageInfo()
                    {
                        LanguageConstant = ResourceNames.LanguageConstant(languageId)
                    }
                };

                // Creates a campaign criterion operation.
                CampaignCriterionOperation operation = new CampaignCriterionOperation()
                {
                    Create = campaignCriterion
                };

                operations.Add(operation);
            }

            // Submits the criteria operations and prints their information.
            MutateCampaignCriteriaResponse response =
                campaignCriterionService.MutateCampaignCriteria(customerId.ToString(), operations);
            Console.WriteLine($"Created {response.Results.Count} campaign criteria with " +
                $"resource names:");

            foreach (MutateCampaignCriterionResult result in response.Results)
            {
                Console.WriteLine(result.ResourceName);
            }
        }

        /// <summary>
        /// Creates an ad group for a given campaign
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The Google Ads customer ID for which the call is made.</param>
        /// <param name="campaignResourceName">Resource name of the campaign to add the ad group
        /// to.</param>
        /// <returns>The resource name of the newly created ad group.</returns>
        private string CreateAdGroup(GoogleAdsClient client, long customerId,
            string campaignResourceName)
        {
            // Get the AdGroupService.
            AdGroupServiceClient adGroupService = client.GetService(Services.V5.AdGroupService);

            // Creates an ad group.
            // Note that the ad group type must not be set.
            // Since the advertising_channel_sub_type is APP_CAMPAIGN,
            //   1. you cannot override bid settings at the ad group level.
            //   2. you cannot add ad group criteria.
            AdGroup adGroup = new AdGroup()
            {
                Name = $"Earth to Mars Cruises #{ExampleUtilities.GetRandomString()}",
                Status = AdGroupStatus.Enabled,
                Campaign = campaignResourceName
            };

            // Creates an ad group operation.
            // Create the operation.
            AdGroupOperation operation = new AdGroupOperation()
            {
                Create = adGroup
            };

            // Submits the ad group operation to add the ad group and prints the results.
            MutateAdGroupsResponse response =
                adGroupService.MutateAdGroups(customerId.ToString(), new[] { operation });

            // Prints and returns the ad group resource name.
            string adGroupResourceName = response.Results[0].ResourceName;
            Console.WriteLine($"Created an ad group with resource name '{adGroupResourceName}'.");
            return adGroupResourceName;
        }

        /// <summary>
        /// Creates an App ad for a given ad group.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The Google Ads customer ID for which the call is made.</param>
        /// <param name="adGroupResourceName">The resource name of the ad group to add the App
        /// ad to.</param>
        private void CreateAppAd(GoogleAdsClient client, long customerId,
                    string adGroupResourceName)
        {
            // Get the AdGroupAdService.
            AdGroupAdServiceClient adGroupAdService = client.GetService(
                Services.V5.AdGroupAdService);

            // Creates an ad group ad.
            AdGroupAd adGroupAd = new AdGroupAd
            {
                AdGroup = adGroupResourceName,
                Status = AdGroupAdStatus.Enabled,
                Ad = new Ad
                {
                    AppAd = new AppAdInfo
                    {
                        Headlines = {
                            new AdTextAsset()
                            {
                                Text = "A cool puzzle game"
                            },
                            new AdTextAsset()
                            {
                                Text = "Remove connected blocks"
                            },
                        },
                        Descriptions = {
                            new AdTextAsset()
                            {
                                Text = "3 difficulty levels"
                            },
                            new AdTextAsset()
                            {
                                Text = "4 colorful fun skins"
                            }
                        },
                        // Optional: You can set up to 20 image assets for your campaign.
                        //Images =
                        //{
                        //    new AdImageAsset()
                        //    {
                        //        Asset = ResourceNames.Asset(customerId, assetId)
                        //    }
                        //}
                    }
                }
            };

            // Create the operation.
            AdGroupAdOperation operation = new AdGroupAdOperation
            {
                Create = adGroupAd
            };

            // Submits the ad group ad operation to add the ad group ad and prints the results.
            MutateAdGroupAdsResponse response =
                adGroupAdService.MutateAdGroupAds(customerId.ToString(), new[] { operation });
            Console.WriteLine($"Created an ad group ad with ad with resource name " +
                $"'{response.Results[0].ResourceName}'.");
        }
    }
}

PHP

<?php

/**
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace Google\Ads\GoogleAds\Examples\AdvancedOperations;

require __DIR__ . '/../../vendor/autoload.php';

use GetOpt\GetOpt;
use Google\Ads\GoogleAds\Examples\Utils\ArgumentNames;
use Google\Ads\GoogleAds\Examples\Utils\ArgumentParser;
use Google\Ads\GoogleAds\Lib\V5\GoogleAdsClient;
use Google\Ads\GoogleAds\Lib\V5\GoogleAdsClientBuilder;
use Google\Ads\GoogleAds\Lib\V5\GoogleAdsException;
use Google\Ads\GoogleAds\Lib\OAuth2TokenBuilder;
use Google\Ads\GoogleAds\Util\V5\ResourceNames;
use Google\Ads\GoogleAds\V5\Common\AdTextAsset;
use Google\Ads\GoogleAds\V5\Common\AppAdInfo;
use Google\Ads\GoogleAds\V5\Common\LanguageInfo;
use Google\Ads\GoogleAds\V5\Common\LocationInfo;
use Google\Ads\GoogleAds\V5\Enums\AdGroupAdStatusEnum\AdGroupAdStatus;
use Google\Ads\GoogleAds\V5\Enums\AdGroupStatusEnum\AdGroupStatus;
use Google\Ads\GoogleAds\V5\Enums\AppCampaignBiddingStrategyGoalTypeEnum\AppCampaignBiddingStrategyGoalType;
use Google\Ads\GoogleAds\V5\Common\TargetCpa;
use Google\Ads\GoogleAds\V5\Enums\AdvertisingChannelSubTypeEnum\AdvertisingChannelSubType;
use Google\Ads\GoogleAds\V5\Enums\AdvertisingChannelTypeEnum\AdvertisingChannelType;
use Google\Ads\GoogleAds\V5\Enums\AppCampaignAppStoreEnum\AppCampaignAppStore;
use Google\Ads\GoogleAds\V5\Enums\BudgetDeliveryMethodEnum\BudgetDeliveryMethod;
use Google\Ads\GoogleAds\V5\Enums\CampaignStatusEnum\CampaignStatus;
use Google\Ads\GoogleAds\V5\Enums\CriterionTypeEnum\CriterionType;
use Google\Ads\GoogleAds\V5\Errors\GoogleAdsError;
use Google\Ads\GoogleAds\V5\Resources\Ad;
use Google\Ads\GoogleAds\V5\Resources\AdGroup;
use Google\Ads\GoogleAds\V5\Resources\AdGroupAd;
use Google\Ads\GoogleAds\V5\Resources\Campaign;
use Google\Ads\GoogleAds\V5\Resources\Campaign\AppCampaignSetting;
use Google\Ads\GoogleAds\V5\Resources\CampaignBudget;
use Google\Ads\GoogleAds\V5\Resources\CampaignCriterion;
use Google\Ads\GoogleAds\V5\Services\AdGroupAdOperation;
use Google\Ads\GoogleAds\V5\Services\AdGroupOperation;
use Google\Ads\GoogleAds\V5\Services\CampaignBudgetOperation;
use Google\Ads\GoogleAds\V5\Services\CampaignCriterionOperation;
use Google\Ads\GoogleAds\V5\Services\CampaignOperation;
use Google\ApiCore\ApiException;

/**
 * This example adds an App campaign.
 *
 * For guidance regarding App Campaigns, see:
 * https://developers.google.com/google-ads/api/docs/app-campaigns/overview
 *
 * To get campaigns, run the GetCampaigns.php example.
 * To upload image assets for this campaign, run the UploadImageAsset.php example.
 */
class AddAppCampaign
{
    private const CUSTOMER_ID = 'INSERT_CUSTOMER_ID_HERE';

    public static function main()
    {
        // Either pass the required parameters for this example on the command line, or insert them
        // into the constants above.
        $options = (new ArgumentParser())->parseCommandArguments([
            ArgumentNames::CUSTOMER_ID => GetOpt::REQUIRED_ARGUMENT
        ]);

        // Generate a refreshable OAuth2 credential for authentication.
        $oAuth2Credential = (new OAuth2TokenBuilder())->fromFile()->build();

        // Construct a Google Ads client configured from a properties file and the
        // OAuth2 credentials above.
        $googleAdsClient = (new GoogleAdsClientBuilder())
            ->fromFile()
            ->withOAuth2Credential($oAuth2Credential)
            ->build();

        try {
            self::runExample(
                $googleAdsClient,
                $options[ArgumentNames::CUSTOMER_ID] ?: self::CUSTOMER_ID
            );
        } catch (GoogleAdsException $googleAdsException) {
            printf(
                "Request with ID '%s' has failed.%sGoogle Ads failure details:%s",
                $googleAdsException->getRequestId(),
                PHP_EOL,
                PHP_EOL
            );
            foreach ($googleAdsException->getGoogleAdsFailure()->getErrors() as $error) {
                /** @var GoogleAdsError $error */
                printf(
                    "\t%s: %s%s",
                    $error->getErrorCode()->getErrorCode(),
                    $error->getMessage(),
                    PHP_EOL
                );
            }
            exit(1);
        } catch (ApiException $apiException) {
            printf(
                "ApiException was thrown with message '%s'.%s",
                $apiException->getMessage(),
                PHP_EOL
            );
            exit(1);
        }
    }

    /**
     * Runs the example.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     */
    public static function runExample(
        GoogleAdsClient $googleAdsClient,
        int $customerId
    ) {
        // Creates a budget for the campaign.
        $budgetResourceName = self::createBudget($googleAdsClient, $customerId);

        // Creates the campaign.
        $campaignResourceName = self::createCampaign(
            $googleAdsClient,
            $customerId,
            $budgetResourceName
        );

        // Sets campaign targeting.
        self::setCampaignTargetingCriteria($googleAdsClient, $customerId, $campaignResourceName);

        // Creates an ad group.
        $adGroupResourceName = self::createAdGroup(
            $googleAdsClient,
            $customerId,
            $campaignResourceName
        );

        // Creates an App ad.
        self::createAppAd($googleAdsClient, $customerId, $adGroupResourceName);
    }

    /**
     * Creates a budget under the given customer ID.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @return string the resource name of the newly created budget
     */
    private static function createBudget(
        GoogleAdsClient $googleAdsClient,
        int $customerId
    ) {
        // Creates a campaign budget.
        $campaignBudget = new CampaignBudget([
            'name' => 'Interplanetary Cruise #' . uniqid(),
            'amount_micros' => 50000000,
            'delivery_method' => BudgetDeliveryMethod::STANDARD,
            // An App campaign cannot use a shared campaign budget.
            // explicitly_shared must be set to false.
            'explicitly_shared' => false
        ]);

        // Creates a campaign budget operation.
        $campaignBudgetOperation = new CampaignBudgetOperation();
        $campaignBudgetOperation->setCreate($campaignBudget);

        // Submits the campaign budget operation to add the campaign budget.
        $campaignBudgetServiceClient = $googleAdsClient->getCampaignBudgetServiceClient();
        $response = $campaignBudgetServiceClient->mutateCampaignBudgets(
            $customerId,
            [$campaignBudgetOperation]
        );

        $createdCampaignBudgetResourceName = $response->getResults()[0]->getResourceName();
        printf(
            "Created campaign budget with resource name: '%s'.%s",
            $createdCampaignBudgetResourceName,
            PHP_EOL
        );

        return $createdCampaignBudgetResourceName;
    }

    /**
     * Creates an App campaign under the given customer ID.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @param string $budgetResourceName the resource name of the budget to associate with the
     *      campaign
     * @return string the resource name of the newly created App campaign
     */
    private static function createCampaign(
        GoogleAdsClient $googleAdsClient,
        int $customerId,
        string $budgetResourceName
    ) {
        // Creates a campaign.
        $campaign = new Campaign([
            'name' => 'Interplanetary Cruise App #' . uniqid(),
            'campaign_budget' => $budgetResourceName,
            // 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,
            // All App campaigns have an advertising_channel_type of
            // MULTI_CHANNEL to reflect the fact that ads from these campaigns are
            // eligible to appear on multiple channels.
            'advertising_channel_type' => AdvertisingChannelType::MULTI_CHANNEL,
            'advertising_channel_sub_type' => AdvertisingChannelSubType::APP_CAMPAIGN,
            // Sets the target CPA to $1 / app install.
            //
            // campaign_bidding_strategy is a 'oneof' message so setting target_cpa
            // is mutually exclusive with other bidding strategies such as
            // manual_cpc, commission, maximize_conversions, etc.
            // See https://developers.google.com/google-ads/api/reference/rpc
            // under current version / resources / Campaign.
            'target_cpa' => new TargetCpa(['target_cpa_micros' => 1000000]),
            // Sets the App campaign settings.
            'app_campaign_setting' => new AppCampaignSetting([
                'app_id' => 'com.google.android.apps.adwords',
                'app_store' => AppCampaignAppStore::GOOGLE_APP_STORE,
                // Optional: Optimize this campaign for getting new users for your app.
                'bidding_strategy_goal_type' =>
                    AppCampaignBiddingStrategyGoalType::OPTIMIZE_INSTALLS_TARGET_INSTALL_COST
            ]),
            // Optional fields.
            'start_date' => date('Ymd', strtotime('+1 day')),
            'end_date' => date('Ymd', strtotime('+365 days'))
            // If you select the
            // OPTIMIZE_IN_APP_CONVERSIONS_TARGET_INSTALL_COST goal type, then also
            // specify your in-app conversion types so the Google Ads API can focus
            // your campaign on people who are most likely to complete the
            // corresponding in-app actions.
            // 'selective_optimization' => new SelectiveOptimization([
            //     'conversion_actions' => ['INSERT_CONVERSION_TYPE_ID_HERE']
            // ])
        ]);

        // Creates a campaign operation.
        $campaignOperation = new CampaignOperation();
        $campaignOperation->setCreate($campaign);

        // Submits the campaign operation and prints the results.
        $campaignServiceClient = $googleAdsClient->getCampaignServiceClient();
        $response = $campaignServiceClient->mutateCampaigns($customerId, [$campaignOperation]);

        $createdCampaignResourceName = $response->getResults()[0]->getResourceName();
        printf(
            "Created App campaign with resource name: '%s'.%s",
            $createdCampaignResourceName,
            PHP_EOL
        );

        return $createdCampaignResourceName;
    }

    /**
     * Sets campaign targeting criteria for a given campaign.
     *
     * Both location and language targeting are illustrated.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @param string $campaignResourceName the resource name of the campaign to apply targeting to
     */
    private static function setCampaignTargetingCriteria(
        GoogleAdsClient $googleAdsClient,
        int $customerId,
        string $campaignResourceName
    ) {
        $campaignCriterionOperations = [];

        // Creates the location campaign criteria.
        // Besides using location_id, you can also search by location names from
        // GeoTargetConstantService.suggestGeoTargetConstants() and directly
        // apply GeoTargetConstant.resource_name here. An example can be found
        // in GetGeoTargetConstantByNames.php.
        $locationIds = [
            21137, // California
            2484   // Mexico
        ];
        foreach ($locationIds as $locationId) {
            // Creates a campaign criterion.
            $campaignCriterion = new CampaignCriterion([
                'campaign' => $campaignResourceName,
                'type' => CriterionType::LOCATION,
                'location' => new LocationInfo([
                    'geo_target_constant' => ResourceNames::forGeoTargetConstant($locationId)
                ])
            ]);

            // Creates a campaign criterion operation.
            $campaignCriterionOperation = new CampaignCriterionOperation();
            $campaignCriterionOperation->setCreate($campaignCriterion);

            $campaignCriterionOperations[] = $campaignCriterionOperation;
        }

        // Creates the language campaign criteria.
        $languageIds = [
            1000, // English
            1003  // Spanish
        ];
        foreach ($languageIds as $languageId) {
            // Creates a campaign criterion.
            $campaignCriterion = new CampaignCriterion([
                'campaign' => $campaignResourceName,
                'type' => CriterionType::LANGUAGE,
                'language' => new LanguageInfo([
                    'language_constant' => ResourceNames::forLanguageConstant($languageId)
                ])
            ]);

            // Creates a campaign criterion operation.
            $campaignCriterionOperation = new CampaignCriterionOperation();
            $campaignCriterionOperation->setCreate($campaignCriterion);

            $campaignCriterionOperations[] = $campaignCriterionOperation;
        }

        // Submits the criteria operations and prints their information.
        $campaignCriterionServiceClient = $googleAdsClient->getCampaignCriterionServiceClient();
        $response = $campaignCriterionServiceClient->mutateCampaignCriteria(
            $customerId,
            $campaignCriterionOperations
        );

        printf(
            "Created %d campaign criteria with resource names:%s",
            $response->getResults()->count(),
            PHP_EOL
        );

        foreach ($response->getResults() as $createdCampaignCriterion) {
            /** @var CampaignCriterion $createdCampaignCriterion */
            printf("\t%s%s", $createdCampaignCriterion->getResourceName(), PHP_EOL);
        }
    }

    /**
     * Creates an ad group for a given campaign.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @param string $campaignResourceName the resource name of the campaign to add the ad group to
     * @return string the resource name of the newly created ad group
     */
    private static function createAdGroup(
        GoogleAdsClient $googleAdsClient,
        int $customerId,
        string $campaignResourceName
    ) {
        // Creates an ad group.
        // Note that the ad group type must not be set.
        // Since the advertising_channel_sub_type is APP_CAMPAIGN,
        //   1. you cannot override bid settings at the ad group level.
        //   2. you cannot add ad group criteria.
        $adGroup = new AdGroup([
            'name' => 'Earth to Mars cruises ' . uniqid(),
            'status' => AdGroupStatus::ENABLED,
            'campaign' => $campaignResourceName
        ]);

        // Creates an ad group operation.
        $adGroupOperation = new AdGroupOperation();
        $adGroupOperation->setCreate($adGroup);

        // Submits the ad group operation to add the ad group and prints the results.
        $adGroupServiceClient = $googleAdsClient->getAdGroupServiceClient();
        $response = $adGroupServiceClient->mutateAdGroups($customerId, [$adGroupOperation]);

        $createdAdGroupResourceName = $response->getResults()[0]->getResourceName();
        printf(
            "Created an ad group with resource name: '%s'.%s",
            $createdAdGroupResourceName,
            PHP_EOL
        );

        return $createdAdGroupResourceName;
    }

    /**
     * Creates an App ad for a given ad group.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @param string $adGroupResourceName the resource name of the ad group to add the App ad to
     */
    private static function createAppAd(
        GoogleAdsClient $googleAdsClient,
        int $customerId,
        string $adGroupResourceName
    ) {
        // Creates an ad group ad.
        $adGroupAd = new AdGroupAd([
            'status' => AdGroupAdStatus::ENABLED,
            'ad_group' => $adGroupResourceName,
            'ad' => new Ad([
                // ad_data is a 'oneof' message so setting app_ad
                // is mutually exclusive with ad data fields such as
                // text_ad, gmail_ad, etc.
                'app_ad' => new AppAdInfo([
                    'headlines' => [
                        new AdTextAsset(['text' => 'A cool puzzle game']),
                        new AdTextAsset(['text' => 'Remove connected blocks'])
                    ],
                    'descriptions' => [
                        new AdTextAsset(['text' => '3 difficulty levels']),
                        new AdTextAsset(['text' => '4 colorful fun skins'])
                    ]
                    // Optional: You can set up to 20 image assets for your campaign.
                    // 'images' => [
                    //     new AdImageAsset([
                    //         'asset' => INSERT_AD_IMAGE_ASSET_RESOURCE_NAME_HERE
                    //     ])
                    // ]
                ])
            ])
        ]);

        // Creates an ad group ad operation.
        $adGroupAdOperation = new AdGroupAdOperation();
        $adGroupAdOperation->setCreate($adGroupAd);

        // Submits the ad group ad operation to add the ad group ad and prints the results.
        $adGroupAdServiceClient = $googleAdsClient->getAdGroupAdServiceClient();
        $response = $adGroupAdServiceClient->mutateAdGroupAds($customerId, [$adGroupAdOperation]);

        $createdAdGroupAdResourceName = $response->getResults()[0]->getResourceName();
        printf(
            "Created an ad group ad with resource name: '%s'.%s",
            $createdAdGroupAdResourceName,
            PHP_EOL
        );
    }
}

AddAppCampaign::main();

Python

#!/usr/bin/env python
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""This example adds an App campaign.

For guidance regarding App Campaigns, see:
https://developers.google.com/google-ads/api/docs/app-campaigns/overview

To get campaigns, run basic_operations/get_campaigns.py.
To upload image assets for this campaign, run misc/upload_image_asset.py.
"""


import argparse
from datetime import datetime, timedelta
import sys
from uuid import uuid4

from google.ads.google_ads.client import GoogleAdsClient
from google.ads.google_ads.errors import GoogleAdsException


def main(client, customer_id):
    """Main function for running this example."""
    try:
        # Creates the budget for the campaign.
        budget_resource_name = _create_budget(client, customer_id)

        # Creates the campaign.
        campaign_resource_name = _create_campaign(
            client, customer_id, budget_resource_name
        )

        # Sets campaign targeting.
        _set_campaign_targeting_criteria(
            client, customer_id, campaign_resource_name
        )

        # Creates an Ad Group.
        ad_group_resource_name = _create_ad_group(
            client, customer_id, campaign_resource_name
        )

        # Creates an App Ad.
        _create_app_ad(client, customer_id, ad_group_resource_name)
    except GoogleAdsException as ex:
        print(
            f'Request with ID "{ex.request_id}" failed with status '
            f'"{ex.error.code().name}" and includes the following errors:'
        )
        for error in ex.failure.errors:
            print(f'\tError with message "{error.message}".')
            if error.location:
                for field_path_element in error.location.field_path_elements:
                    print(f"\t\tOn field: {field_path_element.field_name}")
        sys.exit(1)


def _create_budget(client, customer_id):
    """Creates a budget under the given customer ID.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID str.

    Returns:
        A resource_name str for the newly created Budget.
    """
    # Retrieves a new campaign budget operation object.
    campaign_budget_operation = client.get_type(
        "CampaignBudgetOperation", version="v5"
    )
    # Creates a campaign budget.
    campaign_budget = campaign_budget_operation.create
    campaign_budget.name = f"Interplanetary Cruise #{uuid4()}"
    campaign_budget.amount_micros = 50000000
    campaign_budget.delivery_method = client.get_type(
        "BudgetDeliveryMethodEnum", version="v5"
    ).STANDARD
    # An App campaign cannot use a shared campaign budget.
    # explicitly_shared must be set to false.
    campaign_budget.explicitly_shared = False

    # Retrieves the campaign budget service.
    campaign_budget_service = client.get_service(
        "CampaignBudgetService", version="v5"
    )
    # Submits the campaign budget operation to add the campaign budget.
    response = campaign_budget_service.mutate_campaign_budgets(
        customer_id, [campaign_budget_operation]
    )
    resource_name = response.results[0].resource_name
    print(f'Created campaign budget with resource_name: "{resource_name}"')
    return resource_name


def _create_campaign(client, customer_id, budget_resource_name):
    """Creates an app campaign under the given customer ID.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID str.
        budget_resource_name: the budget to associate with the campaign

    Returns:
        A resource_name str for the newly created app campaign.
    """
    campaign_service = client.get_service("CampaignService", version="v5")
    campaign_operation = client.get_type("CampaignOperation", version="v5")
    campaign = campaign_operation.create
    campaign.name = f"Interplanetary Cruise App #{uuid4()}"
    campaign.campaign_budget = budget_resource_name
    # 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.status = client.get_type("CampaignStatusEnum", version="v5").PAUSED
    # All App campaigns have an advertising_channel_type of
    # MULTI_CHANNEL to reflect the fact that ads from these campaigns are
    # eligible to appear on multiple channels.
    campaign.advertising_channel_type = client.get_type(
        "AdvertisingChannelTypeEnum", version="v5"
    ).MULTI_CHANNEL
    campaign.advertising_channel_sub_type = client.get_type(
        "AdvertisingChannelSubTypeEnum", version="v5"
    ).APP_CAMPAIGN
    # Sets the target CPA to $1 / app install.
    #
    # campaign_bidding_strategy is a 'oneof' message so setting target_cpa
    # is mutually exclusive with other bidding strategies such as
    # manual_cpc, commission, maximize_conversions, etc.
    # See https://developers.google.com/google-ads/api/reference/rpc
    # under current version / resources / Campaign
    campaign.target_cpa.target_cpa_micros = 1000000
    # Sets the App Campaign Settings.
    campaign.app_campaign_setting.app_id = "com.google.android.apps.adwords"
    campaign.app_campaign_setting.app_store = client.get_type(
        "AppCampaignAppStoreEnum", version="v5"
    ).GOOGLE_APP_STORE
    # Optimize this campaign for getting new users for your app.
    campaign.app_campaign_setting.bidding_strategy_goal_type = client.get_type(
        "AppCampaignBiddingStrategyGoalTypeEnum", version="v5"
    ).OPTIMIZE_INSTALLS_TARGET_INSTALL_COST
    # Optional fields
    campaign.start_date = (datetime.now() + timedelta(1)).strftime("%Y%m%d")
    campaign.end_date = (datetime.now() + timedelta(365)).strftime("%Y%m%d")
    # Optional: If you select the
    # OPTIMIZE_IN_APP_CONVERSIONS_TARGET_INSTALL_COST goal type, then also
    # specify your in-app conversion types so the Google Ads API can focus
    # your campaign on people who are most likely to complete the
    # corresponding in-app actions.
    # selective_optimization1 = (client.get_type('StringValue',
    #                            version='v5'))
    # selective_optimization1 = (
    #     'INSERT_CONVERSION_ACTION_RESOURCE_NAME_HERE')
    # campaign.selective_optimization.conversion_actions.extend(
    #     [selective_optimization1])

    # Submits the campaign operation and print the results.
    campaign_response = campaign_service.mutate_campaigns(
        customer_id, [campaign_operation]
    )
    resource_name = campaign_response.results[0].resource_name
    print(f'Created App campaign with resource name: "{resource_name}".')
    return resource_name


def _set_campaign_targeting_criteria(
    client, customer_id, campaign_resource_name
):
    """Sets campaign targeting criteria for a given campaign.

    Both location and language targeting are illustrated.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID str.
        campaign_resource_name: the campaign to apply targeting to
    """
    campaign_criterion_service = client.get_service(
        "CampaignCriterionService", version="v5"
    )
    geo_target_constant_service = client.get_service(
        "GeoTargetConstantService", version="v5"
    )
    language_constant_service = client.get_service(
        "LanguageConstantService", version="v5"
    )
    location_type = client.get_type("CriterionTypeEnum", version="v5").LOCATION
    language_type = client.get_type("CriterionTypeEnum", version="v5").LANGUAGE

    campaign_criterion_operations = []
    # Creates the location campaign criteria.
    # Besides using location_id, you can also search by location names from
    # GeoTargetConstantService.suggest_geo_target_constants() and directly
    # apply GeoTargetConstant.resource_name here. An example can be found
    # in targeting/get_geo_target_constant_by_names.py.
    for location_id in ["21137", "2484"]:  # California  # Mexico
        campaign_criterion_operation = client.get_type(
            "CampaignCriterionOperation", version="v5"
        )
        campaign_criterion = campaign_criterion_operation.create
        campaign_criterion.campaign = campaign_resource_name
        campaign_criterion.type = location_type
        campaign_criterion.location.geo_target_constant = geo_target_constant_service.geo_target_constant_path(
            location_id
        )
        campaign_criterion_operations.append(campaign_criterion_operation)

    # Creates the language campaign criteria.
    for language_id in ["1000", "1003"]:  # English  # Spanish
        campaign_criterion_operation = client.get_type(
            "CampaignCriterionOperation", version="v5"
        )
        campaign_criterion = campaign_criterion_operation.create
        campaign_criterion.campaign = campaign_resource_name
        campaign_criterion.type = language_type
        campaign_criterion.language.language_constant = language_constant_service.language_constant_path(
            language_id
        )
        campaign_criterion_operations.append(campaign_criterion_operation)

    # Submits the criteria operations.
    for row in campaign_criterion_service.mutate_campaign_criteria(
        customer_id, campaign_criterion_operations
    ).results:
        print(
            "Created Campaign Criteria with resource name: "
            f'"{row.resource_name}".'
        )


def _create_ad_group(client, customer_id, campaign_resource_name):
    """Creates an ad group for a given campaign.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID str.
        campaign_resource_name: the campaign to be modified

    Returns:
        A resource_name str for the newly created ad group.
    """
    ad_group_service = client.get_service("AdGroupService", version="v5")

    # Creates the ad group.
    # Note that the ad group type must not be set.
    # Since the advertising_channel_sub_type is APP_CAMPAIGN,
    #   1- you cannot override bid settings at the ad group level.
    #   2- you cannot add ad group criteria.
    ad_group_operation = client.get_type("AdGroupOperation", version="v5")
    ad_group = ad_group_operation.create
    ad_group.name = f"Earth to Mars cruises {uuid4()}"
    ad_group.status = client.get_type("AdGroupStatusEnum", version="v5").ENABLED
    ad_group.campaign = campaign_resource_name

    ad_group_response = ad_group_service.mutate_ad_groups(
        customer_id, [ad_group_operation]
    )

    ad_group_resource_name = ad_group_response.results[0].resource_name
    print(f'Ad Group created with resource name: "{ad_group_resource_name}".')
    return ad_group_resource_name


def _create_app_ad(client, customer_id, ad_group_resource_name):
    """Creates an App ad for a given ad group.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID str.
        ad_group_resource_name: the ad group where the ad will be added.
    """
    # Creates the ad group ad.
    ad_group_ad_service = client.get_service("AdGroupAdService", version="v5")
    ad_group_ad_operation = client.get_type("AdGroupAdOperation", version="v5")
    ad_group_ad = ad_group_ad_operation.create
    ad_group_ad.status = client.get_type(
        "AdGroupAdStatusEnum", version="v5"
    ).ENABLED
    ad_group_ad.ad_group = ad_group_resource_name
    # ad_data is a 'oneof' message so setting app_ad
    # is mutually exclusive with ad data fields such as
    # text_ad, gmail_ad, etc.
    ad_group_ad.ad.app_ad.headlines.extend(
        [
            _create_ad_text_asset(client, "A cool puzzle game"),
            _create_ad_text_asset(client, "Remove connected blocks"),
        ]
    )
    ad_group_ad.ad.app_ad.descriptions.extend(
        [
            _create_ad_text_asset(client, "3 difficulty levels"),
            _create_ad_text_asset(client, "4 colorful fun skins"),
        ]
    )
    # Optional: You can set up to 20 image assets for your campaign.
    # ad_group_ad.ad.app_ad.images.extend(
    #     [INSERT_AD_IMAGE_RESOURCE_NAME(s)_HERE])

    ad_group_ad_response = ad_group_ad_service.mutate_ad_group_ads(
        customer_id, [ad_group_ad_operation]
    )
    ad_group_ad_resource_name = ad_group_ad_response.results[0].resource_name
    print(
        "Ad Group App Ad created with resource name:"
        f'"{ad_group_ad_resource_name}".'
    )


def _create_ad_text_asset(client, text):
    ad_text_asset = client.get_type("AdTextAsset", version="v5")
    ad_text_asset.text = text
    return ad_text_asset


if __name__ == "__main__":
    # GoogleAdsClient will read the google-ads.yaml configuration file in the
    # home directory if none is specified.
    google_ads_client = GoogleAdsClient.load_from_storage()

    parser = argparse.ArgumentParser(
        description=(
            "Adds a App Ad campaign under the specified " "customer ID."
        )
    )
    # The following argument(s) should be provided to run the example.
    parser.add_argument(
        "-c",
        "--customer_id",
        type=str,
        required=True,
        help="The Google Ads customer ID.",
    )
    args = parser.parse_args()

    main(google_ads_client, args.customer_id)

Ruby

#!/usr/bin/env ruby

#
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This example adds an App campaign.
#
# For guidance regarding App Campaigns, see:
# https://developers.google.com/google-ads/api/docs/app-campaigns/overview
#
# To get campaigns, run basic_operations/get_campaigns.rb.
# To upload image assets for this campaign, run misc/upload_image_asset.rb.

require 'optparse'
require 'google/ads/google_ads'
require 'date'

def add_app_campaign(customer_id)
  # GoogleAdsClient will read a config file from
  # ENV['HOME']/google_ads_config.rb when called without parameters
  client = Google::Ads::GoogleAds::GoogleAdsClient.new

  # Creates the budget for the campaign.
  budget_resource_name = create_budget(client, customer_id)

  # Creates the campaign.
  campaign_resource_name = create_campaign(client, customer_id, budget_resource_name)

  # Creates campaign targeting.
  create_campaign_targeting_criteria(client, customer_id, campaign_resource_name)

  # Creates an Ad Group.
  ad_group_resource_name = create_ad_group(client, customer_id, campaign_resource_name)

  # Creates an App Ad.
  create_app_ad(client, customer_id, ad_group_resource_name)
end

def create_budget(client, customer_id)
  # Creates a campaign budget.
  campaign_budget = client.resource.campaign_budget do |b|
    b.name = "Interplanetary Cruise #{(Time.now.to_f * 1000).to_i}"
    b.amount_micros = 50_000_000
    b.delivery_method = :STANDARD
    # An App campaign cannot use a shared campaign budget.
    # explicitly_shared must be set to false.
    b.explicitly_shared = false
  end

  # Submits the campaign budget operation to add the campaign budget.
  operation = client.operation.create_resource.campaign_budget(campaign_budget)
  response = client.service.campaign_budget.mutate_campaign_budgets(
    customer_id: customer_id,
    operations: [operation]
  )
  puts "Created campaign budget: #{response.results.first.resource_name}"
  response.results.first.resource_name
end

def create_campaign(client, customer_id, budget_resource_name)
  campaign = client.resource.campaign do |c|
    c.name = "Interplanetary Cruise App #{(Time.now.to_f * 1000).to_i}"
    c.campaign_budget = budget_resource_name
    # 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.
    c.status = :PAUSED
    # All App campaigns have an advertising_channel_type of
    # MULTI_CHANNEL to reflect the fact that ads from these campaigns are
    # eligible to appear on multiple channels.
    c.advertising_channel_type = :MULTI_CHANNEL
    c.advertising_channel_sub_type = :APP_CAMPAIGN
    # Sets the target CPA to $1 / app install.
    #
    # campaign_bidding_strategy is a 'oneof' message so setting target_cpa
    # is mutually exclusive with other bidding strategies such as
    # manual_cpc, commission, maximize_conversions, etc.
    # See https://developers.google.com/google-ads/api/reference/rpc
    # under current version / resources / Campaign
    c.target_cpa = client.resource.target_cpa do |target_cpa|
      target_cpa.target_cpa_micros = 1_000_000
    end
    # Sets the App Campaign Settings.
    c.app_campaign_setting = client.resource.app_campaign_setting do |acs|
      acs.app_id = 'com.google.android.apps.adwords'
      acs.app_store = :GOOGLE_APP_STORE
      # Optimize this campaign for getting new users for your app.
      acs.bidding_strategy_goal_type = :OPTIMIZE_INSTALLS_TARGET_INSTALL_COST
    end
    # Optional fields
    c.start_date = DateTime.parse((Date.today + 1).to_s).strftime('%Y%m%d')
    c.end_date = DateTime.parse(Date.today.next_year.to_s).strftime('%Y%m%d')
  end

  operation = client.operation.create_resource.campaign(campaign)
  response = client.service.campaign.mutate_campaigns(
    customer_id: customer_id,
    operations: [operation]
  )
  puts "Created campaign: #{response.results.first.resource_name}"
  response.results.first.resource_name
end

def create_campaign_targeting_criteria(client, customer_id, campaign_resource_name)
  # Besides using location_id, you can also search by location names from
  # GeoTargetConstantService.suggest_geo_target_constants() and directly
  # apply GeoTargetConstant.resource_name here. An example can be found
  # in targeting/get_geo_target_constant_by_names.rb.
  location_ops = [
    '21137', # California
    '2484', # Mexico
  ].map do |location_id|
    client.operation.create_resource.campaign_criterion do |cc|
      cc.campaign = campaign_resource_name
      cc.location = client.resource.location_info do |li|
        li.geo_target_constant = client.path.geo_target_constant(location_id)
      end
    end
  end

  # Creates the language campaign criteria.
  language_ops = [
    '1000', # English
    '1003', # Spanish
  ].map do |language_id|
    client.operation.create_resource.campaign_criterion do |cc|
      cc.campaign = campaign_resource_name
      cc.language = client.resource.language_info do |li|
        li.language_constant = client.path.language_constant(language_id)
      end
    end
  end

  operations = location_ops + language_ops

  # Submits the criteria operations.
  criteria_service = client.service.campaign_criterion
  response = criteria_service.mutate_campaign_criteria(
    customer_id: customer_id,
    operations: operations
  )
  response.results.each do |resource|
    puts "Created campaign criterion: #{resource.resource_name}"
  end
end

def create_ad_group(client, customer_id, campaign_resource_name)
  ad_group = client.resource.ad_group do |ag|
    ag.name = "Earth to Mars Cruises #{(Time.now.to_f * 1000).to_i}"
    ag.status = :ENABLED
    ag.campaign = campaign_resource_name
  end

  operation = client.operation.create_resource.ad_group(ad_group)
  response = client.service.ad_group.mutate_ad_groups(
    customer_id: customer_id,
    operations: [operation]
  )

  puts "Created ad group: #{response.results.first.resource_name}"
  response.results.first.resource_name
end

def create_app_ad(client, customer_id, ad_group_resource_name)
  # Creates the ad group ad.
  ad_group_ad = client.resource.ad_group_ad do |aga|
    aga.status = :ENABLED
    aga.ad_group = ad_group_resource_name
    # ad_data is a 'oneof' message so setting app_ad
    # is mutually exclusive with ad data fields such as
    # text_ad, gmail_ad, etc.
    aga.ad = client.resource.ad do |ad|
      ad.app_ad = client.resource.app_ad_info do |info|
        info.headlines << client.resource.ad_text_asset do |ata|
          ata.text = 'A cool puzzle game'
        end
        info.headlines << client.resource.ad_text_asset do |ata|
          ata.text = 'Remove connected blocks'
        end
        info.descriptions << client.resource.ad_text_asset do |ata|
          ata.text = '3 difficulty levels'
        end
        info.descriptions << client.resource.ad_text_asset do |ata|
          ata.text = '4 colorful fun skins'
        end
        # Optional: You can set up to 20 image assets for your campaign.
        # info.images << client.resource.ad_image_asset do |aia|
        #   ala = "[INSERT_AD_IMAGE_RESOURCE_NAME(s)_HERE]"
        # end
      end
    end
  end

  operation = client.operation.create_resource.ad_group_ad(ad_group_ad)
  response = client.service.ad_group_ad.mutate_ad_group_ads(
    customer_id: customer_id,
    operations: [operation]
  )
  puts "Created ad group ad: #{response.results.first.resource_name}"
end

if __FILE__ == $0
  options = {}
  # The following parameter(s) should be provided to run the example. You can
  # either specify these by changing the INSERT_XXX_ID_HERE values below, or on
  # the command line.
  #
  # Parameters passed on the command line will override any parameters set in
  # code.
  #
  # Running the example with -h will print the command line usage.
  options[:customer_id] = 'INSERT_CUSTOMER_ID_HERE'

  OptionParser.new do |opts|
    opts.banner = sprintf('Usage: add_app_campaigns.rb [options]')

    opts.separator ''
    opts.separator 'Options:'

    opts.on('-C', '--customer-id CUSTOMER-ID', String, 'Customer ID') do |v|
      options[:customer_id] = v
    end

    opts.separator ''
    opts.separator 'Help:'

    opts.on_tail('-h', '--help', 'Show this message') do
      puts opts
      exit
    end
  end.parse!

  begin
    add_app_campaign(options.fetch(:customer_id).tr('-', ''))
  rescue Google::Ads::GoogleAds::Errors::GoogleAdsError => e
    e.failure.errors.each do |error|
      STDERR.printf("Error with message: %s\n", error.message)
      error.location&.field_path_elements&.each do |field_path_element|
        STDERR.printf("\tOn field: %s\n", field_path_element.field_name)
      end
      error.error_code.to_h.each do |k, v|
        next if v == :UNSPECIFIED

        STDERR.printf("\tType: %s\n\tCode: %s\n", k, v)
      end
    end
    raise
  end
end

Perl

#!/usr/bin/perl -w
#
# Copyright 2020, Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This example adds an App campaign.
#
# For guidance regarding App campaigns, see:
# https://developers.google.com/google-ads/api/docs/app-campaigns/overview
#
# To get campaigns, run basic_operations/get_campaigns.pl.
# To upload image assets for this campaign, run misc/upload_image_asset.pl.

use strict;
use warnings;
use utf8;

use FindBin qw($Bin);
use lib "$Bin/../../lib";
use Google::Ads::GoogleAds::Client;
use Google::Ads::GoogleAds::Utils::GoogleAdsHelper;
use Google::Ads::GoogleAds::V5::Resources::CampaignBudget;
use Google::Ads::GoogleAds::V5::Resources::Campaign;
use Google::Ads::GoogleAds::V5::Resources::AppCampaignSetting;
use Google::Ads::GoogleAds::V5::Resources::SelectiveOptimization;
use Google::Ads::GoogleAds::V5::Resources::CampaignCriterion;
use Google::Ads::GoogleAds::V5::Resources::AdGroup;
use Google::Ads::GoogleAds::V5::Resources::AdGroupAd;
use Google::Ads::GoogleAds::V5::Resources::Ad;
use Google::Ads::GoogleAds::V5::Common::TargetCpa;
use Google::Ads::GoogleAds::V5::Common::LocationInfo;
use Google::Ads::GoogleAds::V5::Common::LanguageInfo;
use Google::Ads::GoogleAds::V5::Common::AppAdInfo;
use Google::Ads::GoogleAds::V5::Common::AdImageAsset;
use Google::Ads::GoogleAds::V5::Common::AdTextAsset;
use Google::Ads::GoogleAds::V5::Enums::BudgetDeliveryMethodEnum qw(STANDARD);
use Google::Ads::GoogleAds::V5::Enums::CampaignStatusEnum qw(PAUSED);
use Google::Ads::GoogleAds::V5::Enums::AdvertisingChannelTypeEnum
  qw(MULTI_CHANNEL);
use Google::Ads::GoogleAds::V5::Enums::AdvertisingChannelSubTypeEnum
  qw(APP_CAMPAIGN);
use Google::Ads::GoogleAds::V5::Enums::AppCampaignAppStoreEnum
  qw(GOOGLE_APP_STORE);
use Google::Ads::GoogleAds::V5::Enums::AppCampaignBiddingStrategyGoalTypeEnum
  qw(OPTIMIZE_INSTALLS_TARGET_INSTALL_COST);
use Google::Ads::GoogleAds::V5::Enums::CriterionTypeEnum qw(LOCATION LANGUAGE);
use Google::Ads::GoogleAds::V5::Enums::AdGroupStatusEnum;
use Google::Ads::GoogleAds::V5::Enums::AdGroupAdStatusEnum;
use
  Google::Ads::GoogleAds::V5::Services::CampaignBudgetService::CampaignBudgetOperation;
use Google::Ads::GoogleAds::V5::Services::CampaignService::CampaignOperation;
use
  Google::Ads::GoogleAds::V5::Services::CampaignCriterionService::CampaignCriterionOperation;
use Google::Ads::GoogleAds::V5::Services::AdGroupService::AdGroupOperation;
use Google::Ads::GoogleAds::V5::Services::AdGroupAdService::AdGroupAdOperation;
use Google::Ads::GoogleAds::V5::Utils::ResourceNames;

use Getopt::Long qw(:config auto_help);
use Pod::Usage;
use Cwd qw(abs_path);
use Data::Uniqid qw(uniqid);
use POSIX qw(strftime);

# The following parameter(s) should be provided to run the example. You can
# either specify these by changing the INSERT_XXX_ID_HERE values below, or on
# the command line.
#
# Parameters passed on the command line will override any parameters set in
# code.
#
# Running the example with -h will print the command line usage.
my $customer_id = "INSERT_CUSTOMER_ID_HERE";

sub add_app_campaign {
  my ($api_client, $customer_id) = @_;

  # Create the budget for the campaign.
  my $budget_resource_name = create_campaign_budget($api_client, $customer_id);

  # Create the campaign.
  my $campaign_resource_name =
    create_campaign($api_client, $customer_id, $budget_resource_name);

  # Set campaign targeting.
  set_campaign_targeting_criteria($api_client, $customer_id,
    $campaign_resource_name);

  # Create an ad group.
  my $ad_group_resource_name =
    create_ad_group($api_client, $customer_id, $campaign_resource_name);

  # Create an App ad.
  create_app_ad($api_client, $customer_id, $ad_group_resource_name);

  return 1;
}

# Creates a campaign budget.
sub create_campaign_budget {
  my ($api_client, $customer_id) = @_;

  # Create a campaign budget.
  my $campaign_budget =
    Google::Ads::GoogleAds::V5::Resources::CampaignBudget->new({
      name           => "Interplanetary Cruise Budget #" . uniqid(),
      amountMicros   => 50000000,
      deliveryMethod => STANDARD,
      # An App campaign cannot use a shared campaign budget.
      explicitlyShared => "false"
    });

  # Create a campaign budget operation.
  my $campaign_budget_operation =
    Google::Ads::GoogleAds::V5::Services::CampaignBudgetService::CampaignBudgetOperation
    ->new({
      create => $campaign_budget
    });

  # Issue a mutate request to add the campaign budget.
  my $campaign_budget_response = $api_client->CampaignBudgetService()->mutate({
      customerId => $customer_id,
      operations => [$campaign_budget_operation]});

  my $campaign_budget_resource_name =
    $campaign_budget_response->{results}[0]{resourceName};
  printf "Created campaign budget with resource name: '%s'.\n",
    $campaign_budget_resource_name;

  return $campaign_budget_resource_name;
}

# Creates an App campaign.
sub create_campaign {
  my ($api_client, $customer_id, $budget_resource_name) = @_;

  # Create a campaign.
  my $campaign = Google::Ads::GoogleAds::V5::Resources::Campaign->new({
      name           => "Interplanetary Cruise App #" . uniqid(),
      campaignBudget => $budget_resource_name,
      # 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 => PAUSED,
      # All App campaigns have an advertisingChannelType of MULTI_CHANNEL to
      # reflect the fact that ads from these campaigns are eligible to appear
      # on multiple channels.
      advertisingChannelType    => MULTI_CHANNEL,
      advertisingChannelSubType => APP_CAMPAIGN,
      # Set the target CPA to $1 / app install.
      targetCpa => Google::Ads::GoogleAds::V5::Common::TargetCpa->new({
          targetCpaMicros => 1000000
        }
      ),
      # Configure the App campaign setting.
      appCampaignSetting =>
        Google::Ads::GoogleAds::V5::Resources::AppCampaignSetting->new({
          appId                   => "com.google.android.apps.adwords",
          appStore                => GOOGLE_APP_STORE,
          biddingStrategyGoalType => OPTIMIZE_INSTALLS_TARGET_INSTALL_COST
        }
        ),
      # Optional: If you select the OPTIMIZE_IN_APP_CONVERSIONS_TARGET_INSTALL_COST
      # goal type, then also specify your in-app conversion actions so the Google
      # Ads API can focus your campaign on people who are most likely to complete
      # the corresponding in-app actions.
      # selectiveOptimization =>
      #   Google::Ads::GoogleAds::V5::Resources::SelectiveOptimization->new({
      #     conversionActions =>
      #       ["INSERT_CONVERSION_ACTION_RESOURCE_NAME(s)_HERE"]}
      #   ),
      #
      # Optional: Set the start and end dates for the campaign, beginning one day
      # from now and ending a year from now.
      startDate => strftime("%Y%m%d", localtime(time + 60 * 60 * 24)),
      endDate   => strftime("%Y%m%d", localtime(time + 60 * 60 * 24 * 365)),
    });

  # Create a campaign operation.
  my $campaign_operation =
    Google::Ads::GoogleAds::V5::Services::CampaignService::CampaignOperation->
    new({
      create => $campaign
    });

  # Issue a mutate request to add the campaign.
  my $campaign_response = $api_client->CampaignService()->mutate({
      customerId => $customer_id,
      operations => [$campaign_operation]});

  my $campaign_resource_name =
    $campaign_response->{results}[0]{resourceName};
  printf "Created App campaign with resource name: '%s'.\n",
    $campaign_resource_name;

  return $campaign_resource_name;
}

# Sets campaign targeting criteria for a given campaign.
sub set_campaign_targeting_criteria {
  my ($api_client, $customer_id, $campaign_resource_name) = @_;

  my $campaign_criterion_operations = [];

  # Create the location campaign criteria.
  # Location ID 21137 is for California, and 2484 is for Mexico.
  # Besides using location ID, you can also search by location names from
  # GeoTargetConstantService.suggest() method and directly apply
  # GeoTargetConstant.resourceName here. An example can be found in
  # targeting/get_geo_target_constants_by_names.pl.
  foreach my $location_id (21137, 2484) {
    my $campaign_criterion =
      Google::Ads::GoogleAds::V5::Resources::CampaignCriterion->new({
        campaign => $campaign_resource_name,
        type     => LOCATION,
        location => Google::Ads::GoogleAds::V5::Common::LocationInfo->new({
            geoTargetConstant =>
              Google::Ads::GoogleAds::V5::Utils::ResourceNames::geo_target_constant(
              $location_id)})});

    push @$campaign_criterion_operations,
      Google::Ads::GoogleAds::V5::Services::CampaignCriterionService::CampaignCriterionOperation
      ->new({
        create => $campaign_criterion
      });
  }

  # Create the language campaign criteria.
  # Language ID 1000 is for English, and 1003 is for Spanish.
  foreach my $language_id (1000, 1003) {
    my $campaign_criterion =
      Google::Ads::GoogleAds::V5::Resources::CampaignCriterion->new({
        campaign => $campaign_resource_name,
        type     => LANGUAGE,
        language => Google::Ads::GoogleAds::V5::Common::LanguageInfo->new({
            languageConstant =>
              Google::Ads::GoogleAds::V5::Utils::ResourceNames::language_constant(
              $language_id)})});

    push @$campaign_criterion_operations,
      Google::Ads::GoogleAds::V5::Services::CampaignCriterionService::CampaignCriterionOperation
      ->new({
        create => $campaign_criterion
      });
  }

  # Issue a mutate request to add the campaign criterion.
  my $campaign_criterion_response =
    $api_client->CampaignCriterionService()->mutate({
      customerId => $customer_id,
      operations => $campaign_criterion_operations
    });

  my $campaign_criterion_results = $campaign_criterion_response->{results};
  printf "Created %d campaign criteria:\n", scalar @$campaign_criterion_results;

  foreach my $campaign_criterion_result (@$campaign_criterion_results) {
    printf "\t%s\n", $campaign_criterion_result->{resourceName};
  }
}

# Creates an ad group for a given campaign.
sub create_ad_group {
  my ($api_client, $customer_id, $campaign_resource_name) = @_;

  # Create an ad group.
  # Note that the ad group type must not be set.
  # Since the advertisingChannelSubType is APP_CAMPAIGN,
  #   1- you cannot override bid settings at the ad group level.
  #   2- you cannot add ad group criteria.
  my $ad_group = Google::Ads::GoogleAds::V5::Resources::AdGroup->new({
    name     => "Earth to Mars Cruises #" . uniqid(),
    status   => Google::Ads::GoogleAds::V5::Enums::AdGroupStatusEnum::ENABLED,
    campaign => $campaign_resource_name
  });

  # Create an ad group operation.
  my $ad_group_operation =
    Google::Ads::GoogleAds::V5::Services::AdGroupService::AdGroupOperation->
    new({create => $ad_group});

  # Issue a mutate request to add the ad group.
  my $ad_group_response = $api_client->AdGroupService()->mutate({
      customerId => $customer_id,
      operations => [$ad_group_operation]});

  my $ad_group_resource_name =
    $ad_group_response->{results}[0]{resourceName};
  printf "Created ad group with resource name: '%s'.\n",
    $ad_group_resource_name;

  return $ad_group_resource_name;
}

# Creates an App ad for a given ad group.
sub create_app_ad {
  my ($api_client, $customer_id, $ad_group_resource_name) = @_;

  # Create an ad group ad.
  my $ad_group_ad = Google::Ads::GoogleAds::V5::Resources::AdGroupAd->new({
      adGroup => $ad_group_resource_name,
      status => Google::Ads::GoogleAds::V5::Enums::AdGroupAdStatusEnum::ENABLED,
      ad     => Google::Ads::GoogleAds::V5::Resources::Ad->new({
          appAd => Google::Ads::GoogleAds::V5::Common::AppAdInfo->new({
              headlines => [
                create_ad_text_asset("A cool puzzle game"),
                create_ad_text_asset("Remove connected blocks")
              ],
              descriptions => [
                create_ad_text_asset("3 difficulty levels"),
                create_ad_text_asset("4 colorful fun skins")
              ],
              # Optional: You can set up to 20 image assets for your campaign.
              # images => [
              #   Google::Ads::GoogleAds::V5::Common::AdImageAsset->new({
              #       asset => "INSERT_IMAGE_ASSET_RESOURCE_NAME_HERE"
              #     })]
            })})});

  # Create an ad group ad operation.
  my $ad_group_ad_operation =
    Google::Ads::GoogleAds::V5::Services::AdGroupAdService::AdGroupAdOperation
    ->new({create => $ad_group_ad});

  # Issue a mutate request to add the ad group ad.
  my $ad_group_ad_response = $api_client->AdGroupAdService()->mutate({
      customerId => $customer_id,
      operations => [$ad_group_ad_operation]});

  printf "Created ad group ad with resource name: '%s'.\n",
    $ad_group_ad_response->{results}[0]{resourceName};
}

# Creates an ad text asset.
sub create_ad_text_asset {
  my ($text) = @_;

  return Google::Ads::GoogleAds::V5::Common::AdTextAsset->new({
    text => $text
  });
}

# Don't run the example if the file is being included.
if (abs_path($0) ne abs_path(__FILE__)) {
  return 1;
}

# Get Google Ads Client, credentials will be read from ~/googleads.properties.
my $api_client = Google::Ads::GoogleAds::Client->new();

# By default examples are set to die on any server returned fault.
$api_client->set_die_on_faults(1);

# Parameters passed on the command line will override any parameters set in code.
GetOptions("customer_id=s" => \$customer_id);

# Print the help message if the parameters are not initialized in the code nor
# in the command line.
pod2usage(2) if not check_params($customer_id);

# Call the example.
add_app_campaign($api_client, $customer_id =~ s/-//gr);

=pod

=head1 NAME

add_app_campaign

=head1 DESCRIPTION

This example adds an App campaign.

For guidance regarding App campaigns, see:
https://developers.google.com/google-ads/api/docs/app-campaigns/overview

To get campaigns, run basic_operations/get_campaigns.pl.
To upload image assets for this campaign, run misc/upload_image_asset.pl.

=head1 SYNOPSIS

add_app_campaign.pl [options]

    -help                       Show the help message.
    -customer_id                The Google Ads customer ID.

=cut