Extensions Samples

The code samples below provide examples of common extension functions using the AdWords API. Client Library.

Add Google My Business location extensions

// Copyright 2017, Google Inc. All Rights Reserved.
//
// 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.Api.Ads.AdWords.Lib;
using Google.Api.Ads.AdWords.v201708;
using Google.Api.Ads.Common.Lib;

using System;

namespace Google.Api.Ads.AdWords.Examples.CSharp.v201708 {

  /// <summary>
  /// This code example adds a feed that syncs feed items from a Google
  /// My Business (GMB) account and associates the feed with a customer.
  /// </summary>
  public class AddGoogleMyBusinessLocationExtensions : ExampleBase {

    /// <summary>
    /// The placeholder type for location extensions. See the Placeholder
    /// reference page for a list of all the placeholder types and fields.
    ///
    /// https://developers.google.com/adwords/api/docs/appendix/placeholders
    /// </summary>
    private const int PLACEHOLDER_LOCATION = 7;

    /// <summary>
    /// Returns a description about the code example.
    /// </summary>
    public override string Description {
      get {
        return "This code example adds a feed that syncs feed items from a Google My Business " +
            "(GMB) account and associates the feed with a customer.";
      }
    }

    /// <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) {
      AddGoogleMyBusinessLocationExtensions codeExample =
          new AddGoogleMyBusinessLocationExtensions();
      Console.WriteLine(codeExample.Description);

      AdWordsUser user = new AdWordsUser();

      try {
        // The email address of either an owner or a manager of the GMB account.
        string gmbEmailAddress = "INSERT_GMB_EMAIL_ADDRESS_HERE";

        // Refresh the access token so that there's a valid access token.
        user.OAuthProvider.RefreshAccessToken();

        // If the gmbEmailAddress above is the same user you used to generate
        // your AdWords API refresh token, leave the assignment below unchanged.
        // Otherwise, to obtain an access token for your GMB account, run the
        // OAuth Token generator utility while logged in as the same user as
        // gmbEmailAddress. Copy and paste the AccessToken value into the
        // assignment below.
        string gmbAccessToken = user.OAuthProvider.AccessToken;

        // If the gmbEmailAddress above is for a GMB manager instead of the GMB
        // account owner, then set businessAccountIdentifier to the +Page ID of
        // a location for which the manager has access. See the location
        // extensions guide at
        // https://developers.google.com/adwords/api/docs/guides/feed-services-locations
        // for details.
        String businessAccountIdentifier = null;
        codeExample.Run(user, gmbEmailAddress, gmbAccessToken, businessAccountIdentifier);
      } catch (Exception e) {
        Console.WriteLine("An exception occurred while running this code example. {0}",
            ExampleUtilities.FormatException(e));
      }
    }

