Remarketing Samples

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

Add audience

// 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.v201710;

using System;
using System.Collections.Generic;

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

  /// <summary>
  /// This code example illustrates how to create a user list a.k.a. audience.
  /// </summary>
  public class AddAudience : 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) {
      AddAudience codeExample = new AddAudience();
      Console.WriteLine(codeExample.Description);
      try {
        codeExample.Run(new AdWordsUser());
      } 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 illustrates how to create a user list a.k.a. audience.";
      }
    }

    /// <summary>
    /// Runs the code example.
    /// </summary>
    /// <param name="user">The AdWords user.</param>
    public void Run(AdWordsUser user) {
      using (AdwordsUserListService userListService =
          (AdwordsUserListService) user.GetService(
              AdWordsService.v201710.AdwordsUserListService))
      using (ConversionTrackerService conversionTrackerService =
          (ConversionTrackerService) user.GetService(AdWordsService.v201710.
              ConversionTrackerService)) {

        BasicUserList userList = new BasicUserList();
        userList.name = "Mars cruise customers #" + ExampleUtilities.GetRandomString();
        userList.description = "A list of mars cruise customers in the last year.";
        userList.status = UserListMembershipStatus.OPEN;
        userList.membershipLifeSpan = 365;

        UserListConversionType conversionType = new UserListConversionType();
        conversionType.name = userList.name;
        userList.conversionTypes = new UserListConversionType[] { conversionType };

        // Optional: Set the user list status.
        userList.status = UserListMembershipStatus.OPEN;

        // Create the operation.
        UserListOperation operation = new UserListOperation();
        operation.operand = userList;
        operation.@operator = Operator.ADD;

        try {
          // Add the user list.
          UserListReturnValue retval = userListService.mutate(
              new UserListOperation[] { operation });

          UserList[] userLists = null;
          if (retval != null && retval.value != null) {
            userLists = retval.value;
            // Get all conversion snippets
            List<string> conversionIds = new List<string>();
            foreach (BasicUserList newUserList in userLists) {
              if (newUserList.conversionTypes != null) {
                foreach (UserListConversionType newConversionType in newUserList.conversionTypes) {
                  conversionIds.Add(newConversionType.id.ToString());
                }
              }
            }

            Dictionary<long, ConversionTracker> conversionsMap =
                new Dictionary<long, ConversionTracker>();

            if (conversionIds.Count > 0) {
              // Create the selector.
              Selector selector = new Selector() {
                fields = new string[] { ConversionTracker.Fields.Id },
                predicates = new Predicate[] {
                  Predicate.In(ConversionTracker.Fields.Id, conversionIds)
                }
              };

              // Get all conversion trackers.
              ConversionTrackerPage page = conversionTrackerService.get(selector);

              if (page != null && page.entries != null) {
                foreach (ConversionTracker tracker in page.entries) {
                  conversionsMap[tracker.id] = tracker;
                }
              }
            }

            // Display the results.
            foreach (BasicUserList newUserList in userLists) {
              Console.WriteLine("User list with name '{0}' and id '{1}' was added.",
                  newUserList.name, newUserList.id);

              // Display user list associated conversion code snippets.
              if (newUserList.conversionTypes != null) {
                foreach (UserListConversionType userListConversionType in
                    newUserList.conversionTypes) {
                  if (conversionsMap.ContainsKey(userListConversionType.id)) {
                    AdWordsConversionTracker conversionTracker =
                        (AdWordsConversionTracker) conversionsMap[userListConversionType.id];
                    Console.WriteLine("Conversion type code snippet associated to the " +
                        "list:\n{0}\n", conversionTracker.snippet);
                  } else {
                    throw new Exception("Failed to associate conversion type code snippet.");
                  }
                }
              }
            }
          } else {
            Console.WriteLine("No user lists (a.k.a. audiences) were added.");
          }
        } catch (Exception e) {
          throw new System.ApplicationException("Failed to add user lists (a.k.a. audiences).", e);
        }
      }
    }
  }
}

Add conversion trackers

// 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.v201710;

