The code samples below provide examples of common remarketing functions using the AdWords API. Client Library.
Create a remarketing user list (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. package adwords.axis.v201809.remarketing; import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME; import com.google.api.ads.adwords.axis.factory.AdWordsServices; import com.google.api.ads.adwords.axis.utils.v201809.SelectorBuilder; import com.google.api.ads.adwords.axis.v201809.cm.AdWordsConversionTracker; import com.google.api.ads.adwords.axis.v201809.cm.ApiError; import com.google.api.ads.adwords.axis.v201809.cm.ApiException; import com.google.api.ads.adwords.axis.v201809.cm.ConversionTracker; import com.google.api.ads.adwords.axis.v201809.cm.ConversionTrackerPage; import com.google.api.ads.adwords.axis.v201809.cm.ConversionTrackerServiceInterface; import com.google.api.ads.adwords.axis.v201809.cm.Operator; import com.google.api.ads.adwords.axis.v201809.cm.Selector; import com.google.api.ads.adwords.axis.v201809.rm.AdwordsUserListServiceInterface; import com.google.api.ads.adwords.axis.v201809.rm.BasicUserList; import com.google.api.ads.adwords.axis.v201809.rm.UserList; import com.google.api.ads.adwords.axis.v201809.rm.UserListConversionType; import com.google.api.ads.adwords.axis.v201809.rm.UserListMembershipStatus; import com.google.api.ads.adwords.axis.v201809.rm.UserListOperation; import com.google.api.ads.adwords.axis.v201809.rm.UserListReturnValue; import com.google.api.ads.adwords.lib.client.AdWordsSession; import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface; import com.google.api.ads.adwords.lib.selectorfields.v201809.cm.AdwordsUserListField; import com.google.api.ads.common.lib.auth.OfflineCredentials; import com.google.api.ads.common.lib.auth.OfflineCredentials.Api; import com.google.api.ads.common.lib.conf.ConfigurationLoadException; import com.google.api.ads.common.lib.exception.OAuthException; import com.google.api.ads.common.lib.exception.ValidationException; import com.google.api.client.auth.oauth2.Credential; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * This example adds a remarketing user list (a.k.a. audience). * * <p>Credentials and properties in {@code fromFile()} are pulled from the * "ads.properties" file. See README for more info. */ public class AddAudience { public static void main(String[] args) { AdWordsSession session; try { // Generate a refreshable OAuth2 credential. Credential oAuth2Credential = new OfflineCredentials.Builder() .forApi(Api.ADWORDS) .fromFile() .build() .generateCredential(); // Construct an AdWordsSession. session = new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build(); } catch (ConfigurationLoadException cle) { System.err.printf( "Failed to load configuration from the %s file. Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, cle); return; } catch (ValidationException ve) { System.err.printf( "Invalid configuration in the %s file. Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, ve); return; } catch (OAuthException oe) { System.err.printf( "Failed to create OAuth credentials. Check OAuth settings in the %s file. " + "Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, oe); return; } AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance(); try { runExample(adWordsServices, session); } catch (ApiException apiException) { // ApiException is the base class for most exceptions thrown by an API request. Instances // of this exception have a message and a collection of ApiErrors that indicate the // type and underlying cause of the exception. Every exception object in the adwords.axis // packages will return a meaningful value from toString // // ApiException extends RemoteException, so this catch block must appear before the // catch block for RemoteException. System.err.println("Request failed due to ApiException. Underlying ApiErrors:"); if (apiException.getErrors() != null) { int i = 0; for (ApiError apiError : apiException.getErrors()) { System.err.printf(" Error %d: %s%n", i++, apiError); } } } catch (RemoteException re) { System.err.printf( "Request failed unexpectedly due to RemoteException: %s%n", re); } } /** * Runs the example. * * @param adWordsServices the services factory. * @param session the session. * @throws ApiException if the API request failed with one or more service errors. * @throws RemoteException if the API request failed due to other errors. */ public static void runExample( AdWordsServicesInterface adWordsServices, AdWordsSession session) throws RemoteException { // Get the UserListService. AdwordsUserListServiceInterface userListService = adWordsServices.get(session, AdwordsUserListServiceInterface.class); // Get the ConversionTrackerService. ConversionTrackerServiceInterface conversionTrackerService = adWordsServices.get(session, ConversionTrackerServiceInterface.class); // Create conversion type (tag). UserListConversionType conversionType = new UserListConversionType(); conversionType.setName("Mars cruise customers #" + System.currentTimeMillis()); // Create remarketing user list. BasicUserList userList = new BasicUserList(); userList.setName("Mars cruise customers #" + System.currentTimeMillis()); userList.setDescription("A list of mars cruise customers in the last year"); userList.setMembershipLifeSpan(365L); userList.setConversionTypes(new UserListConversionType[] {conversionType}); // You can optionally provide these field(s). userList.setStatus(UserListMembershipStatus.OPEN); // Create operations. UserListOperation operation = new UserListOperation(); operation.setOperand(userList); operation.setOperator(Operator.ADD); UserListOperation[] operations = new UserListOperation[] {operation}; // Add user list. UserListReturnValue result = userListService.mutate(operations); // Display results. // Capture the ID(s) of the conversion. List<String> conversionIds = new ArrayList<>(); for (UserList userListResult : result.getValue()) { if (userListResult instanceof BasicUserList) { BasicUserList remarketingUserList = (BasicUserList) userListResult; for (UserListConversionType userListConversionType : remarketingUserList.getConversionTypes()) { conversionIds.add(userListConversionType.getId().toString()); } } } // Create predicate and selector. Selector selector = new SelectorBuilder() .fields("Id", "GoogleGlobalSiteTag", "GoogleEventSnippet") .in(AdwordsUserListField.Id, conversionIds.toArray(new String[0])) .build(); // Get all conversion trackers. Map<Long, AdWordsConversionTracker> conversionTrackers = new HashMap<Long, AdWordsConversionTracker>(); ConversionTrackerPage page = conversionTrackerService.get(selector); if (page != null && page.getEntries() != null) { conversionTrackers = Arrays.stream(page.getEntries()) .collect( Collectors.toMap( conversionTracker -> conversionTracker.getId(), conversionTracker -> (AdWordsConversionTracker) conversionTracker)); } // Display user lists. for (UserList userListResult : result.getValue()) { System.out.printf("User list with name '%s' and ID %d was added.%n", userListResult.getName(), userListResult.getId()); // Display user list associated conversion code snippets. if (userListResult instanceof BasicUserList) { BasicUserList remarketingUserList = (BasicUserList) userListResult; for (UserListConversionType userListConversionType : remarketingUserList .getConversionTypes()) { ConversionTracker conversionTracker = conversionTrackers.get(userListConversionType.getId()); System.out.printf( "Google global site tag:%n%s%n%n", conversionTracker.getGoogleGlobalSiteTag()); System.out.printf( "Google event snippet:%n%s%n%n", conversionTracker.getGoogleEventSnippet()); } } } } }
Create an AdWords conversion tracker and add to it upload 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. package adwords.axis.v201809.remarketing; import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME; import com.google.api.ads.adwords.axis.factory.AdWordsServices; import com.google.api.ads.adwords.axis.v201809.cm.AdWordsConversionTracker; import com.google.api.ads.adwords.axis.v201809.cm.ApiError; import com.google.api.ads.adwords.axis.v201809.cm.ApiException; import com.google.api.ads.adwords.axis.v201809.cm.ConversionTracker; import com.google.api.ads.adwords.axis.v201809.cm.ConversionTrackerCategory; import com.google.api.ads.adwords.axis.v201809.cm.ConversionTrackerOperation; import com.google.api.ads.adwords.axis.v201809.cm.ConversionTrackerReturnValue; import com.google.api.ads.adwords.axis.v201809.cm.ConversionTrackerServiceInterface; import com.google.api.ads.adwords.axis.v201809.cm.ConversionTrackerStatus; import com.google.api.ads.adwords.axis.v201809.cm.Operator; import com.google.api.ads.adwords.axis.v201809.cm.UploadConversion; import com.google.api.ads.adwords.lib.client.AdWordsSession; import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface; import com.google.api.ads.common.lib.auth.OfflineCredentials; import com.google.api.ads.common.lib.auth.OfflineCredentials.Api; import com.google.api.ads.common.lib.conf.ConfigurationLoadException; import com.google.api.ads.common.lib.exception.OAuthException; import com.google.api.ads.common.lib.exception.ValidationException; import com.google.api.client.auth.oauth2.Credential; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; /** * This example adds an AdWords conversion and an upload conversion tracker. * * <p>Credentials and properties in {@code fromFile()} are pulled from the * "ads.properties" file. See README for more info. */ public class AddConversionTrackers { public static void main(String[] args) { AdWordsSession session; try { // Generate a refreshable OAuth2 credential. Credential oAuth2Credential = new OfflineCredentials.Builder() .forApi(Api.ADWORDS) .fromFile() .build() .generateCredential(); // Construct an AdWordsSession. session = new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build(); } catch (ConfigurationLoadException cle) { System.err.printf( "Failed to load configuration from the %s file. Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, cle); return; } catch (ValidationException ve) { System.err.printf( "Invalid configuration in the %s file. Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, ve); return; } catch (OAuthException oe) { System.err.printf( "Failed to create OAuth credentials. Check OAuth settings in the %s file. " + "Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, oe); return; } AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance(); try { runExample(adWordsServices, session); } catch (ApiException apiException) { // ApiException is the base class for most exceptions thrown by an API request. Instances // of this exception have a message and a collection of ApiErrors that indicate the // type and underlying cause of the exception. Every exception object in the adwords.axis // packages will return a meaningful value from toString // // ApiException extends RemoteException, so this catch block must appear before the // catch block for RemoteException. System.err.println("Request failed due to ApiException. Underlying ApiErrors:"); if (apiException.getErrors() != null) { int i = 0; for (ApiError apiError : apiException.getErrors()) { System.err.printf(" Error %d: %s%n", i++, apiError); } } } catch (RemoteException re) { System.err.printf( "Request failed unexpectedly due to RemoteException: %s%n", re); } } /** * Runs the example. * * @param adWordsServices the services factory. * @param session the session. * @throws ApiException if the API request failed with one or more service errors. * @throws RemoteException if the API request failed due to other errors. */ public static void runExample( AdWordsServicesInterface adWordsServices, AdWordsSession session) throws RemoteException { // Get the ConversionTrackerService. ConversionTrackerServiceInterface service = adWordsServices.get(session, ConversionTrackerServiceInterface.class); List<ConversionTracker> conversionTrackers = new ArrayList<>(); // Create an AdWords conversion tracker. AdWordsConversionTracker adWordsConversionTracker = new AdWordsConversionTracker(); adWordsConversionTracker.setName("Earth to Mars Cruises Conversion # " + System.currentTimeMillis()); adWordsConversionTracker.setCategory(ConversionTrackerCategory.DEFAULT); // You can optionally provide these field(s). adWordsConversionTracker.setStatus(ConversionTrackerStatus.ENABLED); adWordsConversionTracker.setViewthroughLookbackWindow(15); adWordsConversionTracker.setDefaultRevenueValue(1d); adWordsConversionTracker.setAlwaysUseDefaultRevenueValue(Boolean.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.setCategory(ConversionTrackerCategory.LEAD); uploadConversion.setName("Upload Conversion #" + System.currentTimeMillis()); uploadConversion.setViewthroughLookbackWindow(30); uploadConversion.setCtcLookbackWindow(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.setDefaultRevenueCurrencyCode("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.setDefaultRevenueValue(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.setIsExternallyAttributed(true); conversionTrackers.add(uploadConversion); // Create operations. List<ConversionTrackerOperation> operations = conversionTrackers.stream() .map( conversionTracker -> { ConversionTrackerOperation operation = new ConversionTrackerOperation(); operation.setOperator(Operator.ADD); operation.setOperand(conversionTracker); return operation; }) .collect(Collectors.toList()); // Add the conversions. ConversionTrackerReturnValue result = service.mutate(operations.toArray(new ConversionTrackerOperation[operations.size()])); // Display conversion. for (ConversionTracker conversionTracker : result.getValue()) { System.out.printf( "Conversion with ID %d, name '%s', status '%s', " + "category '%s' was added.%n", conversionTracker.getId(), conversionTracker.getName(), conversionTracker.getStatus(), conversionTracker.getCategory()); if (conversionTracker instanceof AdWordsConversionTracker) { System.out.printf( "Google global site tag:%n%s%n%n", conversionTracker.getGoogleGlobalSiteTag()); System.out.printf( "Google event snippet:%n%s%n%n", conversionTracker.getGoogleEventSnippet()); } } } }
Create and populate a 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. package adwords.axis.v201809.remarketing; import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME; import com.google.api.ads.adwords.axis.factory.AdWordsServices; import com.google.api.ads.adwords.axis.v201809.cm.ApiError; import com.google.api.ads.adwords.axis.v201809.cm.ApiException; import com.google.api.ads.adwords.axis.v201809.cm.Operator; import com.google.api.ads.adwords.axis.v201809.rm.AddressInfo; import com.google.api.ads.adwords.axis.v201809.rm.AdwordsUserListServiceInterface; import com.google.api.ads.adwords.axis.v201809.rm.CrmBasedUserList; import com.google.api.ads.adwords.axis.v201809.rm.CustomerMatchUploadKeyType; import com.google.api.ads.adwords.axis.v201809.rm.Member; import com.google.api.ads.adwords.axis.v201809.rm.MutateMembersOperand; import com.google.api.ads.adwords.axis.v201809.rm.MutateMembersOperation; import com.google.api.ads.adwords.axis.v201809.rm.MutateMembersReturnValue; import com.google.api.ads.adwords.axis.v201809.rm.UserList; import com.google.api.ads.adwords.axis.v201809.rm.UserListOperation; import com.google.api.ads.adwords.axis.v201809.rm.UserListReturnValue; import com.google.api.ads.adwords.lib.client.AdWordsSession; import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface; import com.google.api.ads.common.lib.auth.OfflineCredentials; import com.google.api.ads.common.lib.auth.OfflineCredentials.Api; import com.google.api.ads.common.lib.conf.ConfigurationLoadException; import com.google.api.ads.common.lib.exception.OAuthException; import com.google.api.ads.common.lib.exception.ValidationException; import com.google.api.client.auth.oauth2.Credential; import com.google.common.collect.ImmutableList; import java.io.UnsupportedEncodingException; import java.rmi.RemoteException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; /** * This example adds a user list (a.k.a. audience) and uploads members to populate the list. * * <p> * <em>Note:</em> It may take up to several hours for the list to be populated with members. * Email addresses must be associated with a Google account. * For privacy purposes, the user list size will show as zero until the list has at least 1,000 * members. After that, the size will be rounded to the two most significant digits. * </p> * * <p> * <p>Credentials and properties in {@code fromFile()} are pulled from the * "ads.properties" file. See README for more info. * </p> */ public class AddCrmBasedUserList { private static final ImmutableList<String> EMAILS = ImmutableList.of("client1@example.com", "client2@example.com", " Client3@example.com "); private static final MessageDigest digest = getSHA256MessageDigest(); public static void main(String[] args) { AdWordsSession session; try { // Generate a refreshable OAuth2 credential. Credential oAuth2Credential = new OfflineCredentials.Builder() .forApi(Api.ADWORDS) .fromFile() .build() .generateCredential(); // Construct an AdWordsSession. session = new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build(); } catch (ConfigurationLoadException cle) { System.err.printf( "Failed to load configuration from the %s file. Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, cle); return; } catch (ValidationException ve) { System.err.printf( "Invalid configuration in the %s file. Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, ve); return; } catch (OAuthException oe) { System.err.printf( "Failed to create OAuth credentials. Check OAuth settings in the %s file. " + "Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, oe); return; } AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance(); try { runExample(adWordsServices, session); } catch (ApiException apiException) { // ApiException is the base class for most exceptions thrown by an API request. Instances // of this exception have a message and a collection of ApiErrors that indicate the // type and underlying cause of the exception. Every exception object in the adwords.axis // packages will return a meaningful value from toString // // ApiException extends RemoteException, so this catch block must appear before the // catch block for RemoteException. System.err.println("Request failed due to ApiException. Underlying ApiErrors:"); if (apiException.getErrors() != null) { int i = 0; for (ApiError apiError : apiException.getErrors()) { System.err.printf(" Error %d: %s%n", i++, apiError); } } } catch (RemoteException re) { System.err.printf("Request failed unexpectedly due to RemoteException: %s%n", re); } catch (UnsupportedEncodingException ue) { System.err.printf("Example failed due to encoding exception: %s%n", ue); } } /** * Runs the example. * * @param adWordsServices the services factory. * @param session the session. * @throws ApiException if the API request failed with one or more service errors. * @throws RemoteException if the API request failed due to other errors. * @throws UnsupportedEncodingException if encoding the hashed email failed. */ public static void runExample(AdWordsServicesInterface adWordsServices, AdWordsSession session) throws RemoteException, UnsupportedEncodingException { // Get the UserListService. AdwordsUserListServiceInterface userListService = adWordsServices.get(session, AdwordsUserListServiceInterface.class); // Create a user list. CrmBasedUserList userList = new CrmBasedUserList(); userList.setName("Customer relationship management list #" + System.currentTimeMillis()); userList.setDescription("A list of customers that originated from email addresses"); // CRM-based user lists can use a membershipLifeSpan of 10000 to indicate unlimited; otherwise // normal values apply. userList.setMembershipLifeSpan(30L); userList.setUploadKeyType(CustomerMatchUploadKeyType.CONTACT_INFO); // Create operation. UserListOperation operation = new UserListOperation(); operation.setOperand(userList); operation.setOperator(Operator.ADD); // Add user list. UserListReturnValue result = userListService.mutate(new UserListOperation[] {operation}); // Display user list. UserList userListAdded = result.getValue(0); System.out.printf( "User list with name '%s' and ID %d was added.%n", userListAdded.getName(), userListAdded.getId()); // Get user list ID. Long userListId = userListAdded.getId(); // Create operation to add members to the user list based on email addresses. MutateMembersOperation mutateMembersOperation = new MutateMembersOperation(); MutateMembersOperand operand = new MutateMembersOperand(); operand.setUserListId(userListId); // Hash normalized email addresses based on SHA-256 hashing algorithm. List<Member> members = new ArrayList<>(EMAILS.size()); for (String email : EMAILS) { String normalizedEmail = toNormalizedString(email); Member member = new Member(); member.setHashedEmail(toSHA256String(normalizedEmail)); members.add(member); } String firstName = "John"; String lastName = "Doe"; String countryCode = "US"; String zipCode = "10011"; AddressInfo addressInfo = new AddressInfo(); // First and last name must be normalized and hashed. addressInfo.setHashedFirstName(toSHA256String(toNormalizedString(firstName))); addressInfo.setHashedLastName(toSHA256String(toNormalizedString(lastName))); // Country code and zip code are sent in plaintext. addressInfo.setCountryCode(countryCode); addressInfo.setZipCode(zipCode); Member memberByAddress = new Member(); memberByAddress.setAddressInfo(addressInfo); members.add(memberByAddress); operand.setMembersList(members.toArray(new Member[members.size()])); mutateMembersOperation.setOperand(operand); mutateMembersOperation.setOperator(Operator.ADD); // Add members to the user list based on email addresses. MutateMembersReturnValue mutateMembersResult = userListService.mutateMembers(new MutateMembersOperation[] {mutateMembersOperation}); // Display results. // Reminder: it may take several hours for the list to be populated with members. for (UserList userListResult : mutateMembersResult.getUserLists()) { System.out.printf( "%d email addresses were uploaded to user list with name '%s' and ID %d " + "and are scheduled for review.%n", EMAILS.size(), userListResult.getName(), userListResult.getId()); } } /** * Hash a string using SHA-256 hashing algorithm. * * @param str the string to hash. * @return the SHA-256 hash string representation. * @throws UnsupportedEncodingException If UTF-8 charset is not supported. */ private static String toSHA256String(String str) throws UnsupportedEncodingException { byte[] hash = digest.digest(str.getBytes("UTF-8")); StringBuilder result = new StringBuilder(); for (byte b : hash) { result.append(String.format("%02x", b)); } return result.toString(); } /** * Removes leading and trailing whitespace and converts all characters to lower case. * * @param value the string to normalize. * @return a normalized copy of the string. */ private static String toNormalizedString(String value) { return value.trim().toLowerCase(); } /** Returns SHA-256 hashing algorithm. */ private static MessageDigest getSHA256MessageDigest() { try { return MessageDigest.getInstance("SHA-256"); } catch (NoSuchAlgorithmException e) { throw new RuntimeException("Missing SHA-256 algorithm implementation.", e); } } }
Create rule-based user lists
// 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. package adwords.axis.v201809.remarketing; import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME; import com.google.api.ads.adwords.axis.factory.AdWordsServices; import com.google.api.ads.adwords.axis.v201809.cm.ApiError; import com.google.api.ads.adwords.axis.v201809.cm.ApiException; import com.google.api.ads.adwords.axis.v201809.cm.Operator; import com.google.api.ads.adwords.axis.v201809.rm.AdwordsUserListServiceInterface; import com.google.api.ads.adwords.axis.v201809.rm.CombinedRuleUserList; import com.google.api.ads.adwords.axis.v201809.rm.CombinedRuleUserListRuleOperator; import com.google.api.ads.adwords.axis.v201809.rm.DateKey; import com.google.api.ads.adwords.axis.v201809.rm.DateRuleItem; import com.google.api.ads.adwords.axis.v201809.rm.DateRuleItemDateOperator; import com.google.api.ads.adwords.axis.v201809.rm.DateSpecificRuleUserList; import com.google.api.ads.adwords.axis.v201809.rm.ExpressionRuleUserList; import com.google.api.ads.adwords.axis.v201809.rm.NumberKey; import com.google.api.ads.adwords.axis.v201809.rm.NumberRuleItem; import com.google.api.ads.adwords.axis.v201809.rm.NumberRuleItemNumberOperator; import com.google.api.ads.adwords.axis.v201809.rm.Rule; import com.google.api.ads.adwords.axis.v201809.rm.RuleBasedUserListPrepopulationStatus; import com.google.api.ads.adwords.axis.v201809.rm.RuleItem; import com.google.api.ads.adwords.axis.v201809.rm.RuleItemGroup; import com.google.api.ads.adwords.axis.v201809.rm.StringKey; import com.google.api.ads.adwords.axis.v201809.rm.StringRuleItem; import com.google.api.ads.adwords.axis.v201809.rm.StringRuleItemStringOperator; import com.google.api.ads.adwords.axis.v201809.rm.UserList; import com.google.api.ads.adwords.axis.v201809.rm.UserListOperation; import com.google.api.ads.adwords.axis.v201809.rm.UserListReturnValue; import com.google.api.ads.adwords.axis.v201809.rm.UserListRuleTypeEnumsEnum; import com.google.api.ads.adwords.lib.client.AdWordsSession; import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface; import com.google.api.ads.common.lib.auth.OfflineCredentials; import com.google.api.ads.common.lib.auth.OfflineCredentials.Api; import com.google.api.ads.common.lib.conf.ConfigurationLoadException; import com.google.api.ads.common.lib.exception.OAuthException; import com.google.api.ads.common.lib.exception.ValidationException; import com.google.api.client.auth.oauth2.Credential; import java.rmi.RemoteException; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; import org.joda.time.DateTime; /** * This 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. * * <p>Credentials and properties in {@code fromFile()} are pulled from the * "ads.properties" file. See README for more info. */ public class AddRuleBasedUserLists { private static final String DATE_FORMAT_STRING = "yyyyMMdd"; public static void main(String[] args) { AdWordsSession session; try { // Generate a refreshable OAuth2 credential. Credential oAuth2Credential = new OfflineCredentials.Builder() .forApi(Api.ADWORDS) .fromFile() .build() .generateCredential(); // Construct an AdWordsSession. session = new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build(); } catch (ConfigurationLoadException cle) { System.err.printf( "Failed to load configuration from the %s file. Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, cle); return; } catch (ValidationException ve) { System.err.printf( "Invalid configuration in the %s file. Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, ve); return; } catch (OAuthException oe) { System.err.printf( "Failed to create OAuth credentials. Check OAuth settings in the %s file. " + "Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, oe); return; } AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance(); try { runExample(adWordsServices, session); } catch (ApiException apiException) { // ApiException is the base class for most exceptions thrown by an API request. Instances // of this exception have a message and a collection of ApiErrors that indicate the // type and underlying cause of the exception. Every exception object in the adwords.axis // packages will return a meaningful value from toString // // ApiException extends RemoteException, so this catch block must appear before the // catch block for RemoteException. System.err.println("Request failed due to ApiException. Underlying ApiErrors:"); if (apiException.getErrors() != null) { int i = 0; for (ApiError apiError : apiException.getErrors()) { System.err.printf(" Error %d: %s%n", i++, apiError); } } } catch (RemoteException re) { System.err.printf( "Request failed unexpectedly due to RemoteException: %s%n", re); } } /** * Runs the example. * * @param adWordsServices the services factory. * @param session the session. * @throws ApiException if the API request failed with one or more service errors. * @throws RemoteException if the API request failed due to other errors. */ public static void runExample(AdWordsServicesInterface adWordsServices, AdWordsSession session) throws RemoteException { // Get the AdwordsUserListService. AdwordsUserListServiceInterface userListService = adWordsServices.get(session, AdwordsUserListServiceInterface.class); // First rule item group - users who visited the checkout page and had more than one item // in their shopping cart. StringKey pageTypeKey = new StringKey("ecomm_pagetype"); StringRuleItem checkoutStringRuleItem = new StringRuleItem(); checkoutStringRuleItem.setKey(pageTypeKey); checkoutStringRuleItem.setOp(StringRuleItemStringOperator.EQUALS); checkoutStringRuleItem.setValue("checkout"); RuleItem checkoutRuleItem = new RuleItem(); checkoutRuleItem.setStringRuleItem(checkoutStringRuleItem); NumberKey cartSizeKey = new NumberKey("cartsize"); NumberRuleItem cartSizeNumberRuleItem = new NumberRuleItem(); cartSizeNumberRuleItem.setKey(cartSizeKey); cartSizeNumberRuleItem.setOp(NumberRuleItemNumberOperator.GREATER_THAN); cartSizeNumberRuleItem.setValue(1.0); RuleItem cartSizeRuleItem = new RuleItem(); cartSizeRuleItem.setNumberRuleItem(cartSizeNumberRuleItem); // Combine the two rule items into a RuleItemGroup so AdWords will AND their rules // together. RuleItemGroup checkoutMultipleItemGroup = new RuleItemGroup(); checkoutMultipleItemGroup.setItems(new RuleItem[] {checkoutRuleItem, cartSizeRuleItem}); // Second rule item group - users who checked out within the next 3 months. DateKey checkoutDateKey = new DateKey("checkoutdate"); DateRuleItem startDateDateRuleItem = new DateRuleItem(); startDateDateRuleItem.setKey(checkoutDateKey); startDateDateRuleItem.setOp(DateRuleItemDateOperator.AFTER); startDateDateRuleItem.setValue(DateTime.now().toString(DATE_FORMAT_STRING)); RuleItem startDateRuleItem = new RuleItem(); startDateRuleItem.setDateRuleItem(startDateDateRuleItem); DateRuleItem endDateDateRuleItem = new DateRuleItem(); endDateDateRuleItem.setKey(checkoutDateKey); endDateDateRuleItem.setOp(DateRuleItemDateOperator.BEFORE); endDateDateRuleItem.setValue(DateTime.now().plusMonths(3).toString(DATE_FORMAT_STRING)); RuleItem endDateRuleItem = new RuleItem(); endDateRuleItem.setDateRuleItem(endDateDateRuleItem); // Combine the date rule items into a RuleItemGroup. RuleItemGroup checkedOutNextThreeMonthsItemGroup = new RuleItemGroup(); checkedOutNextThreeMonthsItemGroup.setItems( 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.setGroups( 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.setRuleType(UserListRuleTypeEnumsEnum.DNF); // Third and fourth rule item groups. // Visitors of a page who visited another page. StringKey urlStringKey = new StringKey("url__"); StringRuleItem site1StringRuleItem = new StringRuleItem(); site1StringRuleItem.setKey(urlStringKey); site1StringRuleItem.setOp(StringRuleItemStringOperator.EQUALS); site1StringRuleItem.setValue("example.com/example1"); RuleItem site1RuleItem = new RuleItem(); site1RuleItem.setStringRuleItem(site1StringRuleItem); StringRuleItem site2StringRuleItem = new StringRuleItem(); site2StringRuleItem.setKey(urlStringKey); site2StringRuleItem.setOp(StringRuleItemStringOperator.EQUALS); site2StringRuleItem.setValue("example.com/example2"); RuleItem site2RuleItem = new RuleItem(); site2RuleItem.setStringRuleItem(site2StringRuleItem); // Create two RuleItemGroups to show that a visitor browsed two sites. RuleItemGroup site1RuleItemGroup = new RuleItemGroup(); site1RuleItemGroup.setItems(new RuleItem[]{site1RuleItem}); RuleItemGroup site2RuleItemGroup = new RuleItemGroup(); site2RuleItemGroup.setItems(new RuleItem[]{site2RuleItem}); // Create two rules to show that a visitor browsed two sites. Rule userVisitedSite1Rule = new Rule(); userVisitedSite1Rule.setGroups(new RuleItemGroup[]{site1RuleItemGroup}); Rule userVisitedSite2Rule = new Rule(); userVisitedSite2Rule.setGroups(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.setName( "Expression based user list created at " + creationTimeString); expressionUserList.setDescription( "Users who checked out in three month window OR visited the checkout page " + "with more than one item in their cart"); expressionUserList.setRule(rule); // Optional: Set the prepopulationStatus to REQUESTED to include past users in the user list. expressionUserList.setPrepopulationStatus(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.plusMonths(6); DateSpecificRuleUserList dateUserList = new DateSpecificRuleUserList(); dateUserList.setName( "Date rule user list created at " + creationTimeString); dateUserList.setDescription(String.format("Users who visited the site between %s and %s 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.setRule(rule); // Set the start and end dates of the user list. dateUserList.setStartDate(startDate.toString(DATE_FORMAT_STRING)); dateUserList.setEndDate(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.setName("Combined rule user list created at " + creationTimeString); combinedRuleUserList.setDescription("Users who visited two sites."); combinedRuleUserList.setLeftOperand(userVisitedSite1Rule); combinedRuleUserList.setRightOperand(userVisitedSite2Rule); combinedRuleUserList.setRuleOperator(CombinedRuleUserListRuleOperator.AND); // Create operations to add the user lists. List<UserListOperation> operations = Stream.of(expressionUserList, dateUserList, combinedRuleUserList) .map( userList -> { UserListOperation operation = new UserListOperation(); operation.setOperand(userList); operation.setOperator(Operator.ADD); return operation; }) .collect(Collectors.toList()); // Submit the operations. UserListReturnValue result = userListService.mutate(operations.toArray(new UserListOperation[operations.size()])); // Display the results. for (UserList userListResult : result.getValue()) { System.out.printf("User list added with ID %d, name '%s', status '%s', list type '%s'," + " accountUserListStatus '%s', description '%s'.%n", userListResult.getId(), userListResult.getName(), userListResult.getStatus().getValue(), userListResult.getListType() == null ? null : userListResult.getListType().getValue(), userListResult.getAccountUserListStatus().getValue(), userListResult.getDescription()); } } }
Import conversion adjustments for existing conversions
// Copyright 2018 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 adwords.axis.v201809.remarketing; import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME; import com.beust.jcommander.Parameter; import com.google.api.ads.adwords.axis.factory.AdWordsServices; import com.google.api.ads.adwords.axis.v201809.cm.ApiError; import com.google.api.ads.adwords.axis.v201809.cm.ApiException; import com.google.api.ads.adwords.axis.v201809.cm.GclidOfflineConversionAdjustmentFeed; import com.google.api.ads.adwords.axis.v201809.cm.OfflineConversionAdjustmentFeed; import com.google.api.ads.adwords.axis.v201809.cm.OfflineConversionAdjustmentFeedOperation; import com.google.api.ads.adwords.axis.v201809.cm.OfflineConversionAdjustmentFeedReturnValue; import com.google.api.ads.adwords.axis.v201809.cm.OfflineConversionAdjustmentFeedServiceInterface; import com.google.api.ads.adwords.axis.v201809.cm.OfflineConversionAdjustmentType; import com.google.api.ads.adwords.axis.v201809.cm.Operator; import com.google.api.ads.adwords.lib.client.AdWordsSession; import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface; import com.google.api.ads.adwords.lib.utils.examples.ArgumentNames; import com.google.api.ads.common.lib.auth.OfflineCredentials; import com.google.api.ads.common.lib.auth.OfflineCredentials.Api; import com.google.api.ads.common.lib.conf.ConfigurationLoadException; import com.google.api.ads.common.lib.exception.OAuthException; import com.google.api.ads.common.lib.exception.ValidationException; import com.google.api.ads.common.lib.utils.examples.CodeSampleParams; import com.google.api.client.auth.oauth2.Credential; import java.rmi.RemoteException; import javax.annotation.Nullable; /** * This code example imports conversion adjustments for conversions that already exist. To set up a * conversion tracker, run the AddConversionTrackers.java example. */ public class UploadConversionAdjustment { private static class UploadOfflineConversionsParams extends CodeSampleParams { @Parameter( names = ArgumentNames.CONVERSION_NAME, required = true, description = "Name of the conversion tracker.") private String conversionName; @Parameter(names = ArgumentNames.GCL_ID, required = true) private String gclId; @Parameter(names = ArgumentNames.ADJUSTMENT_TYPE, required = true) private String adjustmentType; @Parameter( names = ArgumentNames.CONVERSION_TIME, required = true, description = "Conversion time should be after the click time.") private String conversionTime; @Parameter(names = ArgumentNames.ADJUSTMENT_TIME, required = true) private String adjustmentTime; @Parameter( names = ArgumentNames.ADJUSTED_VALUE, description = "Adjusted value for restatements.") private Double adjustedValue = null; } public static void main(String[] args) { AdWordsSession session; try { // Generate a refreshable OAuth2 credential. Credential oAuth2Credential = new OfflineCredentials.Builder() .forApi(Api.ADWORDS) .fromFile() .build() .generateCredential(); // Construct an AdWordsSession. session = new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build(); } catch (ConfigurationLoadException cle) { System.err.printf( "Failed to load configuration from the %s file. Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, cle); return; } catch (ValidationException ve) { System.err.printf( "Invalid configuration in the %s file. Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, ve); return; } catch (OAuthException oe) { System.err.printf( "Failed to create OAuth credentials. Check OAuth settings in the %s file. " + "Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, oe); return; } AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance(); UploadOfflineConversionsParams params = new UploadOfflineConversionsParams(); 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.conversionName = "INSERT_CONVERSION_NAME_HERE"; params.gclId = "INSERT_GCL_ID_HERE"; params.adjustmentType = "INSERT_ADJUSTMENT_TYPE_HERE"; params.conversionTime = "INSERT_CONVERSION_TIME_HERE"; params.adjustmentTime = "INSERT_ADJUSTMENT_TIME_HERE"; // Optional: Adjusted value for adjustment type RESTATE. params.adjustedValue = Double.parseDouble("INSERT_ADJUSTED_VALUE_HERE"); } OfflineConversionAdjustmentType adjustmentTypeEnum = OfflineConversionAdjustmentType.fromString(params.adjustmentType); try { runExample( adWordsServices, session, params.conversionName, params.gclId, adjustmentTypeEnum, params.conversionTime, params.adjustmentTime, params.adjustedValue); } catch (ApiException apiException) { // ApiException is the base class for most exceptions thrown by an API request. Instances // of this exception have a message and a collection of ApiErrors that indicate the // type and underlying cause of the exception. Every exception object in the adwords.axis // packages will return a meaningful value from toString // // ApiException extends RemoteException, so this catch block must appear before the // catch block for RemoteException. System.err.println("Request failed due to ApiException. Underlying ApiErrors:"); if (apiException.getErrors() != null) { int i = 0; for (ApiError apiError : apiException.getErrors()) { System.err.printf(" Error %d: %s%n", i++, apiError); } } } catch (RemoteException re) { System.err.printf("Request failed unexpectedly due to RemoteException: %s%n", re); } } /** * Runs the example. * * @param adWordsServices the services factory. * @param session the session. * @param conversionName the name of the conversion tracker. * @param gclId the GCLID for the conversion. * @param adjustmentType the type of adjustment. * @param adjustmentTime the date and time of the adjustment. * @param conversionTime the date and time of the conversion. * @param adjustedValue the adjusted value. * @throws ApiException if the API request failed with one or more service errors. * @throws RemoteException if the API request failed due to other errors. */ public static void runExample( AdWordsServicesInterface adWordsServices, AdWordsSession session, String conversionName, String gclId, OfflineConversionAdjustmentType adjustmentType, String conversionTime, String adjustmentTime, @Nullable Double adjustedValue) throws RemoteException { // Get the OfflineConversionAdjustmentFeedService. OfflineConversionAdjustmentFeedServiceInterface offlineConversionFeedService = adWordsServices.get(session, OfflineConversionAdjustmentFeedServiceInterface.class); // Associate conversion adjustments with the existing named conversion tracker. The GCLID should // have been uploaded before with a conversion. GclidOfflineConversionAdjustmentFeed feed = new GclidOfflineConversionAdjustmentFeed(); feed.setConversionName(conversionName); feed.setAdjustmentType(adjustmentType); feed.setConversionTime(conversionTime); feed.setAdjustmentTime(adjustmentTime); feed.setAdjustedValue(adjustedValue); feed.setGoogleClickId(gclId); OfflineConversionAdjustmentFeedOperation offlineConversionOperation = new OfflineConversionAdjustmentFeedOperation(); offlineConversionOperation.setOperator(Operator.ADD); offlineConversionOperation.setOperand(feed); OfflineConversionAdjustmentFeedReturnValue offlineConversionReturnValue = offlineConversionFeedService.mutate( new OfflineConversionAdjustmentFeedOperation[] {offlineConversionOperation}); for (OfflineConversionAdjustmentFeed newFeed : offlineConversionReturnValue.getValue()) { System.out.printf( "Uploaded conversion adjusted value of %.4f for Google Click ID '%s'.%n", newFeed.getAdjustedValue(), ((GclidOfflineConversionAdjustmentFeed) newFeed).getGoogleClickId()); } } }
Import 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. package adwords.axis.v201809.remarketing; import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME; import com.google.api.ads.adwords.axis.factory.AdWordsServices; import com.google.api.ads.adwords.axis.v201809.cm.ApiError; import com.google.api.ads.adwords.axis.v201809.cm.ApiException; import com.google.api.ads.adwords.axis.v201809.cm.OfflineCallConversionFeed; import com.google.api.ads.adwords.axis.v201809.cm.OfflineCallConversionFeedOperation; import com.google.api.ads.adwords.axis.v201809.cm.OfflineCallConversionFeedReturnValue; import com.google.api.ads.adwords.axis.v201809.cm.OfflineCallConversionFeedServiceInterface; import com.google.api.ads.adwords.axis.v201809.cm.Operator; import com.google.api.ads.adwords.lib.client.AdWordsSession; import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface; import com.google.api.ads.common.lib.auth.OfflineCredentials; import com.google.api.ads.common.lib.auth.OfflineCredentials.Api; import com.google.api.ads.common.lib.conf.ConfigurationLoadException; import com.google.api.ads.common.lib.exception.OAuthException; import com.google.api.ads.common.lib.exception.ValidationException; import com.google.api.client.auth.oauth2.Credential; import java.rmi.RemoteException; /** * This example imports offline call conversion values for calls related to the ads in your account. * * <p>Credentials and properties in {@code fromFile()} are pulled from the "ads.properties" file. * See README for more info. */ public class UploadOfflineCallConversions { public static void main(String[] args) { AdWordsSession session; try { // Generate a refreshable OAuth2 credential. Credential oAuth2Credential = new OfflineCredentials.Builder() .forApi(Api.ADWORDS) .fromFile() .build() .generateCredential(); // Construct an AdWordsSession. session = new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build(); } catch (ConfigurationLoadException cle) { System.err.printf( "Failed to load configuration from the %s file. Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, cle); return; } catch (ValidationException ve) { System.err.printf( "Invalid configuration in the %s file. Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, ve); return; } catch (OAuthException oe) { System.err.printf( "Failed to create OAuth credentials. Check OAuth settings in the %s file. " + "Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, oe); return; } AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance(); // Replace with valid values of your account. String callerId = "INSERT_CALLER_ID_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 String callStartTime = "INSERT_CALL_START_TIME_HERE"; // Name of the conversion tracker to upload to. String conversionName = "INSERT_CONVERSION_NAME_HERE"; String conversionTime = "INSERT_CONVERSION_TIME_HERE"; Double conversionValue = Double.valueOf("INSERT_CONVERSION_VALUE_HERE"); try { runExample( adWordsServices, session, callerId, callStartTime, conversionName, conversionTime, conversionValue); } catch (ApiException apiException) { // ApiException is the base class for most exceptions thrown by an API request. Instances // of this exception have a message and a collection of ApiErrors that indicate the // type and underlying cause of the exception. Every exception object in the adwords.axis // packages will return a meaningful value from toString // // ApiException extends RemoteException, so this catch block must appear before the // catch block for RemoteException. System.err.println("Request failed due to ApiException. Underlying ApiErrors:"); if (apiException.getErrors() != null) { int i = 0; for (ApiError apiError : apiException.getErrors()) { System.err.printf(" Error %d: %s%n", i++, apiError); } } } catch (RemoteException re) { System.err.printf( "Request failed unexpectedly due to RemoteException: %s%n", re); } } /** * Runs the example. * * @param adWordsServices the services factory. * @param session the session. * @param callerId the caller ID of the call. * @param callStartTime the call start time of the call. * @param conversionName the name of the conversion tracker. * @param conversionTime the date and time of the conversion. * @param conversionValue the value of the conversion. * @throws ApiException if the API request failed with one or more service errors. * @throws RemoteException if the API request failed due to other errors. */ public static void runExample( AdWordsServicesInterface adWordsServices, AdWordsSession session, String callerId, String callStartTime, String conversionName, String conversionTime, double conversionValue) throws RemoteException { // Get the OfflineCallConversionFeedService. OfflineCallConversionFeedServiceInterface offlineCallConversionFeedService = adWordsServices.get(session, OfflineCallConversionFeedServiceInterface.class); // 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.setCallerId(callerId); feed.setCallStartTime(callStartTime); feed.setConversionName(conversionName); feed.setConversionTime(conversionTime); feed.setConversionValue(conversionValue); OfflineCallConversionFeedOperation offlineCallConversionOperation = new OfflineCallConversionFeedOperation(); offlineCallConversionOperation.setOperator(Operator.ADD); offlineCallConversionOperation.setOperand(feed); // 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. for (OfflineCallConversionFeed feedResult : offlineCallConversionReturnValue.getValue()) { System.out.printf( "Uploaded offline conversion value of %.4f for caller ID '%s'.%n", feedResult.getConversionValue(), feedResult.getCallerId()); } } }
Import offline click 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. package adwords.axis.v201809.remarketing; import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME; import com.beust.jcommander.Parameter; import com.google.api.ads.adwords.axis.factory.AdWordsServices; import com.google.api.ads.adwords.axis.v201809.cm.ApiError; import com.google.api.ads.adwords.axis.v201809.cm.ApiException; import com.google.api.ads.adwords.axis.v201809.cm.OfflineConversionFeed; import com.google.api.ads.adwords.axis.v201809.cm.OfflineConversionFeedOperation; import com.google.api.ads.adwords.axis.v201809.cm.OfflineConversionFeedReturnValue; import com.google.api.ads.adwords.axis.v201809.cm.OfflineConversionFeedServiceInterface; import com.google.api.ads.adwords.axis.v201809.cm.Operator; import com.google.api.ads.adwords.lib.client.AdWordsSession; import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface; import com.google.api.ads.adwords.lib.utils.examples.ArgumentNames; import com.google.api.ads.common.lib.auth.OfflineCredentials; import com.google.api.ads.common.lib.auth.OfflineCredentials.Api; import com.google.api.ads.common.lib.conf.ConfigurationLoadException; import com.google.api.ads.common.lib.exception.OAuthException; import com.google.api.ads.common.lib.exception.ValidationException; import com.google.api.ads.common.lib.utils.examples.CodeSampleParams; import com.google.api.client.auth.oauth2.Credential; import java.rmi.RemoteException; /** * 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.java example. */ public class UploadOfflineConversions { private static class UploadOfflineConversionsParams extends CodeSampleParams { @Parameter(names = ArgumentNames.CONVERSION_NAME, required = true, description = "Name of the conversion tracker to upload to.") private String conversionName; @Parameter(names = ArgumentNames.GCL_ID, required = true, description = "Google Click ID should be newer than 30 days.") private String gclId; @Parameter(names = ArgumentNames.CONVERSION_TIME, required = true, description = "Conversion time should be after the click time.") private String conversionTime; @Parameter(names = ArgumentNames.CONVERSION_VALUE, required = true) private Double conversionValue; } public static void main(String[] args) { AdWordsSession session; try { // Generate a refreshable OAuth2 credential. Credential oAuth2Credential = new OfflineCredentials.Builder() .forApi(Api.ADWORDS) .fromFile() .build() .generateCredential(); // Construct an AdWordsSession. session = new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build(); } catch (ConfigurationLoadException cle) { System.err.printf( "Failed to load configuration from the %s file. Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, cle); return; } catch (ValidationException ve) { System.err.printf( "Invalid configuration in the %s file. Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, ve); return; } catch (OAuthException oe) { System.err.printf( "Failed to create OAuth credentials. Check OAuth settings in the %s file. " + "Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, oe); return; } AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance(); UploadOfflineConversionsParams params = new UploadOfflineConversionsParams(); 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.conversionName = "INSERT_CONVERSION_NAME_HERE"; params.gclId = "INSERT_GCL_ID_HERE"; params.conversionTime = "INSERT_CONVERSION_TIME_HERE"; params.conversionValue = Double.parseDouble("INSERT_CONVERSION_VALUE_HERE"); } try { runExample( adWordsServices, session, params.conversionName, params.gclId, params.conversionTime, params.conversionValue); } catch (ApiException apiException) { // ApiException is the base class for most exceptions thrown by an API request. Instances // of this exception have a message and a collection of ApiErrors that indicate the // type and underlying cause of the exception. Every exception object in the adwords.axis // packages will return a meaningful value from toString // // ApiException extends RemoteException, so this catch block must appear before the // catch block for RemoteException. System.err.println("Request failed due to ApiException. Underlying ApiErrors:"); if (apiException.getErrors() != null) { int i = 0; for (ApiError apiError : apiException.getErrors()) { System.err.printf(" Error %d: %s%n", i++, apiError); } } } catch (RemoteException re) { System.err.printf( "Request failed unexpectedly due to RemoteException: %s%n", re); } } /** * Runs the example. * * @param adWordsServices the services factory. * @param session the session. * @param conversionName the name of the conversion tracker. * @param gClid the GCLID for the conversion. * @param conversionTime the date and time of the conversion. * @param conversionValue the value of the conversion. * @throws ApiException if the API request failed with one or more service errors. * @throws RemoteException if the API request failed due to other errors. */ public static void runExample(AdWordsServicesInterface adWordsServices, AdWordsSession session, String conversionName, String gClid, String conversionTime, double conversionValue) throws RemoteException { // Get the OfflineConversionFeedService. OfflineConversionFeedServiceInterface offlineConversionFeedService = adWordsServices.get(session, OfflineConversionFeedServiceInterface.class); // 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.setConversionName(conversionName); feed.setConversionTime(conversionTime); feed.setConversionValue(conversionValue); feed.setGoogleClickId(gClid); OfflineConversionFeedOperation offlineConversionOperation = new OfflineConversionFeedOperation(); offlineConversionOperation.setOperator(Operator.ADD); offlineConversionOperation.setOperand(feed); OfflineConversionFeedReturnValue offlineConversionReturnValue = offlineConversionFeedService .mutate(new OfflineConversionFeedOperation[] {offlineConversionOperation}); OfflineConversionFeed newFeed = offlineConversionReturnValue.getValue(0); System.out.printf( "Uploaded offline conversion value of %.4f for Google Click ID '%s' to '%s'.%n", newFeed.getConversionValue(), newFeed.getGoogleClickId(), newFeed.getConversionName()); } }
Upload offline data for store sales transactions
// 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. package adwords.axis.v201809.remarketing; import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME; import com.beust.jcommander.Parameter; import com.google.api.ads.adwords.axis.factory.AdWordsServices; import com.google.api.ads.adwords.axis.v201809.cm.ApiError; import com.google.api.ads.adwords.axis.v201809.cm.ApiException; import com.google.api.ads.adwords.axis.v201809.cm.FieldPathElement; import com.google.api.ads.adwords.axis.v201809.cm.Money; import com.google.api.ads.adwords.axis.v201809.cm.Operator; import com.google.api.ads.adwords.axis.v201809.rm.FirstPartyUploadMetadata; import com.google.api.ads.adwords.axis.v201809.rm.MoneyWithCurrency; import com.google.api.ads.adwords.axis.v201809.rm.OfflineData; import com.google.api.ads.adwords.axis.v201809.rm.OfflineDataUpload; import com.google.api.ads.adwords.axis.v201809.rm.OfflineDataUploadOperation; import com.google.api.ads.adwords.axis.v201809.rm.OfflineDataUploadReturnValue; import com.google.api.ads.adwords.axis.v201809.rm.OfflineDataUploadServiceInterface; import com.google.api.ads.adwords.axis.v201809.rm.OfflineDataUploadType; import com.google.api.ads.adwords.axis.v201809.rm.OfflineDataUploadUserIdentifierType; import com.google.api.ads.adwords.axis.v201809.rm.StoreSalesTransaction; import com.google.api.ads.adwords.axis.v201809.rm.StoreSalesUploadCommonMetadata; import com.google.api.ads.adwords.axis.v201809.rm.ThirdPartyUploadMetadata; import com.google.api.ads.adwords.axis.v201809.rm.UploadMetadata; import com.google.api.ads.adwords.axis.v201809.rm.UserIdentifier; import com.google.api.ads.adwords.lib.client.AdWordsSession; import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface; import com.google.api.ads.adwords.lib.utils.examples.ArgumentNames; import com.google.api.ads.common.lib.auth.OfflineCredentials; import com.google.api.ads.common.lib.auth.OfflineCredentials.Api; import com.google.api.ads.common.lib.conf.ConfigurationLoadException; import com.google.api.ads.common.lib.exception.OAuthException; import com.google.api.ads.common.lib.exception.ValidationException; import com.google.api.ads.common.lib.utils.examples.CodeSampleParams; import com.google.api.client.auth.oauth2.Credential; import com.google.common.collect.ImmutableSet; import java.io.UnsupportedEncodingException; import java.rmi.RemoteException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.joda.time.DateTime; /** * This code example shows how to upload offline data for store sales transactions. * * <p> * <p>Credentials and properties in {@code fromFile()} are pulled from the * "ads.properties" file. See README for more info. * </p> */ public class UploadOfflineData { /** User identifier types whose values must be hashed. */ private static final ImmutableSet<OfflineDataUploadUserIdentifierType> HASHED_IDENTIFIER_TYPES = ImmutableSet.of( OfflineDataUploadUserIdentifierType.HASHED_EMAIL, OfflineDataUploadUserIdentifierType.HASHED_FIRST_NAME, OfflineDataUploadUserIdentifierType.HASHED_LAST_NAME, OfflineDataUploadUserIdentifierType.HASHED_PHONE); /** Digest to use for hashing values. */ private static final MessageDigest digest = getSHA256MessageDigest(); private static final class UploadOfflineDataParams extends CodeSampleParams { /** * Email addresses for the transactions. Exactly two addresses required. You can pass these on * the command line using either of the following options: * * <ol> * <li>Separate parameter name/value pairs, e.g., {@code --emailAddress address1 * --emailAddress address2} * <li>A single name/value pair where the value is comma-separated, e.g., {@code * --emailAddress address1,address2} * </ol> */ @Parameter( names = ArgumentNames.EMAIL_ADDRESS, description = "Email addresses for the transactions. Exactly two addresses required.", required = true ) private List<String> emailAddresses; @Parameter(names = ArgumentNames.CONVERSION_NAME, required = true) private String conversionName; @Parameter(names = ArgumentNames.EXTERNAL_UPLOAD_ID, required = true) private Long externalUploadId; @Parameter(names = ArgumentNames.OFFLINE_DATA_UPLOAD_TYPE) private String offlineDataUploadType = OfflineDataUploadType.STORE_SALES_UPLOAD_FIRST_PARTY.getValue(); @Parameter( names = ArgumentNames.UPLOAD_TIME, description = "Only required if uploading third party data." ) private String advertiserUploadTime; @Parameter( names = ArgumentNames.BRIDGE_MAP_VERSION_ID, description = "Only required if uploading third party data." ) private String bridgeMapVersionId; @Parameter( names = ArgumentNames.PARTNER_ID, description = "Only required if uploading third party data." ) private Integer partnerId; } public static void main(String[] args) { AdWordsSession session; try { // Generate a refreshable OAuth2 credential. Credential oAuth2Credential = new OfflineCredentials.Builder() .forApi(Api.ADWORDS) .fromFile() .build() .generateCredential(); // Construct an AdWordsSession. session = new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build(); } catch (ConfigurationLoadException cle) { System.err.printf( "Failed to load configuration from the %s file. Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, cle); return; } catch (ValidationException ve) { System.err.printf( "Invalid configuration in the %s file. Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, ve); return; } catch (OAuthException oe) { System.err.printf( "Failed to create OAuth credentials. Check OAuth settings in the %s file. " + "Exception: %s%n", DEFAULT_CONFIGURATION_FILENAME, oe); return; } AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance(); UploadOfflineDataParams params = new UploadOfflineDataParams(); 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.emailAddresses = Arrays.asList("INSERT_EMAIL_ADDRESS_1_HERE", "INSERT_EMAIL_ADDRESS_2_HERE"); params.conversionName = "INSERT_CONVERSION_NAME_HERE"; params.externalUploadId = Long.valueOf("INSERT_EXTERNAL_UPLOAD_ID_HERE"); // Change the enum below to STORE_SALES_UPLOAD_THIRD_PARTY if uploading third party data. params.offlineDataUploadType = OfflineDataUploadType.STORE_SALES_UPLOAD_FIRST_PARTY.getValue(); // The three constants below are needed when uploading third party data. // You can safely ignore them if you are uploading first party data. // 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 params.advertiserUploadTime = "INSERT_ADVERTISER_UPLOAD_TIME"; params.bridgeMapVersionId = "INSERT_BRIDGE_MAP_VERSION_ID"; params.partnerId = Integer.valueOf("INSERT_PARTNER_ID"); } OfflineDataUploadType uploadTypeEnum = OfflineDataUploadType.fromString(params.offlineDataUploadType); // Set partial failure to true since this example demonstrates how to handle partial // failure errors. session.setPartialFailure(true); try { runExample( adWordsServices, session, params.conversionName, params.externalUploadId, params.emailAddresses, uploadTypeEnum, params.advertiserUploadTime, params.bridgeMapVersionId, params.partnerId); } catch (ApiException apiException) { // ApiException is the base class for most exceptions thrown by an API request. Instances // of this exception have a message and a collection of ApiErrors that indicate the // type and underlying cause of the exception. Every exception object in the adwords.axis // packages will return a meaningful value from toString // // ApiException extends RemoteException, so this catch block must appear before the // catch block for RemoteException. System.err.println("Request failed due to ApiException. Underlying ApiErrors:"); if (apiException.getErrors() != null) { int i = 0; for (ApiError apiError : apiException.getErrors()) { System.err.printf(" Error %d: %s%n", i++, apiError); } } } catch (RemoteException re) { System.err.printf( "Request failed unexpectedly due to RemoteException: %s%n", re); } catch (UnsupportedEncodingException ue) { System.err.printf("Example failed due to encoding exception: %s%n", ue); } } /** * Runs the example. * * @param adWordsServices the services factory. * @param session the session. * @param conversionName the name of the conversion tracker. * @param externalUploadId the external upload ID. * @param emailAddresses the list of email addresses. Must contain exactly two entries for this * example. * @param offlineDataUploadType the type of store sales upload metadata to upload. * @param advertiserUploadTime the date and time of the advertiser upload. * @param bridgeMapVersionId the bridge map version ID. * @param partnerId the partner ID. * @throws ApiException if the API request failed with one or more service errors. * @throws RemoteException if the API request failed due to other errors. * @throws UnsupportedEncodingException if encoding the offline data values failed. */ public static void runExample( AdWordsServicesInterface adWordsServices, AdWordsSession session, String conversionName, long externalUploadId, List<String> emailAddresses, OfflineDataUploadType offlineDataUploadType, String advertiserUploadTime, String bridgeMapVersionId, Integer partnerId) throws RemoteException, UnsupportedEncodingException { // This example requires exactly 2 email addresses. if (emailAddresses.size() != 2) { throw new IllegalArgumentException( String.format( "%d email addresses specified. Please specify exactly 2 email addresses.", emailAddresses.size())); } // Get the OfflineDataUploadService. OfflineDataUploadServiceInterface offlineDataUploadService = adWordsServices.get(session, OfflineDataUploadServiceInterface.class); List<OfflineData> offlineDataList = new ArrayList<>(); // Create the first offline data for upload. // This transaction occurred 7 days ago with amount of 200 USD. DateTime transactionTime1 = DateTime.now().minusDays(7); long transactionAmount1 = 200_000_000L; List<UserIdentifier> userIdentifiers1 = Arrays.asList( createUserIdentifier( OfflineDataUploadUserIdentifierType.HASHED_EMAIL, emailAddresses.get(0)), createUserIdentifier(OfflineDataUploadUserIdentifierType.STATE, "New York")); offlineDataList.add( createOfflineData( transactionTime1, transactionAmount1, "USD", conversionName, userIdentifiers1)); // Create the second offline data for upload. // This transaction occurred 14 days ago with amount of 450 EUR. DateTime transactionTime2 = DateTime.now().minusDays(14); long transactionAmount2 = 450_000_000L; List<UserIdentifier> userIdentifiers2 = Arrays.asList( createUserIdentifier( OfflineDataUploadUserIdentifierType.HASHED_EMAIL, emailAddresses.get(1)), createUserIdentifier(OfflineDataUploadUserIdentifierType.STATE, "California")); offlineDataList.add( createOfflineData( transactionTime2, transactionAmount2, "EUR", conversionName, userIdentifiers2)); // Create offline data upload object. OfflineDataUpload offlineDataUpload = new OfflineDataUpload(); offlineDataUpload.setExternalUploadId(externalUploadId); offlineDataUpload.setOfflineDataList( offlineDataList.toArray(new OfflineData[offlineDataList.size()])); offlineDataUpload.setUploadType(offlineDataUploadType); // Set the type and metadata of this upload. StoreSalesUploadCommonMetadata storeSalesUploadMetadata; if (OfflineDataUploadType.STORE_SALES_UPLOAD_FIRST_PARTY.equals(offlineDataUploadType)) { storeSalesUploadMetadata = new FirstPartyUploadMetadata(); } else { ThirdPartyUploadMetadata thirdPartyUploadMetadata = new ThirdPartyUploadMetadata(); thirdPartyUploadMetadata.setAdvertiserUploadTime(advertiserUploadTime); thirdPartyUploadMetadata.setValidTransactionRate(1.0); thirdPartyUploadMetadata.setPartnerMatchRate(1.0); thirdPartyUploadMetadata.setPartnerUploadRate(1.0); thirdPartyUploadMetadata.setBridgeMapVersionId(bridgeMapVersionId); thirdPartyUploadMetadata.setPartnerId(partnerId); storeSalesUploadMetadata = thirdPartyUploadMetadata; } storeSalesUploadMetadata.setLoyaltyRate(1.0); storeSalesUploadMetadata.setTransactionUploadRate(1.0); UploadMetadata uploadMetadata = new UploadMetadata(); uploadMetadata.setStoreSalesUploadCommonMetadata(storeSalesUploadMetadata); offlineDataUpload.setUploadMetadata(uploadMetadata); // Create an offline data upload operation. List<OfflineDataUploadOperation> operations = new ArrayList<>(); OfflineDataUploadOperation offlineDataUploadOperation = new OfflineDataUploadOperation(); offlineDataUploadOperation.setOperator(Operator.ADD); offlineDataUploadOperation.setOperand(offlineDataUpload); operations.add(offlineDataUploadOperation); // Upload offline data on the server and print some information. OfflineDataUploadReturnValue returnValue = offlineDataUploadService.mutate(operations.toArray(new OfflineDataUploadOperation[0])); offlineDataUpload = returnValue.getValue(0); System.out.printf( "Uploaded offline data with external upload ID %d, and upload status %s.%n", offlineDataUpload.getExternalUploadId(), offlineDataUpload.getUploadStatus()); // Print any partial failure errors from the response. if (returnValue.getPartialFailureErrors() != null) { for (ApiError apiError : returnValue.getPartialFailureErrors()) { // Get the index of the failed operation from the error's field path elements. Integer operationIndex = getFieldPathElementIndex(apiError, "operations"); if (operationIndex != null) { OfflineDataUpload failedOfflineDataUpload = operations.get(operationIndex).getOperand(); // Get the index of the entry in the offline data list from the error's field path // elements. Integer offlineDataListIndex = getFieldPathElementIndex(apiError, "offlineDataList"); System.out.printf( "Offline data list entry %d in operation %d with external upload ID %d and type " + "'%s' has triggered a failure for the following reason: '%s'.%n", offlineDataListIndex, operationIndex, failedOfflineDataUpload.getExternalUploadId(), failedOfflineDataUpload.getUploadType(), apiError.getErrorString()); } else { System.out.printf( "A failure has occurred for the following reason: %s%n", apiError.getErrorString()); } } } } /** * Returns the {@link FieldPathElement#getIndex()} for the specified {@code field} name, if * present in the error's field path elements. * * @param apiError the error to inspect. * @param field the name of the field to search for in the error's field path elements. * @return the index of the entry with the specified field, or {@code null} if no such entry * exists or the entry has a null index. */ private static Integer getFieldPathElementIndex(ApiError apiError, String field) { FieldPathElement[] fieldPathElements = apiError.getFieldPathElements(); if (fieldPathElements == null) { return null; } for(int i = 0; i < fieldPathElements.length; i++) { FieldPathElement fieldPathElement = fieldPathElements[i]; if (field.equals(fieldPathElement.getField())) { return fieldPathElement.getIndex(); } } return null; } /** Returns a new offline data object with the specified values. */ private static OfflineData createOfflineData( DateTime transactionTime, long transactionMicroAmount, String transactionCurrency, String conversionName, List<UserIdentifier> userIdentifiers) { 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.setTransactionTime(transactionTime.toString("yyyyMMdd HHmmss ZZZ")); storeSalesTransaction.setConversionName(conversionName); storeSalesTransaction.setUserIdentifiers( userIdentifiers.toArray(new UserIdentifier[userIdentifiers.size()])); Money money = new Money(); money.setMicroAmount(transactionMicroAmount); MoneyWithCurrency moneyWithCurrency = new MoneyWithCurrency(); moneyWithCurrency.setMoney(money); moneyWithCurrency.setCurrencyCode(transactionCurrency); storeSalesTransaction.setTransactionAmount(moneyWithCurrency); OfflineData offlineData = new OfflineData(); offlineData.setStoreSalesTransaction(storeSalesTransaction); return offlineData; } /** Returns a new user identifier with the specified type and value. */ private static UserIdentifier createUserIdentifier( OfflineDataUploadUserIdentifierType identifierType, String value) throws UnsupportedEncodingException { // If the user identifier type is a hashed type, also call hash function // on the value. if (HASHED_IDENTIFIER_TYPES.contains(identifierType)) { value = toSHA256String(value); } UserIdentifier userIdentifier = new UserIdentifier(); userIdentifier.setUserIdentifierType(identifierType); userIdentifier.setValue(value); return userIdentifier; } /** * Hash a string using SHA-256 hashing algorithm. * * @param str the string to hash. * @return the SHA-256 hash string representation. * @throws UnsupportedEncodingException If UTF-8 charset is not supported. */ private static String toSHA256String(String str) throws UnsupportedEncodingException { // Normalize the string before hashing. byte[] hash = digest.digest(toNormalizedString(str).getBytes("UTF-8")); StringBuilder result = new StringBuilder(); for (byte b : hash) { result.append(String.format("%02x", b)); } return result.toString(); } /** * Removes leading and trailing whitespace and converts all characters to lower case. * * @param value the string to normalize. * @return a normalized copy of the string. */ private static String toNormalizedString(String value) { return value.trim().toLowerCase(); } /** Returns SHA-256 hashing algorithm. */ private static MessageDigest getSHA256MessageDigest() { try { return MessageDigest.getInstance("SHA-256"); } catch (NoSuchAlgorithmException e) { throw new RuntimeException("Missing SHA-256 algorithm implementation.", e); } } }