    /// <summary>
    /// Runs the code example.
    /// </summary>
    /// <param name="user">The AdWords user.</param>
    /// <param name="gmbEmailAddress">The email address for Google My Business
    /// account.</param>
    /// <param name="gmbAccessToken">The OAuth2 access token for Google
    /// My Business account.</param>
    /// <param name="businessAccountIdentifier">The account identifier for
    /// Google My Business account.</param>
    public void Run(AdWordsUser user, string gmbEmailAddress, string gmbAccessToken,
        string businessAccountIdentifier) {
      FeedService feedService = (FeedService) user.GetService(AdWordsService.v201708.FeedService);

      CustomerFeedService customerFeedService = (CustomerFeedService) user.GetService(
          AdWordsService.v201708.CustomerFeedService);

      // Create a feed that will sync to the Google My Business account
      // specified by gmbEmailAddress. Do not add FeedAttributes to this object,
      // as AdWords will add them automatically because this will be a
      // system generated feed.
      Feed gmbFeed = new Feed();
      gmbFeed.name = String.Format("Google My Business feed #{0}",
          ExampleUtilities.GetRandomString());

      PlacesLocationFeedData feedData = new PlacesLocationFeedData();
      feedData.emailAddress = gmbEmailAddress;
      feedData.businessAccountIdentifier = businessAccountIdentifier;

      // Optional: specify labels to filter Google My Business listings. If
      // specified, only listings that have any of the labels set are
      // synchronized into FeedItems.
      feedData.labelFilters = new string[] { "Stores in New York City" };

      OAuthInfo oAuthInfo = new OAuthInfo();
      oAuthInfo.httpMethod = "GET";

      // Permissions for the AdWords API scope will also cover GMB.
      oAuthInfo.httpRequestUrl = user.Config.GetDefaultOAuth2Scope();
      oAuthInfo.httpAuthorizationHeader = string.Format("Bearer {0}", gmbAccessToken);
      feedData.oAuthInfo = oAuthInfo;

      gmbFeed.systemFeedGenerationData = feedData;

      // Since this feed's feed items will be managed by AdWords,
      // you must set its origin to ADWORDS.
      gmbFeed.origin = FeedOrigin.ADWORDS;

      // Create an operation to add the feed.
      FeedOperation feedOperation = new FeedOperation();
      feedOperation.operand = gmbFeed;
      feedOperation.@operator = Operator.ADD;

      try {
        // Add the feed. Since it is a system generated feed, AdWords will
        // automatically:
        // 1. Set up the FeedAttributes on the feed.
        // 2. Set up a FeedMapping that associates the FeedAttributes of the
        //    feed with the placeholder fields of the LOCATION placeholder
        //    type.
        FeedReturnValue addFeedResult = feedService.mutate(new FeedOperation[] { feedOperation });
        Feed addedFeed = addFeedResult.value[0];
        Console.WriteLine("Added GMB feed with ID {0}", addedFeed.id);

        // Add a CustomerFeed that associates the feed with this customer for
        // the LOCATION placeholder type.
        CustomerFeed customerFeed = new CustomerFeed();
        customerFeed.feedId = addedFeed.id;
        customerFeed.placeholderTypes = new int[] { PLACEHOLDER_LOCATION };

        // Create a matching function that will always evaluate to true.
        Function customerMatchingFunction = new Function();
        ConstantOperand constOperand = new ConstantOperand();
        constOperand.type = ConstantOperandConstantType.BOOLEAN;
        constOperand.booleanValue = true;
        customerMatchingFunction.lhsOperand = new FunctionArgumentOperand[] { constOperand };
        customerMatchingFunction.@operator = FunctionOperator.IDENTITY;
        customerFeed.matchingFunction = customerMatchingFunction;

        // Create an operation to add the customer feed.
        CustomerFeedOperation customerFeedOperation = new CustomerFeedOperation();
        customerFeedOperation.operand = customerFeed;
        customerFeedOperation.@operator = Operator.ADD;

        // After the completion of the Feed ADD operation above the added feed
        // will not be available for usage in a CustomerFeed until the sync
        // between the AdWords and GMB accounts completes.  The loop below
        // will retry adding the CustomerFeed up to ten times with an
        // exponential back-off policy.
        CustomerFeed addedCustomerFeed = null;

        AdWordsAppConfig config = new AdWordsAppConfig();
        config.RetryCount = 10;

        ErrorHandler errorHandler = new ErrorHandler(config);
        do {
          try {
            CustomerFeedReturnValue customerFeedResult =
                customerFeedService.mutate(new CustomerFeedOperation[] { customerFeedOperation });
            addedCustomerFeed = customerFeedResult.value[0];

            Console.WriteLine("Added CustomerFeed for feed ID {0} and placeholder type {1}",
                addedCustomerFeed.feedId, addedCustomerFeed.placeholderTypes[0]);
            break;
          } catch (AdWordsApiException e) {
            ApiException apiException = (ApiException) e.ApiException;
            foreach (ApiError error in apiException.errors) {
              if (error is CustomerFeedError) {
                if ((error as CustomerFeedError).reason ==
                    CustomerFeedErrorReason.MISSING_FEEDMAPPING_FOR_PLACEHOLDER_TYPE) {
                  errorHandler.DoExponentialBackoff();
                  errorHandler.IncrementRetriedAttempts();
                } else {
                  throw;
                }
              }
            }
          }
        } while (errorHandler.HaveMoreRetryAttemptsLeft());

        // OPTIONAL: Create a CampaignFeed to specify which FeedItems to use at
        // the Campaign level.  This will be similar to the CampaignFeed in the
        // AddSiteLinks example, except you can also filter based on the
        // business name and category of each FeedItem by using a
        // FeedAttributeOperand in your matching function.

        // OPTIONAL: Create an AdGroupFeed for even more fine grained control
        // over which feed items are used at the AdGroup level.
      } catch (Exception e) {
        throw new System.ApplicationException("Failed to create customer feed.", e);
      }
    }
  }
}

Add prices

// Copyright 2017, Google Inc. All Rights Reserved.
//
// 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.Api.Ads.AdWords.Lib;
using Google.Api.Ads.AdWords.v201708;

using System;
using System.Collections.Generic;

using DayOfWeek = Google.Api.Ads.AdWords.v201708.DayOfWeek;

namespace Google.Api.Ads.AdWords.Examples.CSharp.v201708 {