using System;
using System.Collections.Generic;

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

  /// <summary>
  /// This code example adds an AdWords conversion tracker and an upload conversion tracker.
  /// </summary>
  public class AddConversionTrackers : 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) {
      AddConversionTrackers codeExample = new AddConversionTrackers();
      Console.WriteLine(codeExample.Description);
      try {
        codeExample.Run(new AdWordsUser());
      } 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 an AdWords conversion tracker and an upload conversion " +
            "tracker.";
      }
    }

    /// <summary>
    /// Runs the code example.
    /// </summary>
    /// <param name="user">The AdWords user.</param>
    public void Run(AdWordsUser user) {
      using (ConversionTrackerService conversionTrackerService =
          (ConversionTrackerService) user.GetService(AdWordsService.v201710.
              ConversionTrackerService)) {

        List<ConversionTracker> conversionTrackers = new List<ConversionTracker>();

        // Create an Adwords conversion tracker.
        AdWordsConversionTracker adWordsConversionTracker = new AdWordsConversionTracker();
        adWordsConversionTracker.name = "Earth to Mars Cruises Conversion #" +
            ExampleUtilities.GetRandomString();
        adWordsConversionTracker.category = ConversionTrackerCategory.DEFAULT;

        // Set optional fields.
        adWordsConversionTracker.status = ConversionTrackerStatus.ENABLED;
        adWordsConversionTracker.viewthroughLookbackWindow = 15;
        adWordsConversionTracker.defaultRevenueValue = 23.41;
        adWordsConversionTracker.alwaysUseDefaultRevenueValue = true;
        conversionTrackers.Add(adWordsConversionTracker);

        // Create an upload conversion for offline conversion imports.
        UploadConversion uploadConversion = new UploadConversion();
        // Set an appropriate category. This field is optional, and will be set to
        // DEFAULT if not mentioned.
        uploadConversion.category = ConversionTrackerCategory.LEAD;
        uploadConversion.name = "Upload Conversion #" + ExampleUtilities.GetRandomString();
        uploadConversion.viewthroughLookbackWindow = 30;
        uploadConversion.ctcLookbackWindow = 90;

        // Optional: Set the default currency code to use for conversions
        // that do not specify a conversion currency. This must be an ISO 4217
        // 3-character currency code such as "EUR" or "USD".
        // If this field is not set on this UploadConversion, AdWords will use
        // the account's currency.
        uploadConversion.defaultRevenueCurrencyCode = "EUR";

        // Optional: Set the default revenue value to use for conversions
        // that do not specify a conversion value. Note that this value
        // should NOT be in micros.
        uploadConversion.defaultRevenueValue = 2.50;

        // Optional: To upload fractional conversion credits, mark the upload conversion
        // as externally attributed. See
        // https://developers.google.com/adwords/api/docs/guides/conversion-tracking#importing_externally_attributed_conversions
        // to learn more about importing externally attributed conversions.

        // uploadConversion.isExternallyAttributed = true;

        conversionTrackers.Add(uploadConversion);

        try {
          // Create operations.
          List<ConversionTrackerOperation> operations = new List<ConversionTrackerOperation>();
          foreach (ConversionTracker conversionTracker in conversionTrackers) {
            operations.Add(new ConversionTrackerOperation() {
              @operator = Operator.ADD,
              operand = conversionTracker
            });
          }

          // Add conversion tracker.
          ConversionTrackerReturnValue retval = conversionTrackerService.mutate(
              operations.ToArray());

          // Display the results.
          if (retval != null && retval.value != null) {
            foreach (ConversionTracker conversionTracker in retval.value) {
              if (conversionTracker is AdWordsConversionTracker) {
                AdWordsConversionTracker newAdWordsConversionTracker =
                    (AdWordsConversionTracker) conversionTracker;
                Console.WriteLine("Conversion with ID {0}, name '{1}', status '{2}', category " +
                    "'{3}' and snippet '{4}' was added.",
                    newAdWordsConversionTracker.id, newAdWordsConversionTracker.name,
                    newAdWordsConversionTracker.status, newAdWordsConversionTracker.category,
                    newAdWordsConversionTracker.snippet);
              } else {
                Console.WriteLine("Conversion with ID {0}, name '{1}', status '{2}' and " +
                    "category '{3}' was added.", conversionTracker.id, conversionTracker.name,
                    conversionTracker.status, conversionTracker.category);
              }
            }
          } else {
            Console.WriteLine("No conversion trackers were added.");
          }
        } catch (Exception e) {
          throw new System.ApplicationException("Failed to add conversion trackers.", e);
        }
      }
    }
  }
}