  /// <summary>
  /// This code example adds a price extension and associates it with an
  /// account. Campaign targeting is also set using the specified campaign ID.
  /// To get campaigns, run AddCampaigns.cs.
  /// </summary>
  public class AddPrices : 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) {
      AddPrices codeExample = new AddPrices();
      Console.WriteLine(codeExample.Description);
      try {
        long campaignId = long.Parse("INSERT_CAMPAIGN_ID_HERE");
        codeExample.Run(new AdWordsUser(), campaignId);
      } catch (Exception e) {
        Console.WriteLine("An exception occurred while running this code example. {0}",
            ExampleUtilities.FormatException(e));
      }
    }

    /// <summary>
    /// Returns a description about the code example.
    /// </summary>
    public override string Description {
      get {
        return "This code example adds a price extension and associates it with an account. " +
            "Campaign targeting is also set using the specified campaign ID. To get campaigns, " +
            "run AddCampaigns.cs.";
      }
    }

    /// <summary>
    /// Runs the code example.
    /// </summary>
    /// <param name="user">The AdWords user.</param>
    /// <param name="campaignId">Id of the campaign to which sitelinks will
    /// be added.</param>
    public void Run(AdWordsUser user, long campaignId) {
      // Get the CustomerExtensionSettingService.
      CustomerExtensionSettingService customerExtensionSettingService =
          (CustomerExtensionSettingService) user.GetService(
               AdWordsService.v201708.CustomerExtensionSettingService);

      // Create the price extension feed item.
      PriceFeedItem priceFeedItem = new PriceFeedItem() {
        priceExtensionType = PriceExtensionType.SERVICES,

        // Price qualifier is optional.
        priceQualifier = PriceExtensionPriceQualifier.FROM,
        trackingUrlTemplate = "http://tracker.example.com/?u={lpurl}",
        language = "en",

        campaignTargeting = new FeedItemCampaignTargeting() {
          TargetingCampaignId = campaignId,
        },
        scheduling = new FeedItemSchedule[] {
          new FeedItemSchedule() {
            dayOfWeek = DayOfWeek.SATURDAY,
            startHour = 10,
            startMinute = MinuteOfHour.ZERO,
            endHour = 22,
            endMinute = MinuteOfHour.ZERO
          },
          new FeedItemSchedule() {
            dayOfWeek = DayOfWeek.SUNDAY,
            startHour = 10,
            startMinute = MinuteOfHour.ZERO,
            endHour = 18,
            endMinute = MinuteOfHour.ZERO
          }
        }
      };

      // To create a price extension, at least three table rows are needed.
      List<PriceTableRow> priceTableRows = new List<PriceTableRow>();
      String currencyCode = "USD";
      priceTableRows.Add(
          CreatePriceTableRow(
              "Scrubs",
              "Body Scrub, Salt Scrub",
              "http://www.example.com/scrubs",
              "http://m.example.com/scrubs",
              60000000,
              currencyCode,
              PriceExtensionPriceUnit.PER_HOUR));
      priceTableRows.Add(
          CreatePriceTableRow(
              "Hair Cuts",
              "Once a month",
              "http://www.example.com/haircuts",
              "http://m.example.com/haircuts",
              75000000,
              currencyCode,
              PriceExtensionPriceUnit.PER_MONTH));
      priceTableRows.Add(
          CreatePriceTableRow(
              "Skin Care Package",
              "Four times a month",
              "http://www.example.com/skincarepackage",
              null,
              250000000,
              currencyCode,
              PriceExtensionPriceUnit.PER_MONTH));

      priceFeedItem.tableRows = priceTableRows.ToArray();

      // Create your campaign extension settings. This associates the sitelinks
      // to your campaign.
      CustomerExtensionSetting customerExtensionSetting = new CustomerExtensionSetting() {
        extensionType = FeedType.PRICE,
        extensionSetting = new ExtensionSetting() {
          extensions = new ExtensionFeedItem[] { priceFeedItem }
        }
      };

      CustomerExtensionSettingOperation operation = new CustomerExtensionSettingOperation() {
        operand = customerExtensionSetting,
        @operator = Operator.ADD
      };

      try {
        // Add the extensions.
        CustomerExtensionSettingReturnValue retVal =
            customerExtensionSettingService.mutate(
                new CustomerExtensionSettingOperation[] { operation });
        if (retVal.value != null && retVal.value.Length > 0) {
          CustomerExtensionSetting newExtensionSetting = retVal.value[0];
          Console.WriteLine("Extension setting with type '{0}' was added.",
              newExtensionSetting.extensionType);
        } else {
          Console.WriteLine("No extension settings were created.");
        }
      } catch (Exception e) {
        throw new System.ApplicationException("Failed to create extension settings.", e);
      }
    }

    /// <summary>
    /// Creates a price table row.
    /// </summary>
    /// <param name="header">The row header.</param>
    /// <param name="description">The description text.</param>
    /// <param name="finalUrl">The final URL.</param>
    /// <param name="finalMobileUrl">The mobile final URL, or null if this field
    /// should not be set.</param>
    /// <param name="priceInMicros">The price in micros.</param>
    /// <param name="currencyCode">The currency code.</param>
    /// <param name="priceUnit">The price unit.</param>
    /// <returns>A price table row for creating price extension.</returns>
    private static PriceTableRow CreatePriceTableRow(String header, String description,
        String finalUrl, String finalMobileUrl, long priceInMicros, String currencyCode,
        PriceExtensionPriceUnit priceUnit) {
      PriceTableRow retval = new PriceTableRow() {
        header = header,
        description = description,
        finalUrls = new UrlList() {
          urls = new String[] { finalUrl }
        },
        price = new MoneyWithCurrency() {
          currencyCode = currencyCode,
          money = new Money() {
            microAmount = priceInMicros
          }
        },
        priceUnit = priceUnit
      };

      // Optional: set the mobile final URLs.
      if (!string.IsNullOrEmpty(finalMobileUrl)) {
        retval.finalMobileUrls = new UrlList () {
          urls = new String[] { finalMobileUrl }
        };
      }
      return retval;
    }
  }
}

Add sitelinks to a campaign

// Copyright 2017, Google Inc. All Rights Reserved.
//
// 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.Api.Ads.AdWords.Lib;
using Google.Api.Ads.AdWords.v201708;

using System;
using System.Collections.Generic;

using DayOfWeek = Google.Api.Ads.AdWords.v201708.DayOfWeek;

namespace Google.Api.Ads.AdWords.Examples.CSharp.v201708 {

  /// <summary>
  /// This code example adds sitelinks to a campaign. To create a campaign,
  /// run AddCampaign.cs.
  /// </summary>
  public class AddSitelinks : 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) {
      AddSitelinks codeExample = new AddSitelinks();
      Console.WriteLine(codeExample.Description);
      try {
        long campaignId = long.Parse("INSERT_CAMPAIGN_ID_HERE");
        codeExample.Run(new AdWordsUser(), campaignId);
      } catch (Exception e) {
        Console.WriteLine("An exception occurred while running this code example. {0}",
            ExampleUtilities.FormatException(e));
      }
    }

    /// <summary>
    /// Returns a description about the code example.
    /// </summary>
    public override string Description {
      get {
        return "This code example adds sitelinks to a campaign. To create a campaign, run " +
            "AddCampaign.cs.";
      }
    }

    /// <summary>
    /// Runs the code example.
    /// </summary>
    /// <param name="user">The AdWords user.</param>
    /// <param name="campaignId">Id of the campaign to which sitelinks will
    /// be added.</param>
    public void Run(AdWordsUser user, long campaignId) {
      // Get the CampaignExtensionSettingService.
      CampaignExtensionSettingService campaignExtensionSettingService =
          (CampaignExtensionSettingService) user.GetService(
               AdWordsService.v201708.CampaignExtensionSettingService);

      CustomerService customerService = (CustomerService) user.GetService(
          AdWordsService.v201708.CustomerService);

      // Find the matching customer and its time zone. The getCustomers method
      // will return a single Customer object corresponding to the session's
      // clientCustomerId.
      Customer customer = customerService.getCustomers()[0];
      Console.WriteLine("Found customer ID {0:###-###-####} with time zone '{1}'.",
        customer.customerId, customer.dateTimeZone);

      List<ExtensionFeedItem> extensions = new List<ExtensionFeedItem>();

      // Create your sitelinks.
      SitelinkFeedItem sitelink1 = new SitelinkFeedItem() {
        sitelinkText = "Store Hours",
        sitelinkFinalUrls = new UrlList() {
          urls = new string[] { "http://www.example.com/storehours" }
        }
      };
      extensions.Add(sitelink1);

      DateTime startOfThanksGiving = new DateTime(DateTime.Now.Year, 11, 20, 0, 0, 0);
      DateTime endOfThanksGiving = new DateTime(DateTime.Now.Year, 11, 27, 23, 59, 59);

      // Add check to make sure we don't create a sitelink with end date in the
      // past.
      if (DateTime.Now < endOfThanksGiving) {
        // Show the Thanksgiving specials link only from 20 - 27 Nov.
        SitelinkFeedItem sitelink2 = new SitelinkFeedItem() {
          sitelinkText = "Thanksgiving Specials",
          sitelinkFinalUrls = new UrlList() {
            urls = new string[] { "http://www.example.com/thanksgiving" }
          },
          startTime = string.Format("{0} {1}", startOfThanksGiving.ToString("yyyyMMdd HHmmss"),
              customer.dateTimeZone),
          endTime = string.Format("{0} {1}", endOfThanksGiving.ToString("yyyyMMdd HHmmss"),
              customer.dateTimeZone),

          // Target this sitelink for United States only. See
          // https://developers.google.com/adwords/api/docs/appendix/geotargeting
          // for valid geolocation codes.
          geoTargeting = new Location() {
            id = 2840
          },

          // Restrict targeting only to people physically within the United States.
          // Otherwise, this could also show to people interested in the United States
          // but not physically located there.
          geoTargetingRestriction = new FeedItemGeoRestriction() {
            geoRestriction = GeoRestriction.LOCATION_OF_PRESENCE
          }
        };
        extensions.Add(sitelink2);
      }
      // Show the wifi details primarily for high end mobile users.
      SitelinkFeedItem sitelink3 = new SitelinkFeedItem() {
        sitelinkText = "Wifi available",
        sitelinkFinalUrls = new UrlList() {
          urls = new string[] { "http://www.example.com/mobile/wifi" }
        },
        devicePreference = new FeedItemDevicePreference() {
          // See https://developers.google.com/adwords/api/docs/appendix/platforms
          // for device criteria IDs.
          devicePreference = 30001
        },

        // Target this sitelink for the keyword "free wifi".
        keywordTargeting = new Keyword() {
          text = "free wifi",
          matchType = KeywordMatchType.BROAD
        }
      };
      extensions.Add(sitelink3);

      // Show the happy hours link only during Mon - Fri 6PM to 9PM.
      SitelinkFeedItem sitelink4 = new SitelinkFeedItem() {
        sitelinkText = "Happy hours",
        sitelinkFinalUrls = new UrlList() {
          urls = new string[] { "http://www.example.com/happyhours" },
        },
        scheduling = new FeedItemSchedule[] {
            new FeedItemSchedule() {
                dayOfWeek = DayOfWeek.MONDAY,
                startHour = 18,
                startMinute = MinuteOfHour.ZERO,
                endHour = 21,
                endMinute = MinuteOfHour.ZERO
            },
            new FeedItemSchedule() {
                dayOfWeek = DayOfWeek.TUESDAY,
                startHour = 18,
                startMinute = MinuteOfHour.ZERO,
                endHour = 21,
                endMinute = MinuteOfHour.ZERO
            },
            new FeedItemSchedule() {
                dayOfWeek = DayOfWeek.WEDNESDAY,
                startHour = 18,
                startMinute = MinuteOfHour.ZERO,
                endHour = 21,
                endMinute = MinuteOfHour.ZERO
            },
            new FeedItemSchedule() {
                dayOfWeek = DayOfWeek.THURSDAY,
                startHour = 18,
                startMinute = MinuteOfHour.ZERO,
                endHour = 21,
                endMinute = MinuteOfHour.ZERO
            },
            new FeedItemSchedule() {
                dayOfWeek = DayOfWeek.FRIDAY,
                startHour = 18,
                startMinute = MinuteOfHour.ZERO,
                endHour = 21,
                endMinute = MinuteOfHour.ZERO
            }
        }
      };
      extensions.Add(sitelink4);

      // Create your campaign extension settings. This associates the sitelinks
      // to your campaign.
      CampaignExtensionSetting campaignExtensionSetting = new CampaignExtensionSetting();
      campaignExtensionSetting.campaignId = campaignId;
      campaignExtensionSetting.extensionType = FeedType.SITELINK;
      campaignExtensionSetting.extensionSetting = new ExtensionSetting() {
        extensions = extensions.ToArray()
      };

      CampaignExtensionSettingOperation operation = new CampaignExtensionSettingOperation() {
        operand = campaignExtensionSetting,
        @operator = Operator.ADD
      };

      try {
        // Add the extensions.
        CampaignExtensionSettingReturnValue retVal = campaignExtensionSettingService.mutate(
            new CampaignExtensionSettingOperation[] { operation });

        // Display the results.
        if (retVal.value != null && retVal.value.Length > 0) {
          CampaignExtensionSetting newExtensionSetting = retVal.value[0];
          Console.WriteLine("Extension setting with type = {0} was added to campaign ID {1}.",
              newExtensionSetting.extensionType, newExtensionSetting.campaignId);
        } else {
          Console.WriteLine("No extension settings were created.");
        }
      } catch (Exception e) {
        throw new System.ApplicationException("Failed to create extension settings.", e);
      }
    }
  }
}