Add rule-based user list

// 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.v201710;

using System;
using System.Collections.Generic;

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

  /// <summary>
  /// This code example adds two rule-based remarketing user lists: one with no
  /// site visit date restrictions, and another that will only include users
  /// who visit your site in the next six months. See
  /// https://developers.google.com/adwords/api/docs/guides/rule-based-remarketing
  /// to learn more about rule based remarketing.
  /// </summary>
  public class AddRuleBasedRemarketingList : ExampleBase {
    private const string DATE_FORMAT_STRING = "yyyyMMdd";

    /// <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) {
      AddRuleBasedRemarketingList codeExample = new AddRuleBasedRemarketingList();
      Console.WriteLine(codeExample.Description);
      try {
        codeExample.Run(new AdWordsUser());
      } 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 two rule-based remarketing user lists: one with no " +
            "site visit date restrictions, and another that will only include users who " +
            "visit your site in the next six months. See " +
            "https://developers.google.com/adwords/api/docs/guides/rule-based-remarketing to " +
            "learn more about rule based remarketing.";
      }
    }

    /// <summary>
    /// Runs the code example.
    /// </summary>
    /// <param name="user">The AdWords user.</param>
    public void Run(AdWordsUser user) {
      using (AdwordsUserListService userListService =
          (AdwordsUserListService) user.GetService(
              AdWordsService.v201710.AdwordsUserListService)) {

        // First rule item group - users who visited the checkout page and had
        // more than one item in their shopping cart.
        StringRuleItem checkoutStringRuleItem = new StringRuleItem();
        checkoutStringRuleItem.key = new StringKey();
        checkoutStringRuleItem.key.name = "ecomm_pagetype";
        checkoutStringRuleItem.op = StringRuleItemStringOperator.EQUALS;
        checkoutStringRuleItem.value = "checkout";

        RuleItem checkoutRuleItem = new RuleItem();
        checkoutRuleItem.Item = checkoutStringRuleItem;

        NumberRuleItem cartSizeNumberRuleItem = new NumberRuleItem();
        cartSizeNumberRuleItem.key = new NumberKey();
        cartSizeNumberRuleItem.key.name = "cartsize";
        cartSizeNumberRuleItem.op = NumberRuleItemNumberOperator.GREATER_THAN;
        cartSizeNumberRuleItem.value = 1;

        RuleItem cartSizeRuleItem = new RuleItem();
        cartSizeRuleItem.Item = cartSizeNumberRuleItem;

        // Combine the two rule items into a RuleItemGroup so AdWords will AND
        // their rules together.
        RuleItemGroup checkoutMultipleItemGroup = new RuleItemGroup();
        checkoutMultipleItemGroup.items = new RuleItem[] { checkoutRuleItem, cartSizeRuleItem };

        // Second rule item group - users who check out within the next 3 months.
        DateRuleItem startDateDateRuleItem = new DateRuleItem();
        startDateDateRuleItem.key = new DateKey();
        startDateDateRuleItem.key.name = "checkoutdate";
        startDateDateRuleItem.op = DateRuleItemDateOperator.AFTER;
        startDateDateRuleItem.value = DateTime.Now.ToString(DATE_FORMAT_STRING);
        RuleItem startDateRuleItem = new RuleItem();
        startDateRuleItem.Item = startDateDateRuleItem;

        DateRuleItem endDateDateRuleItem = new DateRuleItem();
        endDateDateRuleItem.key = new DateKey();
        endDateDateRuleItem.key.name = "checkoutdate";
        endDateDateRuleItem.op = DateRuleItemDateOperator.BEFORE;
        endDateDateRuleItem.value = DateTime.Now.AddMonths(3).ToString(DATE_FORMAT_STRING);
        RuleItem endDateRuleItem = new RuleItem();
        endDateRuleItem.Item = endDateDateRuleItem;

        // Combine the date rule items into a RuleItemGroup.
        RuleItemGroup checkedOutNextThreeMonthsItemGroup = new RuleItemGroup();
        checkedOutNextThreeMonthsItemGroup.items =
            new RuleItem[] { startDateRuleItem, endDateRuleItem };

        // Combine the rule item groups into a Rule so AdWords knows how to apply the rules.
        Rule rule = new Rule();
        rule.groups = new RuleItemGroup[] {checkoutMultipleItemGroup,
            checkedOutNextThreeMonthsItemGroup};

        // ExpressionRuleUserLists can use either CNF Or DNF For matching. CNF means
        // 'at least one item in each rule item group must match', and DNF means 'at
        // least one entire rule item group must match'.
        // DateSpecificRuleUserList only supports DNF. You can also omit the rule
        // type altogether To Default To DNF.
        rule.ruleType = UserListRuleTypeEnumsEnum.DNF;

        // Third and fourth rule item groups.
        // Visitors of a page who visited another page. See
        // https://developers.google.com/adwords/api/docs/reference/latest/AdwordsUserListService.StringKey
        // for more details.
        StringKey urlStringKey = new StringKey() {
          name = "url__"
        };

        StringRuleItem site1StringRuleItem = new StringRuleItem();
        site1StringRuleItem.key = urlStringKey;
        site1StringRuleItem.op = StringRuleItemStringOperator.EQUALS;
        site1StringRuleItem.value = "example.com/example1";
        RuleItem site1RuleItem = new RuleItem();
        site1RuleItem.Item = site1StringRuleItem;

        StringRuleItem site2StringRuleItem = new StringRuleItem();
        site2StringRuleItem.key = (urlStringKey);
        site2StringRuleItem.op = (StringRuleItemStringOperator.EQUALS);
        site2StringRuleItem.value = ("example.com/example2");
        RuleItem site2RuleItem = new RuleItem();
        site2RuleItem.Item = (site2StringRuleItem);

        // Create two RuleItemGroups to show that a visitor browsed two sites.
        RuleItemGroup site1RuleItemGroup = new RuleItemGroup();
        site1RuleItemGroup.items = new RuleItem[] { site1RuleItem };
        RuleItemGroup site2RuleItemGroup = new RuleItemGroup();
        site2RuleItemGroup.items = new RuleItem[] { site2RuleItem };

        // Create two rules to show that a visitor browsed two sites.
        Rule userVisitedSite1Rule = new Rule();
        userVisitedSite1Rule.groups = new RuleItemGroup[] { site1RuleItemGroup };

        Rule userVisitedSite2Rule = new Rule();
        userVisitedSite2Rule.groups = new RuleItemGroup[] { site2RuleItemGroup };

        // Create the user list with no restrictions on site visit date.
        ExpressionRuleUserList expressionUserList = new ExpressionRuleUserList();
        String creationTimeString = DateTime.Now.ToString("yyyyMMdd_HHmmss");
        expressionUserList.name = "Expression based user list created at " + creationTimeString;
        expressionUserList.description = "Users who checked out in three month window OR " +
            "visited the checkout page with more than one item in their cart.";
        expressionUserList.rule = rule;

        // Optional: Set the prepopulationStatus to REQUESTED to include past users
        // in the user list.
        expressionUserList.prepopulationStatus = RuleBasedUserListPrepopulationStatus.REQUESTED;

        // Create the user list restricted to users who visit your site within
        // the next six months.
        DateTime startDate = DateTime.Now;
        DateTime endDate = startDate.AddMonths(6);

        DateSpecificRuleUserList dateUserList = new DateSpecificRuleUserList();
        dateUserList.name = "Date rule user list created at " + creationTimeString;
        dateUserList.description = String.Format("Users who visited the site between {0} and " +
            "{1} and checked out in three month window OR visited the checkout page " +
            "with more than one item in their cart.", startDate.ToString(DATE_FORMAT_STRING),
            endDate.ToString(DATE_FORMAT_STRING));
        dateUserList.rule = rule;

        // Set the start and end dates of the user list.
        dateUserList.startDate = startDate.ToString(DATE_FORMAT_STRING);
        dateUserList.endDate = endDate.ToString(DATE_FORMAT_STRING);

        // Create the user list where "Visitors of a page who did visit another page".
        // To create a user list where "Visitors of a page who did not visit another
        // page", change the ruleOperator from AND to AND_NOT.
        CombinedRuleUserList combinedRuleUserList = new CombinedRuleUserList();
        combinedRuleUserList.name = "Combined rule user list created at " + creationTimeString;
        combinedRuleUserList.description = "Users who visited two sites.";
        combinedRuleUserList.leftOperand = userVisitedSite1Rule;
        combinedRuleUserList.rightOperand = userVisitedSite2Rule;
        combinedRuleUserList.ruleOperator = CombinedRuleUserListRuleOperator.AND;

        // Create operations to add the user lists.
        List<UserListOperation> operations = new List<UserListOperation>();
        foreach (UserList userList in new UserList[] { expressionUserList, dateUserList,
          combinedRuleUserList }) {
          UserListOperation operation = new UserListOperation();
          operation.operand = userList;
          operation.@operator = Operator.ADD;
          operations.Add(operation);
        }

        try {
          // Submit the operations.
          UserListReturnValue result = userListService.mutate(operations.ToArray());

          // Display the results.
          foreach (UserList userListResult in result.value) {
            Console.WriteLine("User list added with ID {0}, name '{1}', status '{2}', " +
                "list type '{3}', accountUserListStatus '{4}', description '{5}'.",
                userListResult.id,
                userListResult.name,
                userListResult.status,
                userListResult.listType,
                userListResult.accountUserListStatus,
                userListResult.description);
          }
        } catch (Exception e) {
          throw new System.ApplicationException("Failed to add rule based user lists.", e);
        }
      }
    }
  }
}