Add sitelinks to a campaign using feeds

// Copyright 2017, Google Inc. All Rights Reserved.
//
// 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.Api.Ads.AdWords.Lib;
using Google.Api.Ads.AdWords.v201708;

using System;
using System.Collections.Generic;

namespace Google.Api.Ads.AdWords.Examples.CSharp.v201708 {

  /// <summary>
  /// This code example adds sitelinks to a campaign using feed services.
  /// To create a campaign, run AddCampaign.cs. To add sitelinks using the
  /// simpler ExtensionSetting services, see AddSitelinks.cs.
  /// </summary>
  public class AddSitelinksUsingFeeds : ExampleBase {

    /// <summary>
    /// Holds data about sitelinks in a feed.
    /// </summary>
    private class SitelinksDataHolder {

      /// <summary>
      /// The sitelink feed item IDs.
      /// </summary>
      private List<long> feedItemIds = new List<long>();

      /// <summary>
      /// Gets the sitelink feed item IDs.
      /// </summary>
      public List<long> FeedItemIds {
        get {
          return feedItemIds;
        }
      }

      /// <summary>
      /// Gets or sets the feed ID.
      /// </summary>
      public long FeedId {
        get;
        set;
      }

      /// <summary>
      /// Gets or sets the link text feed attribute ID.
      /// </summary>
      public long LinkTextFeedAttributeId {
        get;
        set;
      }

      /// <summary>
      /// Gets or sets the link URL feed attribute ID.
      /// </summary>
      public long LinkFinalUrlFeedAttributeId {
        get;
        set;
      }

      /// <summary>
      /// Gets or sets the line 2 feed attribute ID.
      /// </summary>
      public long Line2FeedAttributeId {
        get;
        set;
      }

      /// <summary>
      /// Gets or sets the line 3 feed attribute ID.
      /// </summary>
      public long Line3FeedAttributeId {
        get;
        set;
      }
    }

    /// <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) {
      AddSitelinksUsingFeeds codeExample = new AddSitelinksUsingFeeds();
      Console.WriteLine(codeExample.Description);
      try {
        long campaignId = long.Parse("INSERT_CAMPAIGN_ID_HERE");
        string feedName = "INSERT_FEED_NAME_HERE";
        codeExample.Run(new AdWordsUser(), campaignId, feedName);
      } catch (Exception e) {
        Console.WriteLine("An exception occurred while running this code example. {0}",
            ExampleUtilities.FormatException(e));
      }
    }

    /// <summary>
    /// Returns a description about the code example.
    /// </summary>
    public override string Description {
      get {
        return "This code example adds sitelinks to a campaign using feed services. To create a " +
            "campaign, run AddCampaign.cs. To add sitelinks using the simpler ExtensionSetting " +
            "services, see AddSitelinks.cs.";
      }
    }

    /// <summary>
    /// Runs the code example.
    /// </summary>
    /// <param name="user">The AdWords user.</param>
    /// <param name="campaignId">Id of the campaign with which sitelinks are associated.
    /// </param>
    /// <param name="feedName">Name of the feed to be created.</param>
    public void Run(AdWordsUser user, long campaignId, string feedName) {
      SitelinksDataHolder sitelinksData = new SitelinksDataHolder();
      createSitelinksFeed(user, sitelinksData, feedName);
      createSitelinksFeedItems(user, sitelinksData);
      createSitelinksFeedMapping(user, sitelinksData);
      createSitelinksCampaignFeed(user, sitelinksData, campaignId);
    }

    private static void createSitelinksFeed(AdWordsUser user, SitelinksDataHolder sitelinksData,
        string feedName) {
      // Get the FeedService.
      FeedService feedService = (FeedService) user.GetService(AdWordsService.v201708.FeedService);

      // Create attributes.
      FeedAttribute textAttribute = new FeedAttribute();
      textAttribute.type = FeedAttributeType.STRING;
      textAttribute.name = "Link Text";

      FeedAttribute finalUrlAttribute = new FeedAttribute();
      finalUrlAttribute.type = FeedAttributeType.URL_LIST;
      finalUrlAttribute.name = "Link Final URLs";

      FeedAttribute line2Attribute = new FeedAttribute();
      line2Attribute.type = FeedAttributeType.STRING;
      line2Attribute.name = "Line 2";

      FeedAttribute line3Attribute = new FeedAttribute();
      line3Attribute.type = FeedAttributeType.STRING;
      line3Attribute.name = "Line 3";

      // Create the feed.
      Feed sitelinksFeed = new Feed();
      sitelinksFeed.name = feedName;
      sitelinksFeed.attributes = new FeedAttribute[] { textAttribute, finalUrlAttribute,
          line2Attribute, line3Attribute };
      sitelinksFeed.origin = FeedOrigin.USER;

      // Create operation.
      FeedOperation operation = new FeedOperation();
      operation.operand = sitelinksFeed;
      operation.@operator = Operator.ADD;

      // Add the feed.
      FeedReturnValue result = feedService.mutate(new FeedOperation[] { operation });

      Feed savedFeed = result.value[0];
      sitelinksData.FeedId = savedFeed.id;

      FeedAttribute[] savedAttributes = savedFeed.attributes;
      sitelinksData.LinkTextFeedAttributeId = savedAttributes[0].id;
      sitelinksData.LinkFinalUrlFeedAttributeId = savedAttributes[1].id;
      sitelinksData.Line2FeedAttributeId = savedAttributes[2].id;
      sitelinksData.Line3FeedAttributeId = savedAttributes[3].id;

      Console.WriteLine("Feed with name {0} and ID {1} with linkTextAttributeId {2}, " +
          "linkFinalUrlAttributeId {3}, line2AttributeId {4} and line3AttributeId {5} " +
          "was created.", savedFeed.name, savedFeed.id, savedAttributes[0].id,
          savedAttributes[1].id, savedAttributes[2].id, savedAttributes[3].id);
    }