Upload offline conversions

// 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.v201710;

using System;

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

  /// <summary>
  /// This code example imports offline conversion values for specific clicks to
  /// your account. To get Google Click ID for a click, run
  /// CLICK_PERFORMANCE_REPORT. To set up a conversion tracker, run the
  /// AddConversionTrackers.cs example.
  /// </summary>
  public class UploadOfflineConversions : 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) {
      string conversionName = "INSERT_CONVERSION_NAME_HERE";
      // GCLID needs to be newer than 30 days.
      string gClId = "INSERT_GOOGLE_CLICK_ID_HERE";
      //  The conversion time should be higher than the click time.
      string conversionTime = "INSERT_CONVERSION_TIME_HERE";
      double conversionValue = double.Parse("INSERT_CONVERSION_VALUE_HERE");

      UploadOfflineConversions codeExample = new UploadOfflineConversions();
      Console.WriteLine(codeExample.Description);
      try {
        codeExample.Run(new AdWordsUser(), conversionName, gClId, conversionTime, conversionValue);
      } 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 imports offline conversion values for specific clicks to " +
          "your account. To get Google Click ID for a click, run CLICK_PERFORMANCE_REPORT. " +
            " To set up a conversion tracker, run the AddConversionTrackers.cs example.";
      }
    }

    /// <summary>
    /// Runs the code example.
    /// </summary>
    /// <param name="user">The AdWords user.</param>
    /// <param name="conversionName">The name of the upload conversion to be
    /// created.</param>
    /// <param name="gClid">The Google Click ID of the click for which offline
    /// conversions are uploaded.</param>
    /// <param name="conversionValue">The conversion value to be uploaded.
    /// </param>
    /// <param name="conversionTime">The conversion time, in yyyymmdd hhmmss
    /// format.</param>
    public void Run(AdWordsUser user, String conversionName, String gClid, String conversionTime,
        double conversionValue) {
      using (OfflineConversionFeedService offlineConversionFeedService =
          (OfflineConversionFeedService) user.GetService(
              AdWordsService.v201710.OfflineConversionFeedService)) {

        try {
          // Associate offline conversions with the existing named conversion tracker. If
          // this tracker was newly created, it may be a few hours before it can accept
          // conversions.
          OfflineConversionFeed feed = new OfflineConversionFeed();
          feed.conversionName = conversionName;
          feed.conversionTime = conversionTime;
          feed.conversionValue = conversionValue;
          feed.googleClickId = gClid;

          // Optional: To upload fractional conversion credits, set the external attribution model
          // and credit. To use this feature, your conversion tracker should be marked as externally
          // attributed. See
          // https://developers.google.com/adwords/api/docs/guides/conversion-tracking#importing_externally_attributed_conversions
          // to learn more about importing externally attributed conversions.

          // feed.externalAttributionModel = "Linear";
          // feed.externalAttributionCredit = 0.3;

          OfflineConversionFeedOperation offlineConversionOperation =
              new OfflineConversionFeedOperation();
          offlineConversionOperation.@operator = Operator.ADD;
          offlineConversionOperation.operand = feed;

          OfflineConversionFeedReturnValue offlineConversionRetval =
              offlineConversionFeedService.mutate(
                  new OfflineConversionFeedOperation[] { offlineConversionOperation });

          OfflineConversionFeed newFeed = offlineConversionRetval.value[0];

          Console.WriteLine("Uploaded offline conversion value of {0} for Google Click ID = " +
              "'{1}' to '{2}'.", newFeed.conversionValue, newFeed.googleClickId,
              newFeed.conversionName);
        } catch (Exception e) {
          throw new System.ApplicationException("Failed upload offline conversions.", e);
        }
      }
    }

  }
}