    private static void createSitelinksFeedItems(
        AdWordsUser user, SitelinksDataHolder siteLinksData) {
      // Get the FeedItemService.
      FeedItemService feedItemService =
        (FeedItemService) user.GetService(AdWordsService.v201708.FeedItemService);

      // Create operations to add FeedItems.
      FeedItemOperation home =
          newSitelinkFeedItemAddOperation(siteLinksData,
          "Home", "http://www.example.com", "Home line 2", "Home line 3");
      FeedItemOperation stores =
          newSitelinkFeedItemAddOperation(siteLinksData,
          "Stores", "http://www.example.com/stores", "Stores line 2", "Stores line 3");
      FeedItemOperation onSale =
          newSitelinkFeedItemAddOperation(siteLinksData,
          "On Sale", "http://www.example.com/sale", "On Sale line 2", "On Sale line 3");
      FeedItemOperation support =
          newSitelinkFeedItemAddOperation(siteLinksData,
          "Support", "http://www.example.com/support", "Support line 2", "Support line 3");
      FeedItemOperation products =
          newSitelinkFeedItemAddOperation(siteLinksData,
          "Products", "http://www.example.com/prods", "Products line 2", "Products line 3");

      // This site link is using geographical targeting by specifying the
      // criterion ID for California.
      FeedItemOperation aboutUs =
          newSitelinkFeedItemAddOperation(siteLinksData,
          "About Us", "http://www.example.com/about", "About Us line 2", "About Us line 3", 21137);

      FeedItemOperation[] operations =
          new FeedItemOperation[] { home, stores, onSale, support, products, aboutUs };

      FeedItemReturnValue result = feedItemService.mutate(operations);
      foreach (FeedItem item in result.value) {
        Console.WriteLine("FeedItem with feedItemId {0} was added.", item.feedItemId);
        siteLinksData.FeedItemIds.Add(item.feedItemId);
      }
    }

    // See the Placeholder reference page for a list of all the placeholder types and fields.
    // https://developers.google.com/adwords/api/docs/appendix/placeholders.html
    private const int PLACEHOLDER_SITELINKS = 1;

    // See the Placeholder reference page for a list of all the placeholder types and fields.
    private const int PLACEHOLDER_FIELD_SITELINK_LINK_TEXT = 1;

    private const int PLACEHOLDER_FIELD_SITELINK_FINAL_URL = 5;
    private const int PLACEHOLDER_FIELD_LINE_2_TEXT = 3;
    private const int PLACEHOLDER_FIELD_LINE_3_TEXT = 4;

    private static void createSitelinksFeedMapping(
        AdWordsUser user, SitelinksDataHolder sitelinksData) {
      // Get the FeedItemService.
      FeedMappingService feedMappingService =
        (FeedMappingService) user.GetService(AdWordsService.v201708.FeedMappingService);

      // Map the FeedAttributeIds to the fieldId constants.
      AttributeFieldMapping linkTextFieldMapping = new AttributeFieldMapping();
      linkTextFieldMapping.feedAttributeId = sitelinksData.LinkTextFeedAttributeId;
      linkTextFieldMapping.fieldId = PLACEHOLDER_FIELD_SITELINK_LINK_TEXT;

      AttributeFieldMapping linkFinalUrlFieldMapping = new AttributeFieldMapping();
      linkFinalUrlFieldMapping.feedAttributeId = sitelinksData.LinkFinalUrlFeedAttributeId;
      linkFinalUrlFieldMapping.fieldId = PLACEHOLDER_FIELD_SITELINK_FINAL_URL;

      AttributeFieldMapping line2FieldMapping = new AttributeFieldMapping();
      line2FieldMapping.feedAttributeId = sitelinksData.Line2FeedAttributeId;
      line2FieldMapping.fieldId = PLACEHOLDER_FIELD_LINE_2_TEXT;

      AttributeFieldMapping line3FieldMapping = new AttributeFieldMapping();
      line3FieldMapping.feedAttributeId = sitelinksData.Line3FeedAttributeId;
      line3FieldMapping.fieldId = PLACEHOLDER_FIELD_LINE_3_TEXT;

      // Create the FieldMapping and operation.
      FeedMapping feedMapping = new FeedMapping();
      feedMapping.placeholderType = PLACEHOLDER_SITELINKS;
      feedMapping.feedId = sitelinksData.FeedId;
      feedMapping.attributeFieldMappings = new AttributeFieldMapping[] {
        linkTextFieldMapping, linkFinalUrlFieldMapping, line2FieldMapping, line3FieldMapping };

      FeedMappingOperation operation = new FeedMappingOperation();
      operation.operand = feedMapping;
      operation.@operator = Operator.ADD;

      // Save the field mapping.
      FeedMappingReturnValue result =
          feedMappingService.mutate(new FeedMappingOperation[] { operation });

      foreach (FeedMapping savedFeedMapping in result.value) {
        Console.WriteLine(
            "Feed mapping with ID {0} and placeholderType {1} was saved for feed with ID {2}.",
            savedFeedMapping.feedMappingId, savedFeedMapping.placeholderType,
            savedFeedMapping.feedId);
      }
    }

    private static void createSitelinksCampaignFeed(AdWordsUser user,
      SitelinksDataHolder sitelinksData, long campaignId) {
      // Get the CampaignFeedService.
      CampaignFeedService campaignFeedService =
        (CampaignFeedService) user.GetService(AdWordsService.v201708.CampaignFeedService);

      // Construct a matching function that associates the sitelink feeditems
      // to the campaign, and set the device preference to Mobile. See the
      // matching function guide at
      // https://developers.google.com/adwords/api/docs/guides/feed-matching-functions
      // for more details.
      string matchingFunctionString = string.Format(@"
          AND(
            IN(FEED_ITEM_ID, {{{0}}}),
            EQUALS(CONTEXT.DEVICE, 'Mobile')
          )",
          string.Join(",", sitelinksData.FeedItemIds));

      CampaignFeed campaignFeed = new CampaignFeed() {
        feedId = sitelinksData.FeedId,
        campaignId = campaignId,
        matchingFunction = new Function() {
          functionString = matchingFunctionString
        },
        // Specifying placeholder types on the CampaignFeed allows the same feed
        // to be used for different placeholders in different Campaigns.
        placeholderTypes = new int[] { PLACEHOLDER_SITELINKS }
      };

      CampaignFeedOperation operation = new CampaignFeedOperation();
      operation.operand = campaignFeed;
      operation.@operator = Operator.ADD;

      CampaignFeedReturnValue result = campaignFeedService.mutate(
          new CampaignFeedOperation[] { operation });

      foreach (CampaignFeed savedCampaignFeed in result.value) {
        Console.WriteLine("Campaign with ID {0} was associated with feed with ID {1}",
            savedCampaignFeed.campaignId, savedCampaignFeed.feedId);
      }
    }

    private static FeedItemOperation newSitelinkFeedItemAddOperation(
        SitelinksDataHolder sitelinksData, String text, String finalUrl,
        string line2, string line3) {
      return newSitelinkFeedItemAddOperation(sitelinksData, text, finalUrl, line2, line3, null);
    }

    private static FeedItemOperation newSitelinkFeedItemAddOperation(
        SitelinksDataHolder sitelinksData, String text, String finalUrl, string line2,
        string line3, long? locationId) {
      // Create the FeedItemAttributeValues for our text values.
      FeedItemAttributeValue linkTextAttributeValue = new FeedItemAttributeValue();
      linkTextAttributeValue.feedAttributeId = sitelinksData.LinkTextFeedAttributeId;
      linkTextAttributeValue.stringValue = text;

      FeedItemAttributeValue linkFinalUrlAttributeValue = new FeedItemAttributeValue();
      linkFinalUrlAttributeValue.feedAttributeId = sitelinksData.LinkFinalUrlFeedAttributeId;
      linkFinalUrlAttributeValue.stringValues = new string[] { finalUrl };

      FeedItemAttributeValue line2AttributeValue = new FeedItemAttributeValue();
      line2AttributeValue.feedAttributeId = sitelinksData.Line2FeedAttributeId;
      line2AttributeValue.stringValue = line2;

      FeedItemAttributeValue line3AttributeValue = new FeedItemAttributeValue();
      line3AttributeValue.feedAttributeId = sitelinksData.Line3FeedAttributeId;
      line3AttributeValue.stringValue = line3;

      // Create the feed item and operation.
      FeedItem item = new FeedItem();
      item.feedId = sitelinksData.FeedId;

      // OPTIONAL: Use geographical targeting on a feed item.
      // The IDs can be found in the documentation or retrieved with the
      // LocationCriterionService.
      if (locationId != null) {
        item.geoTargeting = new Location() {
          id = locationId.Value,
        };

        // OPTIONAL: Restrict targeting only to people physically within the location.
        item.geoTargetingRestriction = new FeedItemGeoRestriction() {
          geoRestriction = GeoRestriction.LOCATION_OF_PRESENCE
        };
      }

      item.attributeValues =
          new FeedItemAttributeValue[] { linkTextAttributeValue, linkFinalUrlAttributeValue,
            line2AttributeValue, line3AttributeValue };

      FeedItemOperation operation = new FeedItemOperation();
      operation.operand = item;
      operation.@operator = Operator.ADD;

      return operation;
    }
  }
}

Send feedback about...

AdWords API
AdWords API
Need help? Visit our support page.