Upload offline call conversions

// 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.v201710;

using System;

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

  /// <summary>
  /// This code example imports offline call conversion values for calls related to the
  /// ads in your account.
  /// </summary>
  public class UploadOfflineCallConversions : 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) {
      string conversionName = "INSERT_CONVERSION_NAME_HERE";

      // For times use the format yyyyMMdd HHmmss tz. For more details on formats, see:
      // https://developers.google.com/adwords/api/docs/appendix/codes-formats#date-and-time-formats
      // For time zones, see:
      // https://developers.google.com/adwords/api/docs/appendix/codes-formats#timezone-ids

      //  The conversion time should be after the call start time.
      string conversionTime = "INSERT_CONVERSION_TIME_HERE";
      string callStartTime = "INSERT_CALL_START_TIME_HERE";

      string callerId = "INSERT_CALLER_ID_HERE";
      double conversionValue = double.Parse("INSERT_CONVERSION_VALUE_HERE");

      UploadOfflineCallConversions codeExample = new UploadOfflineCallConversions();
      Console.WriteLine(codeExample.Description);
      try {
        codeExample.Run(new AdWordsUser(), conversionName, callStartTime, callerId,
            conversionTime, conversionValue);
      } 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 imports offline call conversion values for calls related " +
            "to the ads in your account.";
      }
    }

    /// <summary>
    /// Runs the code example.
    /// </summary>
    /// <param name="user">The AdWords user.</param>
    /// <param name="conversionName">The name of the call conversion to be updated.</param>
    /// <param name="callStartTime">The call start time.</param>
    /// <param name="conversionValue">The conversion value to be uploaded.</param>
    /// <param name="callerId">The caller ID to be uploaded.</param>
    /// <param name="conversionTime">The conversion time, in yyyymmdd hhmmss
    /// format.</param>
    public void Run(AdWordsUser user, String conversionName, String callStartTime, String callerId,
        String conversionTime, double conversionValue) {
      using (OfflineCallConversionFeedService offlineCallConversionFeedService =
           (OfflineCallConversionFeedService) user.GetService(
               AdWordsService.v201710.OfflineCallConversionFeedService)) {

        // Associate offline call conversions with the existing named conversion tracker. If this
        // tracker was newly created, it may be a few hours before it can accept conversions.
        OfflineCallConversionFeed feed = new OfflineCallConversionFeed();
        feed.callerId = callerId;
        feed.callStartTime = callStartTime;
        feed.conversionName = conversionName;
        feed.conversionTime = conversionTime;
        feed.conversionValue = conversionValue;

        OfflineCallConversionFeedOperation offlineCallConversionOperation =
            new OfflineCallConversionFeedOperation();
        offlineCallConversionOperation.@operator = Operator.ADD;
        offlineCallConversionOperation.operand = feed;

        try {
          // This example uploads only one call conversion, but you can upload
          // multiple call conversions by passing additional operations.
          OfflineCallConversionFeedReturnValue offlineCallConversionReturnValue =
              offlineCallConversionFeedService.mutate(
                  new OfflineCallConversionFeedOperation[] { offlineCallConversionOperation });

          // Display results.
          foreach (OfflineCallConversionFeed feedResult in
              offlineCallConversionReturnValue.value) {
            Console.WriteLine("Uploaded offline call conversion value of {0} for caller ID '{1}'.",
                feedResult.conversionValue, feedResult.callerId);
          }
        } catch (Exception e) {
          throw new System.ApplicationException("Failed to upload offline call conversions.", e);
        }
      }
    }

  }
}

Upload offline data


// 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.v201710;

using Org.BouncyCastle.Crypto.Digests;

using System;
using System.Text;

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

  /// <summary>
  /// This code example shows how to upload offline data for store sales transactions.
  /// </summary>
  public class UploadOfflineData : ExampleBase {

    private static readonly GeneralDigest digest = new Sha256Digest();

    /// <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) {
      // The external upload ID can be any number that you use to keep track of your uploads.
      long externalUploadId = long.Parse("INSERT_EXTERNAL_UPLOAD_ID");

      // Insert the conversion type name that you'd like to attribute this upload to.
      string conversionName = "INSERT_CONVERSION_NAME";

      // Insert email addresses below for creating user identifiers.
      string[] emailAddresses = { "EMAIL_ADDRESS_1", "EMAIL_ADDRESS_2" };

      UploadOfflineData codeExample = new UploadOfflineData();
      Console.WriteLine(codeExample.Description);
      try {
        codeExample.Run(new AdWordsUser(), conversionName, externalUploadId, emailAddresses);
      } 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 shows how to upload offline data for store sales transactions.";
      }
    }

    /// <summary>
    /// Runs the code example.
    /// </summary>
    /// <param name="user">The AdWords user.</param>
    /// <param name="conversionName">The conversion type name that you'd like to attribute this
    /// upload to.</param>
    /// <param name="externalUploadId">The external upload ID can be any number that you use to
    /// keep track of your uploads.</param>
    /// <param name="emailAddresses">The email addresses for creating user identifiers.</param>
    public void Run(AdWordsUser user, string conversionName, long externalUploadId,
        string[] emailAddresses) {
      using (OfflineDataUploadService offlineDataUploadService =
          (OfflineDataUploadService) user.GetService(
              AdWordsService.v201710.OfflineDataUploadService)) {

        // Create the first offline data row for upload.
        // This transaction occurred 7 days ago with amount of 200 USD.
        DateTime transactionTime1 = new DateTime();
        transactionTime1.AddDays(-7);
        long transactionAmount1 = 200000000;
        string transactionCurrencyCode1 = "USD";
        UserIdentifier[] userIdentifierList1 = new UserIdentifier[] {
          CreateUserIdentifier(OfflineDataUploadUserIdentifierType.HASHED_EMAIL,
              emailAddresses[0]),
          CreateUserIdentifier(OfflineDataUploadUserIdentifierType.STATE, "New York")
        };
        OfflineData offlineData1 = CreateOfflineDataRow(transactionTime1, transactionAmount1,
            transactionCurrencyCode1, conversionName, userIdentifierList1);

        // Create the second offline data row for upload.
        // This transaction occurred 14 days ago with amount of 450 EUR.
        DateTime transactionTime2 = new DateTime();
        transactionTime2.AddDays(-14);
        long transactionAmount2 = 450000000;
        string transactionCurrencyCode2 = "EUR";
        UserIdentifier[] userIdentifierList2 = new UserIdentifier[] {
          CreateUserIdentifier(OfflineDataUploadUserIdentifierType.HASHED_EMAIL,
              emailAddresses[1]),
          CreateUserIdentifier(OfflineDataUploadUserIdentifierType.STATE, "California")
        };
        OfflineData offlineData2 = CreateOfflineDataRow(transactionTime2, transactionAmount2,
          transactionCurrencyCode2, conversionName, userIdentifierList2);

        // Create offline data upload object.
        OfflineDataUpload offlineDataUpload = new OfflineDataUpload();
        offlineDataUpload.externalUploadId = externalUploadId;
        offlineDataUpload.offlineDataList = new OfflineData[] { offlineData1, offlineData2 };

        // Optional: You can set the type of this upload.
        // offlineDataUpload.uploadType = OfflineDataUploadType.STORE_SALES_UPLOAD_FIRST_PARTY;

        // Create an offline data upload operation.
        OfflineDataUploadOperation offlineDataUploadOperation = new OfflineDataUploadOperation();
        offlineDataUploadOperation.@operator = Operator.ADD;
        offlineDataUploadOperation.operand = offlineDataUpload;

        try {
          // Upload offline data to the server.
          OfflineDataUploadReturnValue result = offlineDataUploadService.mutate(
              new OfflineDataUploadOperation[] { offlineDataUploadOperation });
          offlineDataUpload = result.value[0];

          // Print the upload ID and status.
          Console.WriteLine("Uploaded offline data with external upload ID {0}, " +
              "and upload status {1}.", offlineDataUpload.externalUploadId,
              offlineDataUpload.uploadStatus);

          // Print any partial data errors from the response. The order of the partial
          // data errors list is the same as the uploaded offline data list in the
          // request.
          if (offlineDataUpload.partialDataErrors != null) {
            for (int i = 0; i < offlineDataUpload.partialDataErrors.Length; i++) {
              ApiError partialDataError = offlineDataUpload.partialDataErrors[i];
              Console.WriteLine("Found a partial error for offline data {0} with error " +
                  "string: {1}.", i + 1, partialDataError.errorString);
            }
          }
        } catch (Exception e) {
          throw new System.ApplicationException("Failed upload offline data conversions.", e);
        }
      }
    }

    /// <summary>
    /// Creates the offline data row from the specified transaction time, transaction micro amount,
    /// transaction currency, conversion name and user identifier list.
    /// </summary>
    /// <param name="transactionTime">The transaction time.</param>
    /// <param name="transactionMicroAmount">The transaction micro amount.</param>
    /// <param name="transactionCurrency">The transaction currency.</param>
    /// <param name="conversionName">Name of the conversion.</param>
    /// <param name="userIdentifierList">The user identifier list.</param>
    /// <returns>The offline data row.</returns>
    OfflineData CreateOfflineDataRow(DateTime transactionTime, long transactionMicroAmount,
        string transactionCurrency, string conversionName, UserIdentifier[] userIdentifierList) {
      StoreSalesTransaction storeSalesTransaction = new StoreSalesTransaction();

      // For times use the format yyyyMMdd HHmmss [tz].
      // For details, see
      // https://developers.google.com/adwords/api/docs/appendix/codes-formats#date-and-time-formats
      storeSalesTransaction.transactionTime = transactionTime.ToString("Ymd His");
      storeSalesTransaction.conversionName = conversionName;
      storeSalesTransaction.userIdentifiers = userIdentifierList;

      Money money = new Money();
      money.microAmount = transactionMicroAmount;
      MoneyWithCurrency moneyWithCurrency = new MoneyWithCurrency();
      moneyWithCurrency.money = money;
      moneyWithCurrency.currencyCode = transactionCurrency;
      storeSalesTransaction.transactionAmount = moneyWithCurrency;

      OfflineData offlineData = new OfflineData();
      offlineData.Item = storeSalesTransaction;

      return offlineData;
    }

    /// <summary>
    /// Hash a string value using SHA-256 hashing algorithm.
    /// </summary>
    /// <param name="digest">Provides the algorithm for SHA-256.</param>
    /// <param name="value">The string value (e.g. an email address) to hash.</param>
    /// <returns>The hashed value.</returns>
    private static String ToSha256String(GeneralDigest digest, String value) {
      byte[] data = Encoding.UTF8.GetBytes(value);
      byte[] digestBytes = new byte[digest.GetDigestSize()];
      digest.BlockUpdate(data, 0, data.Length);
      digest.DoFinal(digestBytes, 0);

      // Convert the byte array into an unhyphenated hexadecimal string.
      return BitConverter.ToString(digestBytes).Replace("-", string.Empty);
    }

    /// <summary>
    /// Creates the user identifier.
    /// </summary>
    /// <param name="type">The user identifier type.</param>
    /// <param name="value">The user identifier value.</param>
    /// <returns></returns>
    UserIdentifier CreateUserIdentifier(OfflineDataUploadUserIdentifierType type, string value) {
      // If the user identifier type is a hashed type, also call hash function
      // on the value.
      if (type.ToString().StartsWith("HASHED_")) {
        value = ToSha256String(digest, ToNormalizedValue(value));
      }
      UserIdentifier userIdentifier = new UserIdentifier();
      userIdentifier.userIdentifierType = type;
      userIdentifier.value = value;

      return userIdentifier;
    }

    /// <summary>
    /// Removes leading and trailing whitespace and converts all characters to
    /// lower case.
    /// </summary>
    /// <param name="value">The value to normalize.</param>
    /// <returns>The normalized value.</returns>
    private static String ToNormalizedValue(String value) {
      return value.Trim().ToLower();
    }
  }
}

Send feedback about...

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