Dzięki kierowaniu na listę klientów możesz wykorzystywać dane online i offline, aby docierać do klientów i zachęcać ich do ponownej interakcji w wyszukiwarce, Gmailu, YouTube, sieci reklamowej i na karcie Zakupy. Na podstawie informacji udostępnionych Ci przez klientów funkcja kierowania na listę klientów kieruje reklamy na tych i podobnych użytkowników. Możesz przesyłać dane z systemu zarządzania relacjami z klientami (CRM) zbiorczo, dodawać lub usuwać dane albo używać tych list użytkowników do tworzenia logical_user_list
.
W omówieniu zarządzania odbiorcami znajdziesz listę różnych typów segmentów odbiorców, które możesz porównać z kierowaniem na listę klientów i innymi opcjami list użytkowników.
Dowiedz się więcej o kierowaniu na listę klientów i kierowaniu na odbiorców.
Wymagania wstępne
Nie wszystkie konta kwalifikują się do korzystania z kierowania na listę klientów. Aby korzystać z funkcji Kierowanie na listę klientów, Twoje konto musi spełniać te wymagania:
- dobrą historię przestrzegania zasad;
- dobrą historię płatności;
Dostępne funkcje zależą od warunków spełnianych przez Twoje konto. Wymagania i ograniczenia dotyczące kwalifikowania się do korzystania z kierowania na listę klientów znajdziesz w zasadach dotyczących tej funkcji.
Zanim zaczniesz: zaplanuj wdrożenie
Zanim zaczniesz pisać kod, zaplanuj wdrożenie kierowania na listę klientów. W tej sekcji opisujemy ogólny proces i najważniejsze kwestie, które pomogą Ci zaprojektować solidną integrację. Gdy będziesz mieć jasny plan, możesz przejść do kolejnych kroków implementacji.
Wzorzec użytkowania
Oto zalecany proces tworzenia listy klientów i kierowania na nią reklam:
Utwórz pustą listę klientów.
Utwórz
OfflineUserDataJob
. Utworzenie jednego dużego zadania jest znacznie wydajniejsze niż utworzenie kilku mniejszych zadań.Upewnij się, że w żądaniach
OfflineUserDataJob
create
wypełniasz poleconsent
wcustomer_match_user_list_metadata
. W przypadku żądańremove
zgoda nie jest wymagana. Interfejs API zwracaOfflineUserDataJobError.CUSTOMER_NOT_ACCEPTED_CUSTOMER_DATA_TERMS
, jeśliconsent.ad_user_data
lubconsent.ad_personalization
zadania ma wartośćDENIED
.Jeśli użytkownik odmówi wyrażenia zgody, możesz utworzyć zadanie z operacją
remove
, aby usunąć identyfikatory użytkownika z listy użytkowników.Jeśli brakuje Ci zgody użytkowników, utwórz osobne zadanie, w którym nie ustawisz pola
consent
wcustomer_match_user_list_metadata
zadania, a następnie dodaj identyfikatory tych użytkowników za pomocą operacjicreate
w tym osobnym zadaniu.Dodaj operacje za pomocą metody
OfflineUserDataJobService.AddOfflineUserDataJobOperations
. Aby zapewnić optymalne przetwarzanie,zalecamy dodawanie maksymalnie 10 000 identyfikatorów w jednym wywołaniu. PojedynczeAddOfflineUserDataJobOperations
żądanie może zawierać maksymalnie 100 tys. identyfikatorów we wszystkich obiektachUserData
na liście operacji.Jeśli na przykład każdy z obiektów
UserData
ma jeden identyfikatorUserIdentifier
dlahashed_email
i drugi identyfikatorUserIdentifier
dlahashed_phone_number
, optymalne jest wysyłanie 5000 obiektówUserData
na żądanie, ponieważ każde żądanie będzie zawierać łącznie 10 000 identyfikatorów użytkownika.Powtarzaj poprzedni krok, aż dodasz wszystkie operacje lub zadanie osiągnie maksymalną pojemność. Nie ma limitu liczby operacji, które możesz dodać do jednego zadania. Zalecamy jednak,aby nie przekraczać 1 000 000 operacji na zadanie,aby zapewnić optymalne przetwarzanie.
Uruchom zadanie. Zadanie musisz uruchomić w ciągu 5 dni od jego utworzenia. W przeciwnym razie zadanie nie będzie już dostępne do uruchomienia.
Sprawdź, czy przesyłanie się powiodło.
Sprawdź współczynnik dopasowania.
Kieruj reklamy na listę.
OfflineUserDataJobService i UserDataService
Dane kierowania na listę klientów można przesyłać za pomocą 2 usług. Wybierz usługę na podstawie przypadku użycia, ponieważ mogą obowiązywać ograniczenia.
Usługi przesyłania danych na potrzeby kierowania na listę klientów | |
---|---|
OfflineUserDataJobService (preferowane)
|
Większość deweloperów korzysta z tej usługi. Jest zoptymalizowana pod kątem przesyłania dużych plików z wysoką przepustowością i po zakończeniu przesyłania zwraca dane o skuteczności. Ten przewodnik dotyczy głównie tej usługi. |
UserDataService
|
Ta usługa jest zoptymalizowana pod kątem przesyłania niewielkiej liczby identyfikatorów naraz z sporadycznymi aktualizacjami i nie jest zoptymalizowana pod kątem ciągłego działania. Limit wynosi 10 operacji na żądanie. Pojedyncze żądanie nie może zawierać więcej niż 100 elementów łącznie we wszystkich user_identifiers .
Wskazówki dotyczące przesyłania danych za pomocą tej usługi znajdziesz w przewodniku po zarządzaniu integracją z kierowaniem na listę klientów. Od wersji 15 interfejsu Google Ads API w żądaniach |
OfflineUserDataJobService
Sprawdzone metody
Podczas projektowania integracji kierowania na listę klientów pamiętaj o tych sprawdzonych metodach:
Nie próbuj używać wielu kont do modyfikowania jednej listy użytkowników. Listę użytkowników może modyfikować tylko konto Google Ads lub konto partnera danych, które ją utworzyło.
Zwiększ liczbę operacji na
AddOfflineUserDataJobOperationsRequest
do maksymalnie 100 000 identyfikatorów, aby uniknąć błędówRESOURCE_EXHAUSTED
.Nie łącz operacji
create
iremove
w ramach tego samegoOfflineUserDataJob
. Może to spowodować błądCONFLICTING_OPERATION
.Włącz
partial_failure
wAddOfflineUserDataJobOperationsRequest
, aby wykrywać problematyczne operacje przed uruchomieniem zadania. Operacje są weryfikowane po przesłaniu doOfflineUserDataJob
.Unikaj jednoczesnego uruchamiania wielu procesów
OfflineUserDataJob
, które modyfikują tę samą listę użytkowników (czyli wielu zadań, którychCustomerMatchUserListMetadata.user_list
odwołuje się do tej samej nazwy zasobu). Może to spowodować błądCONCURRENT_MODIFICATION
ponieważ wiele zadań nie może działać na tej samej liście w tym samym czasie. Ten błąd może też wystąpić, jeśli spróbujesz jednocześnie modyfikować listę za pomocą interfejsu Google Ads i interfejsu Google Ads API. Pamiętaj, że nie dotyczy to dodawania operacji do zadaniaPENDING
, co można zrobić w dowolnym momencie przed rozpoczęciem zadania.Jeśli masz tysiące operacji do zastosowania, utwórz jedną
OfflineUserDataJob
zawierającą wszystkie operacje. Nie twórz kilku zadań, z których każde ma tylko kilkaset operacji, i nie uruchamiaj ich kolejno ani jednocześnie. Jedno duże zadanie ze wszystkimi operacjami jest znacznie wydajniejsze niż wiele małych zadań i zmniejsza ryzyko wystąpienia błędów w przepływie pracy.
Pomysły na to, jak wykorzystać listy klientów do optymalnego kierowania, znajdziesz w Centrum pomocy.
Krok 1. Utwórz listę klientów
Utwórz listę klientów za pomocą UserListService
. Listy klientów są tworzone przez ustawienie pola crm_based_user_list
w obiekcie user_list
. Pole crm_based_user_list
można ustawić w przypadku typów kampanii, które obsługują kierowanie na listy klientów:
Dopasowywanie do klientów w kampaniach różnych typów | |
---|---|
Sieć wyszukiwania | Reklamy wyświetlają się w sieci wyszukiwania. |
Sieć reklamowa | Reklamy wyświetlają się w sieci reklamowej, a w Gmailu tylko wtedy, gdy są w niej kreacje GSP. |
Rozszerzenie na sieć reklamową w kampaniach w sieci wyszukiwania | Reklamy wyświetlają się w sieci wyszukiwania, a w Gmailu tylko wtedy, gdy są dostępne kreacje GSP. |
Kampanie wideo | Reklamy wyświetlają się w YouTube tylko wtedy, gdy są w niej reklamy TrueView In-Stream. |
Kampanie produktowe | Reklamy wyświetlają się na karcie Zakupy. |
crm_based_user_list
zawiera 3 pola:
app_id
: ciąg znaków, który jednoznacznie identyfikuje aplikację mobilną, z której zebrano dane. Jest to wymagane podczas tworzeniaCrmBasedUserList
na potrzeby przesyłania identyfikatorów wyświetlania reklam mobilnych.upload_key_type
: typ klucza dopasowania na liście, który może mieć wartośćCONTACT_INFO
,CRM_ID
lubMOBILE_ADVERTISING_ID
. Na tej samej liście nie można używać różnych typów danych. To pole jest wymagane w przypadku wszystkich list klientów.data_source_type
: źródło danych listy. Wartością domyślną jestFIRST_PARTY
. Klienci, którzy znajdują się na liście dozwolonych, mogą tworzyć listy klientów pochodzące od innych firm.
Atrybut membership_life_span
listy użytkowników umożliwia określenie w dniach okresu, w którym użytkownik jest uznawany za znajdującego się na liście. Wartość parametru membership_life_span
na liście użytkowników kierowania na listę klientów nie może przekraczać 540
, która jest też wartością domyślną.
Atrybut membership_status
określa, czy lista akceptuje nowych użytkowników.
Przykładowy kod do tworzenia listy klientów
Java
private String createCustomerMatchUserList(GoogleAdsClient googleAdsClient, long customerId) { // Creates the new user list. UserList userList = UserList.newBuilder() .setName("Customer Match list #" + getPrintableDateTime()) .setDescription("A list of customers that originated from email addresses") // Membership life span must be between 0 and 540 days inclusive. See: // https://developers.google.com/google-ads/api/reference/rpc/latest/UserList#membership_life_span // Sets the membership life span to 30 days. .setMembershipLifeSpan(30) // Sets the upload key type to indicate the type of identifier that will be used to // add users to the list. This field is immutable and required for a CREATE operation. .setCrmBasedUserList( CrmBasedUserListInfo.newBuilder() .setUploadKeyType(CustomerMatchUploadKeyType.CONTACT_INFO)) .build(); // Creates the operation. UserListOperation operation = UserListOperation.newBuilder().setCreate(userList).build(); // Creates the service client. try (UserListServiceClient userListServiceClient = googleAdsClient.getLatestVersion().createUserListServiceClient()) { // Adds the user list. MutateUserListsResponse response = userListServiceClient.mutateUserLists( Long.toString(customerId), ImmutableList.of(operation)); // Prints the response. System.out.printf( "Created Customer Match user list with resource name: %s.%n", response.getResults(0).getResourceName()); return response.getResults(0).getResourceName(); } }
C#
private string CreateCustomerMatchUserList(GoogleAdsClient client, long customerId) { // Get the UserListService. UserListServiceClient service = client.GetService(Services.V21.UserListService); // Creates the user list. UserList userList = new UserList() { Name = $"Customer Match list# {ExampleUtilities.GetShortRandomString()}", Description = "A list of customers that originated from email and physical" + " addresses", // Membership life span must be between 0 and 540 days inclusive. See: // https://developers.google.com/google-ads/api/reference/rpc/latest/UserList#membership_life_span // Sets the membership life span to 30 days. MembershipLifeSpan = 30, CrmBasedUserList = new CrmBasedUserListInfo() { UploadKeyType = CustomerMatchUploadKeyType.ContactInfo } }; // Creates the user list operation. UserListOperation operation = new UserListOperation() { Create = userList }; // Issues a mutate request to add the user list and prints some information. MutateUserListsResponse response = service.MutateUserLists( customerId.ToString(), new[] { operation }); string userListResourceName = response.Results[0].ResourceName; Console.WriteLine($"User list with resource name '{userListResourceName}' " + $"was created."); return userListResourceName; }
PHP
private static function createCustomerMatchUserList( GoogleAdsClient $googleAdsClient, int $customerId ): string { // Creates the user list. $userList = new UserList([ 'name' => 'Customer Match list #' . Helper::getPrintableDatetime(), 'description' => 'A list of customers that originated from email ' . 'and physical addresses', // Membership life span must be between 0 and 540 days inclusive. See: // https://developers.google.com/google-ads/api/reference/rpc/latest/UserList#membership_life_span // Sets the membership life span to 30 days. 'membership_life_span' => 30, 'crm_based_user_list' => new CrmBasedUserListInfo([ // Sets the upload key type to indicate the type of identifier that will be used to // add users to the list. This field is immutable and required for a CREATE // operation. 'upload_key_type' => CustomerMatchUploadKeyType::CONTACT_INFO ]) ]); // Creates the user list operation. $operation = new UserListOperation(); $operation->setCreate($userList); // Issues a mutate request to add the user list and prints some information. $userListServiceClient = $googleAdsClient->getUserListServiceClient(); $response = $userListServiceClient->mutateUserLists( MutateUserListsRequest::build($customerId, [$operation]) ); $userListResourceName = $response->getResults()[0]->getResourceName(); printf("User list with resource name '%s' was created.%s", $userListResourceName, PHP_EOL); return $userListResourceName; }
Python
def create_customer_match_user_list( client: GoogleAdsClient, customer_id: str ) -> str: """Creates a Customer Match user list. Args: client: The Google Ads client. customer_id: The ID for the customer that owns the user list. Returns: The string resource name of the newly created user list. """ # Creates the UserListService client. user_list_service_client: UserListServiceClient = client.get_service( "UserListService" ) # Creates the user list operation. user_list_operation: UserListOperation = client.get_type( "UserListOperation" ) # Creates the new user list. user_list: UserList = user_list_operation.create user_list.name = f"Customer Match list #{uuid.uuid4()}" user_list.description = ( "A list of customers that originated from email and physical addresses" ) # Sets the upload key type to indicate the type of identifier that is used # to add users to the list. This field is immutable and required for a # CREATE operation. user_list.crm_based_user_list.upload_key_type = ( client.enums.CustomerMatchUploadKeyTypeEnum.CONTACT_INFO ) # Membership life span must be between 0 and 540 days inclusive. See: # https://developers.google.com/google-ads/api/reference/rpc/latest/UserList#membership_life_span # Sets the membership life span to 30 days. user_list.membership_life_span = 30 response: MutateUserListsResponse = ( user_list_service_client.mutate_user_lists( customer_id=customer_id, operations=[user_list_operation] ) ) user_list_resource_name: str = response.results[0].resource_name print( f"User list with resource name '{user_list_resource_name}' was created." ) return user_list_resource_name
Ruby
def create_customer_match_user_list(client, customer_id) # Creates the user list. operation = client.operation.create_resource.user_list do |ul| ul.name = "Customer Match List #{(Time.new.to_f * 1000).to_i}" ul.description = "A list of customers that originated from email and " \ "physical addresses" # Membership life span must be between 0 and 540 days inclusive. See: # https://developers.google.com/google-ads/api/reference/rpc/latest/UserList#membership_life_span # Sets the membership life span to 30 days. ul.membership_life_span = 30 ul.crm_based_user_list = client.resource.crm_based_user_list_info do |crm| crm.upload_key_type = :CONTACT_INFO end end # Issues a mutate request to add the user list and prints some information. response = client.service.user_list.mutate_user_lists( customer_id: customer_id, operations: [operation], ) # Prints out some information about the newly created user list. resource_name = response.results.first.resource_name puts "User list with resource name #{resource_name} was created." resource_name end
Perl
sub create_customer_match_user_list { my ($api_client, $customer_id) = @_; # Create the user list. my $user_list = Google::Ads::GoogleAds::V21::Resources::UserList->new({ name => "Customer Match list #" . uniqid(), description => "A list of customers that originated from email and physical addresses", # Membership life span must be between 0 and 540 days inclusive. See: # https://developers.google.com/google-ads/api/reference/rpc/latest/UserList#membership_life_span # Set the membership life span to 30 days. membershipLifeSpan => 30, # Set the upload key type to indicate the type of identifier that will be # used to add users to the list. This field is immutable and required for # a CREATE operation. crmBasedUserList => Google::Ads::GoogleAds::V21::Common::CrmBasedUserListInfo->new({ uploadKeyType => CONTACT_INFO })}); # Create the user list operation. my $user_list_operation = Google::Ads::GoogleAds::V21::Services::UserListService::UserListOperation-> new({ create => $user_list }); # Issue a mutate request to add the user list and print some information. my $user_lists_response = $api_client->UserListService()->mutate({ customerId => $customer_id, operations => [$user_list_operation]}); my $user_list_resource_name = $user_lists_response->{results}[0]{resourceName}; printf "User list with resource name '%s' was created.\n", $user_list_resource_name; return $user_list_resource_name; }
Krok 2. Dodaj członków do listy użytkowników
Trzy główne klucze dopasowania to adres e-mail, adres pocztowy i numer telefonu. Jako kluczy dopasowania możesz używać identyfikatora użytkownika i identyfikatora urządzenia mobilnego, ale te rozwiązania są mniej przyszłościowe, ponieważ opierają się na plikach cookie i identyfikatorach urządzeń. Zalecamy przesyłanie danych kontaktowych użytkowników, takich jak adres e-mail, adres pocztowy i numer telefonu, zamiast identyfikatorów CRM lub identyfikatorów urządzeń mobilnych.
Każda lista użytkowników może zawierać tylko jeden typ danych o klientach określony w polu CrmBasedUserListInfo.upload_key_type
. Obiekt UserData
, który reprezentuje pojedynczego użytkownika, może zawierać do 20 identyfikatorów użytkowników, z których każdy ma własny obiekt UserIdentifier
. Jeśli podasz więcej niż 20 identyfikatorów, wystąpi błąd TOO_MANY_USER_IDENTIFIERS
.
Google Ads używa listy użytkowników kierowanych na listę klientów do kierowania reklam tylko wtedy, gdy w momencie wyświetlenia reklamy przekracza ona minimalny próg aktywnych użytkowników. Aktywni użytkownicy to liczba użytkowników z Twojej listy, którzy korzystają aktywnie z Gmaila, wyszukiwarki, YouTube lub sieci reklamowej. Prześlij co najmniej 5000 użytkowników,aby zwiększyć szansę na uzyskanie wystarczającej liczby dopasowanych, aktywnych użytkowników do kierowania.
Przesyłanie informacji kontaktowych użytkownika
Aby przesłać adresy e-mail, adresy pocztowe lub numery telefonów użytkowników, ustaw wartość parametru
upload_key_type
na CONTACT_INFO
. Pamiętaj, że aby można było dopasować informacje kontaktowe, muszą one być powiązane z kontem Google. Nie można kierować reklam na konta firmowe, takie jak Google Workspace.
Ze względu na ochronę prywatności przed przesłaniem adresów e-mail, imion, nazwisk i numerów telefonów należy je zaszyfrować przy użyciu algorytmu SHA-256. Aby ustandaryzować wyniki szyfrowania, przed zaszyfrowaniem tych wartości wykonaj te czynności:
- usuń spacje na początku i na końcu ciągu,
- W przypadku imion i nazwisk, adresów e-mail i adresów pocztowych: zmień pisownię tekstu na małe litery.
- W przypadku numerów telefonów: przed zaszyfrowaniem przekonwertuj każdy numer telefonu na format E.164. Ten format reprezentuje numer telefonu jako liczbę składającą się z maksymalnie 15 cyfr, która zaczyna się od znaku
+
, np.+12125650000
lub+442070313000
. Początkowy znak+
można opcjonalnie pominąć.
W przypadku adresów e-mail nie musisz usuwać wszystkich kropek (.
) poprzedzających nazwę domeny w adresach gmail.com
i googlemail.com
, ponieważ są one nadal akceptowane.
Jeśli dane kontaktowe nie zostaną prawidłowo sformatowane przed zaszyfrowaniem, interfejs API nadal zaakceptuje zaszyfrowane informacje, ale nie będzie można ich dopasować do klienta.
Jeśli chcesz przesłać dane adresu pocztowego, musisz podać co najmniej:
- Kod kraju
- Kod pocztowy
- Zaszyfrowane imię
- Zaszyfrowane nazwisko
Jeśli brakuje któregoś z tych pól, adresu nie można dopasować.
Listy klientów mogą zawierać tylko 1 upload_key_type
, ale w przypadku upload_key_type
CONTACT_INFO
można przesyłać wiele typów informacji kontaktowych.
Jest to zalecane w celu zwiększenia współczynników dopasowania.
Przesyłanie identyfikatorów CRM
Aby wypełnić listę klientów identyfikatorami CRM, ustaw wartość parametru upload_key_type
na CRM_ID
.
Identyfikatory CRM są dopasowywane na podstawie identyfikatora użytkownika wygenerowanego i przypisanego przez reklamodawcę.
Jest to podobne do przesyłania MOBILE_ADVERTISING_ID
instancji, ale zamiast tego wypełniasz pole third_party_user_id
obiektu UserIdentifier
.
Przesyłanie identyfikatorów mobilnych
Podobnie jak w przypadku kierowania na listę klientów z użyciem adresów e-mail możesz przeprowadzać dopasowywanie klientów za pomocą identyfikatorów urządzeń mobilnych, takich jak identyfikator wyświetlania reklam (IDFA) lub identyfikator reklamowy Google (AAID). Aby to zrobić, przed użyciem listy użytkowników do kierowania na listę klientów za pomocą identyfikatorów urządzeń mobilnych określ właściwość app_id
i ustaw wartość upload_key_type
na MOBILE_ADVERTISING_ID
.
Przykładowy kod
W tym przykładzie użyto znaku OfflineUserDataJobOperation
, aby dołączyć informacje kontaktowe klienta do listy klientów.
Java
// Creates a raw input list of unhashed user information, where each element of the list // represents a single user and is a map containing a separate entry for the keys "email", // "phone", "firstName", "lastName", "countryCode", and "postalCode". In your application, this // data might come from a file or a database. List<Map<String, String>> rawRecords = new ArrayList<>(); // The first user data has an email address and a phone number. Map<String, String> rawRecord1 = ImmutableMap.<String, String>builder() .put("email", "dana@example.com") // Phone number to be converted to E.164 format, with a leading '+' as required. This // includes whitespace that will be removed later. .put("phone", "+1 800 5550101") .build(); // The second user data has an email address, a mailing address, and a phone number. Map<String, String> rawRecord2 = ImmutableMap.<String, String>builder() // Email address that includes a period (.) before the domain. .put("email", "alex.2@example.com") // Address that includes all four required elements: first name, last name, country // code, and postal code. .put("firstName", "Alex") .put("lastName", "Quinn") .put("countryCode", "US") .put("postalCode", "94045") // Phone number to be converted to E.164 format, with a leading '+' as required. .put("phone", "+1 800 5550102") .build(); // The third user data only has an email address. Map<String, String> rawRecord3 = ImmutableMap.<String, String>builder().put("email", "charlie@example.com").build(); // Adds the raw records to the raw input list. rawRecords.add(rawRecord1); rawRecords.add(rawRecord2); rawRecords.add(rawRecord3); // Iterates over the raw input list and creates a UserData object for each record. List<UserData> userDataList = new ArrayList<>(); for (Map<String, String> rawRecord : rawRecords) { // Creates a builder for the UserData object that represents a member of the user list. UserData.Builder userDataBuilder = UserData.newBuilder(); // Checks if the record has email, phone, or address information, and adds a SEPARATE // UserIdentifier object for each one found. For example, a record with an email address and a // phone number will result in a UserData with two UserIdentifiers. // IMPORTANT: Since the identifier attribute of UserIdentifier // (https://developers.google.com/google-ads/api/reference/rpc/latest/UserIdentifier) is a // oneof // (https://protobuf.dev/programming-guides/proto3/#oneof-features), you must set only ONE of // hashedEmail, hashedPhoneNumber, mobileId, thirdPartyUserId, or addressInfo. Setting more // than one of these attributes on the same UserIdentifier will clear all the other members // of the oneof. For example, the following code is INCORRECT and will result in a // UserIdentifier with ONLY a hashedPhoneNumber. // // UserIdentifier incorrectlyPopulatedUserIdentifier = // UserIdentifier.newBuilder() // .setHashedEmail("...") // .setHashedPhoneNumber("...") // .build(); // // The separate 'if' statements below demonstrate the correct approach for creating a UserData // for a member with multiple UserIdentifiers. // Checks if the record has an email address, and if so, adds a UserIdentifier for it. if (rawRecord.containsKey("email")) { UserIdentifier hashedEmailIdentifier = UserIdentifier.newBuilder() .setHashedEmail(normalizeAndHash(sha256Digest, rawRecord.get("email"), true)) .build(); // Adds the hashed email identifier to the UserData object's list. userDataBuilder.addUserIdentifiers(hashedEmailIdentifier); } // Checks if the record has a phone number, and if so, adds a UserIdentifier for it. if (rawRecord.containsKey("phone")) { UserIdentifier hashedPhoneNumberIdentifier = UserIdentifier.newBuilder() .setHashedPhoneNumber(normalizeAndHash(sha256Digest, rawRecord.get("phone"), true)) .build(); // Adds the hashed phone number identifier to the UserData object's list. userDataBuilder.addUserIdentifiers(hashedPhoneNumberIdentifier); } // Checks if the record has all the required mailing address elements, and if so, adds a // UserIdentifier for the mailing address. if (rawRecord.containsKey("firstName")) { // Checks if the record contains all the other required elements of a mailing address. Set<String> missingAddressKeys = new HashSet<>(); for (String addressKey : new String[] {"lastName", "countryCode", "postalCode"}) { if (!rawRecord.containsKey(addressKey)) { missingAddressKeys.add(addressKey); } } if (!missingAddressKeys.isEmpty()) { System.out.printf( "Skipping addition of mailing address information because the following required keys" + " are missing: %s%n", missingAddressKeys); } else { // Creates an OfflineUserAddressInfo object that contains all the required elements of a // mailing address. OfflineUserAddressInfo addressInfo = OfflineUserAddressInfo.newBuilder() .setHashedFirstName( normalizeAndHash(sha256Digest, rawRecord.get("firstName"), false)) .setHashedLastName( normalizeAndHash(sha256Digest, rawRecord.get("lastName"), false)) .setCountryCode(rawRecord.get("countryCode")) .setPostalCode(rawRecord.get("postalCode")) .build(); UserIdentifier addressIdentifier = UserIdentifier.newBuilder().setAddressInfo(addressInfo).build(); // Adds the address identifier to the UserData object's list. userDataBuilder.addUserIdentifiers(addressIdentifier); } } if (!userDataBuilder.getUserIdentifiersList().isEmpty()) { // Builds the UserData and adds it to the list. userDataList.add(userDataBuilder.build()); } } // Creates the operations to add users. List<OfflineUserDataJobOperation> operations = new ArrayList<>(); for (UserData userData : userDataList) { operations.add(OfflineUserDataJobOperation.newBuilder().setCreate(userData).build()); }
C#
// Creates a raw input list of unhashed user information, where each element of the list // represents a single user and is a map containing a separate entry for the keys // "email", "phone", "firstName", "lastName", "countryCode", and "postalCode". // In your application, this data might come from a file or a database. List<Dictionary<string, string>> rawRecords = new List<Dictionary<string, string>>(); // The first user data has an email address and a phone number. Dictionary<string, string> rawRecord1 = new Dictionary<string, string>(); rawRecord1.Add("email", "dana@example.com"); // Phone number to be converted to E.164 format, with a leading '+' as required. // This includes whitespace that will be removed later. rawRecord1.Add("phone", "+1 800 5550101"); // The second user data has an email address, a mailing address, and a phone number. Dictionary<string, string> rawRecord2 = new Dictionary<string, string>(); // Email address that includes a period (.) before the Gmail domain. rawRecord2.Add("email", "alex.2@example.com"); // Address that includes all four required elements: first name, last name, country // code, and postal code. rawRecord2.Add("firstName", "Alex"); rawRecord2.Add("lastName", "Quinn"); rawRecord2.Add("countryCode", "US"); rawRecord2.Add("postalCode", "94045"); // Phone number to be converted to E.164 format, with a leading '+' as required. // This includes whitespace that will be removed later. rawRecord2.Add("phone", "+1 800 5550102"); // The third user data only has an email address. Dictionary<string, string> rawRecord3 = new Dictionary<string, string>(); rawRecord3.Add("email", "charlie@example.com"); // Adds the raw records to the raw input list. rawRecords.Add(rawRecord1); rawRecords.Add(rawRecord2); rawRecords.Add(rawRecord3); // Iterates over the raw input list and creates a UserData object for each record. List<UserData> userDataList = new List<UserData>(); foreach (Dictionary<string, string> rawRecord in rawRecords) { // Creates a UserData object that represents a member of the user list. UserData userData = new UserData(); // Checks if the record has email, phone, or address information, and adds a // SEPARATE UserIdentifier object for each one found. // For example, a record with an email address and a phone number will result in a // UserData with two UserIdentifiers. // IMPORTANT: Since the identifier attribute of UserIdentifier // (https://developers.google.com/google-ads/api/reference/rpc/latest/UserIdentifier) // is a oneof // (https://protobuf.dev/programming-guides/proto3/#oneof-features), you must set // only ONE of hashedEmail, hashedPhoneNumber, mobileId, thirdPartyUserId, // or addressInfo. // Setting more than one of these attributes on the same UserIdentifier will clear // all the other members of the oneof. // For example, the following code is INCORRECT and will result in a UserIdentifier // with ONLY a hashedPhoneNumber. // // UserIdentifier incorrectlyPopulatedUserIdentifier = new UserIdentifier() // { // HashedEmail = "...", // HashedPhoneNumber = "..." // }; // // The separate 'if' statements below demonstrate the correct approach for creating // a UserData for a member with multiple UserIdentifiers. // Checks if the record has an email address, and if so, adds a UserIdentifier // for it. if (rawRecord.ContainsKey("email")) { UserIdentifier hashedEmailIdentifier = new UserIdentifier() { HashedEmail = NormalizeAndHash(rawRecord["email"], true) }; userData.UserIdentifiers.Add(hashedEmailIdentifier); } // Checks if the record has a phone number, and if so, adds a UserIdentifier for it. if (rawRecord.ContainsKey("phone")) { UserIdentifier hashedPhoneNumberIdentifier = new UserIdentifier() { HashedPhoneNumber = NormalizeAndHash(rawRecord["phone"], true) }; // Adds the hashed phone number identifier to the UserData object's list. userData.UserIdentifiers.Add(hashedPhoneNumberIdentifier); } // Checks if the record has all the required mailing address elements, and if so, // adds a UserIdentifier for the mailing address. if (rawRecord.ContainsKey("firstName")) { // Checks if the record contains all the other required elements of a mailing // address. HashSet<string> missingAddressKeys = new HashSet<string>(); foreach (string addressKey in new string[] {"lastName", "countryCode", "postalCode"}) { if (!rawRecord.ContainsKey(addressKey)) { missingAddressKeys.Add(addressKey); } } if (!missingAddressKeys.Any()) { Console.WriteLine( $"Skipping addition of mailing address information because the following " + "required keys are missing: {missingAddressKeys}"); } else { // Creates an OfflineUserAddressInfo object that contains all the required // elements of a mailing address. OfflineUserAddressInfo addressInfo = new OfflineUserAddressInfo() { HashedFirstName = NormalizeAndHash(rawRecord["firstName"]), HashedLastName = NormalizeAndHash(rawRecord["lastName"]), CountryCode = rawRecord["countryCode"], PostalCode = rawRecord["postalCode"] }; UserIdentifier addressIdentifier = new UserIdentifier() { AddressInfo = addressInfo }; // Adds the address identifier to the UserData object's list. userData.UserIdentifiers.Add(addressIdentifier); } } if (userData.UserIdentifiers.Any()) { userDataList.Add(userData); } } // Creates the operations to add the users. List<OfflineUserDataJobOperation> operations = new List<OfflineUserDataJobOperation>(); foreach(UserData userData in userDataList) { operations.Add(new OfflineUserDataJobOperation() { Create = userData }); }
PHP
// Creates a raw input list of unhashed user information, where each element of the list // represents a single user and is a map containing a separate entry for the keys 'email', // 'phone', 'firstName', 'lastName', 'countryCode', and 'postalCode'. In your application, // this data might come from a file or a database. $rawRecords = []; // The first user data has an email address and a phone number. $rawRecord1 = [ // The first user data has an email address and a phone number. 'email' => 'dana@example.com', // Phone number to be converted to E.164 format, with a leading '+' as required. This // includes whitespace that will be removed later. 'phone' => '+1 800 5550101' ]; $rawRecords[] = $rawRecord1; // The second user data has an email address, a mailing address, and a phone number. $rawRecord2 = [ // Email address that includes a period (.) before the Gmail domain. 'email' => 'alex.2@example.com', // Address that includes all four required elements: first name, last name, country // code, and postal code. 'firstName' => 'Alex', 'lastName' => 'Quinn', 'countryCode' => 'US', 'postalCode' => '94045', // Phone number to be converted to E.164 format, with a leading '+' as required. 'phone' => '+1 800 5550102', ]; $rawRecords[] = $rawRecord2; // The third user data only has an email address. $rawRecord3 = ['email' => 'charlie@example.com']; $rawRecords[] = $rawRecord3; // Iterates over the raw input list and creates a UserData object for each record. $userDataList = []; foreach ($rawRecords as $rawRecord) { // Checks if the record has email, phone, or address information, and adds a SEPARATE // UserIdentifier object for each one found. For example, a record with an email address // and a phone number will result in a UserData with two UserIdentifiers. // IMPORTANT: Since the identifier attribute of UserIdentifier // (https://developers.google.com/google-ads/api/reference/rpc/latest/UserIdentifier) is // a oneof // (https://protobuf.dev/programming-guides/proto3/#oneof-features), you must set only // ONE of 'hashed_email, 'hashed_phone_number', 'mobile_id', 'third_party_user_id', or // 'address_info'. // Setting more than one of these attributes on the same UserIdentifier will clear all // the other members of the oneof. For example, the following code is INCORRECT and will // result in a UserIdentifier with ONLY a 'hashed_phone_number'. // // $incorrectlyPopulatedUserIdentifier = new UserIdentifier(); // $incorrectlyPopulatedUserIdentifier->setHashedEmail('...'); // $incorrectlyPopulatedUserIdentifier->setHashedPhoneNumber('...'); // // The separate 'if' statements below demonstrate the correct approach for creating a // UserData for a member with multiple UserIdentifiers. $userIdentifiers = []; // Checks if the record has an email address, and if so, adds a UserIdentifier for it. if (array_key_exists('email', $rawRecord)) { $hashedEmailIdentifier = new UserIdentifier([ 'hashed_email' => self::normalizeAndHash($rawRecord['email'], true) ]); // Adds the hashed email identifier to the user identifiers list. $userIdentifiers[] = $hashedEmailIdentifier; } // Checks if the record has a phone number, and if so, adds a UserIdentifier for it. if (array_key_exists('phone', $rawRecord)) { $hashedPhoneNumberIdentifier = new UserIdentifier([ 'hashed_phone_number' => self::normalizeAndHash($rawRecord['phone'], true) ]); // Adds the hashed email identifier to the user identifiers list. $userIdentifiers[] = $hashedPhoneNumberIdentifier; } // Checks if the record has all the required mailing address elements, and if so, adds a // UserIdentifier for the mailing address. if (array_key_exists('firstName', $rawRecord)) { // Checks if the record contains all the other required elements of a mailing // address. $missingAddressKeys = []; foreach (['lastName', 'countryCode', 'postalCode'] as $addressKey) { if (!array_key_exists($addressKey, $rawRecord)) { $missingAddressKeys[] = $addressKey; } } if (!empty($missingAddressKeys)) { printf( "Skipping addition of mailing address information because the " . "following required keys are missing: %s%s", json_encode($missingAddressKeys), PHP_EOL ); } else { // Creates an OfflineUserAddressInfo object that contains all the required // elements of a mailing address. $addressIdentifier = new UserIdentifier([ 'address_info' => new OfflineUserAddressInfo([ 'hashed_first_name' => self::normalizeAndHash( $rawRecord['firstName'], false ), 'hashed_last_name' => self::normalizeAndHash( $rawRecord['lastName'], false ), 'country_code' => $rawRecord['countryCode'], 'postal_code' => $rawRecord['postalCode'] ]) ]); // Adds the address identifier to the user identifiers list. $userIdentifiers[] = $addressIdentifier; } } if (!empty($userIdentifiers)) { // Builds the UserData and adds it to the list. $userDataList[] = new UserData(['user_identifiers' => $userIdentifiers]); } } // Creates the operations to add users. $operations = array_map( function (UserData $userData) { return new OfflineUserDataJobOperation(['create' => $userData]); }, $userDataList );
Python
def build_offline_user_data_job_operations( client: GoogleAdsClient, ) -> List[OfflineUserDataJobOperation]: """Creates a raw input list of unhashed user information. Each element of the list represents a single user and is a dict containing a separate entry for the keys "email", "phone", "first_name", "last_name", "country_code", and "postal_code". In your application, this data might come from a file or a database. Args: client: The Google Ads client. Returns: A list containing the operations. """ # The first user data has an email address and a phone number. raw_record_1: Dict[str, str] = { "email": "dana@example.com", # Phone number to be converted to E.164 format, with a leading '+' as # required. This includes whitespace that will be removed later. "phone": "+1 800 5550101", } # The second user data has an email address, a mailing address, and a phone # number. raw_record_2: Dict[str, str] = { # Email address that includes a period (.) before the email domain. "email": "alex.2@example.com", # Address that includes all four required elements: first name, last # name, country code, and postal code. "first_name": "Alex", "last_name": "Quinn", "country_code": "US", "postal_code": "94045", # Phone number to be converted to E.164 format, with a leading '+' as # required. "phone": "+1 800 5550102", } # The third user data only has an email address. raw_record_3: Dict[str, str] = {"email": "charlie@example.com"} # Adds the raw records to a raw input list. raw_records: List[Dict[str, str]] = [ raw_record_1, raw_record_2, raw_record_3, ] operations: List[OfflineUserDataJobOperation] = [] # Iterates over the raw input list and creates a UserData object for each # record. for record in raw_records: # Creates a UserData object that represents a member of the user list. user_data: UserData = client.get_type("UserData") # Checks if the record has email, phone, or address information, and # adds a SEPARATE UserIdentifier object for each one found. For example, # a record with an email address and a phone number will result in a # UserData with two UserIdentifiers. # IMPORTANT: Since the identifier attribute of UserIdentifier # (https://developers.google.com/google-ads/api/reference/rpc/latest/UserIdentifier) # is a oneof # (https://protobuf.dev/programming-guides/proto3/#oneof-features), you # must set only ONE of hashed_email, hashed_phone_number, mobile_id, # third_party_user_id, or address-info. Setting more than one of these # attributes on the same UserIdentifier will clear all the other members # of the oneof. For example, the following code is INCORRECT and will # result in a UserIdentifier with ONLY a hashed_phone_number: # incorrect_user_identifier = client.get_type("UserIdentifier") # incorrect_user_identifier.hashed_email = "..." # incorrect_user_identifier.hashed_phone_number = "..." # The separate 'if' statements below demonstrate the correct approach # for creating a UserData object for a member with multiple # UserIdentifiers. # Checks if the record has an email address, and if so, adds a # UserIdentifier for it. if "email" in record: user_identifier: UserIdentifier = client.get_type("UserIdentifier") user_identifier.hashed_email = normalize_and_hash( record["email"], True ) # Adds the hashed email identifier to the UserData object's list. user_data.user_identifiers.append(user_identifier) # Checks if the record has a phone number, and if so, adds a # UserIdentifier for it. if "phone" in record: user_identifier: UserIdentifier = client.get_type("UserIdentifier") user_identifier.hashed_phone_number = normalize_and_hash( record["phone"], True ) # Adds the hashed phone number identifier to the UserData object's # list. user_data.user_identifiers.append(user_identifier) # Checks if the record has all the required mailing address elements, # and if so, adds a UserIdentifier for the mailing address. if "first_name" in record: required_keys = ("last_name", "country_code", "postal_code") # Checks if the record contains all the other required elements of # a mailing address. if not all(key in record for key in required_keys): # Determines which required elements are missing from the # record. missing_keys = record.keys() - required_keys print( "Skipping addition of mailing address information " "because the following required keys are missing: " f"{missing_keys}" ) else: user_identifier: UserIdentifier = client.get_type( "UserIdentifier" ) address_info: AddressInfo = user_identifier.address_info address_info.hashed_first_name = normalize_and_hash( record["first_name"], False ) address_info.hashed_last_name = normalize_and_hash( record["last_name"], False ) address_info.country_code = record["country_code"] address_info.postal_code = record["postal_code"] user_data.user_identifiers.append(user_identifier) # If the user_identifiers repeated field is not empty, create a new # OfflineUserDataJobOperation and add the UserData to it. if user_data.user_identifiers: operation: OfflineUserDataJobOperation = client.get_type( "OfflineUserDataJobOperation" ) operation.create = user_data operations.append(operation)
Ruby
# Create a list of unhashed user data records that we will format in the # following steps to prepare for the API. raw_records = [ # The first user data has an email address and a phone number. { email: 'dana@example.com', # Phone number to be converted to E.164 format, with a leading '+' as # required. This includes whitespace that will be removed later. phone: '+1 800 5550100', }, # The second user data has an email address, a phone number, and an address. { # Email address that includes a period (.) before the Gmail domain. email: 'alex.2@example.com', # Address that includes all four required elements: first name, last # name, country code, and postal code. first_name: 'Alex', last_name: 'Quinn', country_code: 'US', postal_code: '94045', # Phone number to be converted to E.164 format, with a leading '+' as # required. phone: '+1 800 5550102', }, # The third user data only has an email address. { email: 'charlie@example.com', }, ] # Create a UserData for each entry in the raw records. user_data_list = raw_records.map do |record| client.resource.user_data do |data| if record[:email] data.user_identifiers << client.resource.user_identifier do |ui| ui.hashed_email = normalize_and_hash(record[:email], true) end end if record[:phone] data.user_identifiers << client.resource.user_identifier do |ui| ui.hashed_phone_number = normalize_and_hash(record[:phone], true) end end if record[:first_name] # Check that we have all the required information. missing_keys = [:last_name, :country_code, :postal_code].reject {|key| record[key].nil? } if missing_keys.empty? # If nothing is missing, add the address. data.user_identifiers << client.resource.user_identifier do |ui| ui.address_identifier = client.resource.offline_user_address_info do |address| address.hashed_first_name = normalize_and_hash(record[:first_name]) address.hashed_last_name = normalize_and_hash(record[:last_name]) address.country_code = record[:country_code] address.postal_code = record[:postal_code] end end else # If some data is missing, skip this entry. puts "Skipping addition of mailing information because the following keys are missing:" \ "#{missing_keys}" end end end end operations = user_data_list.map do |user_data| client.operation.create_resource.offline_user_data_job(user_data) end
Perl
# The first user data has an email address and a phone number. my $raw_record_1 = { email => 'dana@example.com', # Phone number to be converted to E.164 format, with a leading '+' as # required. This includes whitespace that will be removed later. phone => '+1 800 5550101', }; # The second user data has an email address, a mailing address, and a phone # number. my $raw_record_2 = { # Email address that includes a period (.) before the Gmail domain. email => 'alex.2@example.com', # Address that includes all four required elements: first name, last # name, country code, and postal code. firstName => 'Alex', lastName => 'Quinn', countryCode => 'US', postalCode => '94045', # Phone number to be converted to E.164 format, with a leading '+' as # required. phone => '+1 800 5550102', }; # The third user data only has an email address. my $raw_record_3 = {email => 'charlie@example.com',}; my $raw_records = [$raw_record_1, $raw_record_2, $raw_record_3]; my $operations = []; foreach my $record (@$raw_records) { # Check if the record has email, phone, or address information, and adds a # SEPARATE UserIdentifier object for each one found. For example, a record # with an email address and a phone number will result in a UserData with two # UserIdentifiers. # # IMPORTANT: Since the identifier attribute of UserIdentifier # (https://developers.google.com/google-ads/api/reference/rpc/latest/UserIdentifier) # is a oneof # (https://protobuf.dev/programming-guides/proto3/#oneof-features), you must set # only ONE of hashed_email, hashed_phone_number, mobile_id, third_party_user_id, # or address-info. Setting more than one of these attributes on the same UserIdentifier # will clear all the other members of the oneof. For example, the following code is # INCORRECT and will result in a UserIdentifier with ONLY a hashed_phone_number: # # my $incorrect_user_identifier = Google::Ads::GoogleAds::V21::Common::UserIdentifier->new({ # hashedEmail => '...', # hashedPhoneNumber => '...', # }); # # The separate 'if' statements below demonstrate the correct approach for creating a # UserData object for a member with multiple UserIdentifiers. my $user_identifiers = []; # Check if the record has an email address, and if so, add a UserIdentifier for it. if (defined $record->{email}) { # Add the hashed email identifier to the list of UserIdentifiers. push( @$user_identifiers, Google::Ads::GoogleAds::V21::Common::UserIdentifier->new({ hashedEmail => normalize_and_hash($record->{email}, 1)})); } # Check if the record has a phone number, and if so, add a UserIdentifier for it. if (defined $record->{phone}) { # Add the hashed phone number identifier to the list of UserIdentifiers. push( @$user_identifiers, Google::Ads::GoogleAds::V21::Common::UserIdentifier->new({ hashedPhoneNumber => normalize_and_hash($record->{phone}, 1)})); } # Check if the record has all the required mailing address elements, and if so, add # a UserIdentifier for the mailing address. if (defined $record->{firstName}) { my $required_keys = ["lastName", "countryCode", "postalCode"]; my $missing_keys = []; foreach my $key (@$required_keys) { if (!defined $record->{$key}) { push(@$missing_keys, $key); } } if (@$missing_keys) { print "Skipping addition of mailing address information because the following" . "keys are missing: " . join(",", @$missing_keys); } else { push( @$user_identifiers, Google::Ads::GoogleAds::V21::Common::UserIdentifier->new({ addressInfo => Google::Ads::GoogleAds::V21::Common::OfflineUserAddressInfo-> new({ # First and last name must be normalized and hashed. hashedFirstName => normalize_and_hash($record->{firstName}), hashedLastName => normalize_and_hash($record->{lastName}), # Country code and zip code are sent in plain text. countryCode => $record->{countryCode}, postalCode => $record->{postalCode}, })})); } } # If the user_identifiers array is not empty, create a new # OfflineUserDataJobOperation and add the UserData to it. if (@$user_identifiers) { my $user_data = Google::Ads::GoogleAds::V21::Common::UserData->new({ userIdentifiers => [$user_identifiers]}); push( @$operations, Google::Ads::GoogleAds::V21::Services::OfflineUserDataJobService::OfflineUserDataJobOperation ->new({ create => $user_data })); } }
Krok 3. Sprawdź przesłanie listy i współczynnik dopasowania
Gdy OfflineUserDataJob
ma SUCCESS
stan, szacowany współczynnik dopasowania jest dostępny w polu
operation_metadata.match_rate_range
. Jeśli zapytasz o to pole przed zakończeniem zadania, wartość w tym polu może wynosić zero. Aby mieć pewność, że Twój wynik jest gotowy do weryfikacji, a lista do kierowania reklam, zalecamy sprawdzenie, czy zadanie zostało wykonane. Wykonanie zadania może zająć od 10 minut do 24 godzin.
Przykładowy kod sprawdzania stanu zadania
Java
private void checkJobStatus( GoogleAdsClient googleAdsClient, long customerId, String offlineUserDataJobResourceName) { try (GoogleAdsServiceClient googleAdsServiceClient = googleAdsClient.getLatestVersion().createGoogleAdsServiceClient()) { String query = String.format( "SELECT offline_user_data_job.resource_name, " + "offline_user_data_job.id, " + "offline_user_data_job.status, " + "offline_user_data_job.type, " + "offline_user_data_job.failure_reason, " + "offline_user_data_job.customer_match_user_list_metadata.user_list " + "FROM offline_user_data_job " + "WHERE offline_user_data_job.resource_name = '%s'", offlineUserDataJobResourceName); // Issues the query and gets the GoogleAdsRow containing the job from the response. GoogleAdsRow googleAdsRow = googleAdsServiceClient .search(Long.toString(customerId), query) .iterateAll() .iterator() .next(); OfflineUserDataJob offlineUserDataJob = googleAdsRow.getOfflineUserDataJob(); System.out.printf( "Offline user data job ID %d with type '%s' has status: %s%n", offlineUserDataJob.getId(), offlineUserDataJob.getType(), offlineUserDataJob.getStatus()); OfflineUserDataJobStatus jobStatus = offlineUserDataJob.getStatus(); if (OfflineUserDataJobStatus.SUCCESS == jobStatus) { // Prints information about the user list. printCustomerMatchUserListInfo( googleAdsClient, customerId, offlineUserDataJob.getCustomerMatchUserListMetadata().getUserList()); } else if (OfflineUserDataJobStatus.FAILED == jobStatus) { System.out.printf(" Failure reason: %s%n", offlineUserDataJob.getFailureReason()); } else if (OfflineUserDataJobStatus.PENDING == jobStatus || OfflineUserDataJobStatus.RUNNING == jobStatus) { System.out.println(); System.out.printf( "To check the status of the job periodically, use the following GAQL query with" + " GoogleAdsService.search:%n%s%n", query); } } }
C#
private static void CheckJobStatusAndPrintResults(GoogleAdsClient client, long customerId, string offlineUserDataJobResourceName) { // Get the GoogleAdsService. GoogleAdsServiceClient service = client.GetService(Services.V21.GoogleAdsService); string query = "SELECT offline_user_data_job.resource_name, " + "offline_user_data_job.id, offline_user_data_job.status, " + "offline_user_data_job.type, offline_user_data_job.failure_reason, " + "offline_user_data_job.customer_match_user_list_metadata.user_list " + "FROM offline_user_data_job WHERE " + $"offline_user_data_job.resource_name = '{offlineUserDataJobResourceName}'"; // Issues the query and gets the GoogleAdsRow containing the job from the response. GoogleAdsRow googleAdsRow = service.Search(customerId.ToString(), query).First(); OfflineUserDataJob offlineUserDataJob = googleAdsRow.OfflineUserDataJob; Console.WriteLine($"Offline user data job ID {offlineUserDataJob.Id} with type " + $"'{offlineUserDataJob.Type}' has status: {offlineUserDataJob.Status}"); switch (offlineUserDataJob.Status) { case OfflineUserDataJobStatus.Success: // Prints information about the user list. PrintCustomerMatchUserListInfo(client, customerId, offlineUserDataJob.CustomerMatchUserListMetadata.UserList); break; case OfflineUserDataJobStatus.Failed: Console.WriteLine($" Failure reason: {offlineUserDataJob.FailureReason}"); break; case OfflineUserDataJobStatus.Pending: case OfflineUserDataJobStatus.Running: Console.WriteLine("To check the status of the job periodically, use the " + $"following GAQL query with GoogleAdsService.search:\n\n{query}"); break; } }
PHP
private static function checkJobStatus( GoogleAdsClient $googleAdsClient, int $customerId, string $offlineUserDataJobResourceName ) { $googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient(); // Creates a query that retrieves the offline user data job. $query = "SELECT offline_user_data_job.resource_name, " . "offline_user_data_job.id, " . "offline_user_data_job.status, " . "offline_user_data_job.type, " . "offline_user_data_job.failure_reason, " . "offline_user_data_job.customer_match_user_list_metadata.user_list " . "FROM offline_user_data_job " . "WHERE offline_user_data_job.resource_name = '$offlineUserDataJobResourceName'"; // Issues a search request to get the GoogleAdsRow containing the job from the response. /** @var GoogleAdsRow $googleAdsRow */ $googleAdsRow = $googleAdsServiceClient->search(SearchGoogleAdsRequest::build($customerId, $query)) ->getIterator() ->current(); $offlineUserDataJob = $googleAdsRow->getOfflineUserDataJob(); // Prints out some information about the offline user data job. $offlineUserDataJobStatus = $offlineUserDataJob->getStatus(); printf( "Offline user data job ID %d with type '%s' has status: %s.%s", $offlineUserDataJob->getId(), OfflineUserDataJobType::name($offlineUserDataJob->getType()), OfflineUserDataJobStatus::name($offlineUserDataJobStatus), PHP_EOL ); if ($offlineUserDataJobStatus === OfflineUserDataJobStatus::SUCCESS) { // Prints information about the user list. self::printCustomerMatchUserListInfo( $googleAdsClient, $customerId, $offlineUserDataJob->getCustomerMatchUserListMetadata()->getUserList() ); } elseif ($offlineUserDataJobStatus === OfflineUserDataJobStatus::FAILED) { printf(" Failure reason: %s.%s", $offlineUserDataJob->getFailureReason(), PHP_EOL); } elseif ( $offlineUserDataJobStatus === OfflineUserDataJobStatus::PENDING || $offlineUserDataJobStatus === OfflineUserDataJobStatus::RUNNING ) { printf( '%1$sTo check the status of the job periodically, use the following GAQL query with' . ' GoogleAdsService.search:%1$s%2$s%1$s', PHP_EOL, $query ); } }
Python
def check_job_status( client: GoogleAdsClient, customer_id: str, offline_user_data_job_resource_name: str, ) -> None: """Retrieves, checks, and prints the status of the offline user data job. If the job is completed successfully, information about the user list is printed. Otherwise, a GAQL query will be printed, which can be used to check the job status at a later date. Offline user data jobs may take 6 hours or more to complete, so checking the status periodically, instead of waiting, can be more efficient. Args: client: The Google Ads client. customer_id: The ID for the customer that owns the user list. offline_user_data_job_resource_name: The resource name of the offline user data job to get the status of. """ query: str = f""" SELECT offline_user_data_job.resource_name, offline_user_data_job.id, offline_user_data_job.status, offline_user_data_job.type, offline_user_data_job.failure_reason, offline_user_data_job.customer_match_user_list_metadata.user_list FROM offline_user_data_job WHERE offline_user_data_job.resource_name = '{offline_user_data_job_resource_name}' LIMIT 1""" # Issues a search request using streaming. google_ads_service: GoogleAdsServiceClient = client.get_service( "GoogleAdsService" ) results: SearchGoogleAdsStreamResponse = google_ads_service.search( customer_id=customer_id, query=query ) offline_user_data_job_result: OfflineUserDataJob = next( iter(results) ).offline_user_data_job status_name: str = offline_user_data_job_result.status.name user_list_resource_name: str = ( offline_user_data_job_result.customer_match_user_list_metadata.user_list ) print( f"Offline user data job ID '{offline_user_data_job_result.id}' with type " f"'{offline_user_data_job_result.type_.name}' has status: {status_name}" ) if status_name == "SUCCESS": print_customer_match_user_list_info( client, customer_id, user_list_resource_name ) elif status_name == "FAILED": print( f"\tFailure Reason: {offline_user_data_job_result.failure_reason}" ) elif status_name in ("PENDING", "RUNNING"): print( "To check the status of the job periodically, use the following " f"GAQL query with GoogleAdsService.Search: {query}" )
Ruby
def check_job_status(client, customer_id, offline_user_data_job) query = <<~QUERY SELECT offline_user_data_job.id, offline_user_data_job.status, offline_user_data_job.type, offline_user_data_job.failure_reason, offline_user_data_job.customer_match_user_list_metadata.user_list FROM offline_user_data_job WHERE offline_user_data_job.resource_name = '#{offline_user_data_job}' QUERY row = client.service.google_ads.search( customer_id: customer_id, query: query, ).first job = row.offline_user_data_job puts "Offline user data job ID #{job.id} with type '#{job.type}' has status: #{job.status}." case job.status when :SUCCESS print_customer_match_user_list(client, customer_id, job.customer_match_user_list_metadata.user_list) when :FAILED puts " Failure reason: #{job.failure_reason}" else puts " To check the status of the job periodically, use the following GAQL " \ "query with GoogleAdsService.search:" puts query end end
Perl
sub check_job_status { my ($api_client, $customer_id, $offline_user_data_job_resource_name) = @_; my $search_query = "SELECT offline_user_data_job.resource_name, " . "offline_user_data_job.id, offline_user_data_job.status, " . "offline_user_data_job.type, offline_user_data_job.failure_reason, " . "offline_user_data_job.customer_match_user_list_metadata.user_list " . "FROM offline_user_data_job " . "WHERE offline_user_data_job.resource_name = " . "'$offline_user_data_job_resource_name' LIMIT 1"; my $search_request = Google::Ads::GoogleAds::V21::Services::GoogleAdsService::SearchGoogleAdsRequest ->new({ customerId => $customer_id, query => $search_query }); # Get the GoogleAdsService. my $google_ads_service = $api_client->GoogleAdsService(); my $iterator = Google::Ads::GoogleAds::Utils::SearchGoogleAdsIterator->new({ service => $google_ads_service, request => $search_request }); # The results have exactly one row. my $google_ads_row = $iterator->next; my $offline_user_data_job = $google_ads_row->{offlineUserDataJob}; my $status = $offline_user_data_job->{status}; printf "Offline user data job ID %d with type %s has status: %s.\n", $offline_user_data_job->{id}, $offline_user_data_job->{type}, $status; if ($status eq SUCCESS) { print_customer_match_user_list_info($api_client, $customer_id, $offline_user_data_job->{customerMatchUserListMetadata}{userList}); } elsif ($status eq FAILED) { print "Failure reason: $offline_user_data_job->{failureReason}"; } elsif (grep /$status/, (PENDING, RUNNING)) { print "To check the status of the job periodically, use the following GAQL " . "query with the GoogleAdsService->search() method:\n$search_query\n"; } return 1; }
Aby sprawdzić rozmiar listy, możesz wysłać zapytanie do zasobu user_list
.
Przykład kodu do wysyłania zapytań o zasób user_list
Java
try (GoogleAdsServiceClient googleAdsServiceClient = googleAdsClient.getLatestVersion().createGoogleAdsServiceClient()) { // Creates a query that retrieves the user list. String query = String.format( "SELECT user_list.size_for_display, user_list.size_for_search " + "FROM user_list " + "WHERE user_list.resource_name = '%s'", userListResourceName); // Constructs the SearchGoogleAdsStreamRequest. SearchGoogleAdsStreamRequest request = SearchGoogleAdsStreamRequest.newBuilder() .setCustomerId(Long.toString(customerId)) .setQuery(query) .build(); // Issues the search stream request. ServerStream<SearchGoogleAdsStreamResponse> stream = googleAdsServiceClient.searchStreamCallable().call(request);
C#
// Get the GoogleAdsService. GoogleAdsServiceClient service = client.GetService(Services.V21.GoogleAdsService); // Creates a query that retrieves the user list. string query = "SELECT user_list.size_for_display, user_list.size_for_search " + "FROM user_list " + $"WHERE user_list.resource_name = '{userListResourceName}'"; // Issues a search stream request. service.SearchStream(customerId.ToString(), query, delegate (SearchGoogleAdsStreamResponse resp) { // Display the results. foreach (GoogleAdsRow userListRow in resp.Results) { UserList userList = userListRow.UserList; Console.WriteLine("The estimated number of users that the user list " + $"'{userList.ResourceName}' has is {userList.SizeForDisplay}" + $" for Display and {userList.SizeForSearch} for Search."); } } );
PHP
$googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient(); // Creates a query that retrieves the user list. $query = "SELECT user_list.size_for_display, user_list.size_for_search " . "FROM user_list " . "WHERE user_list.resource_name = '$userListResourceName'"; // Issues a search stream request. /** @var GoogleAdsServerStreamDecorator $stream */ $stream = $googleAdsServiceClient->searchStream( SearchGoogleAdsStreamRequest::build($customerId, $query) );
Python
googleads_service_client: GoogleAdsServiceClient = client.get_service( "GoogleAdsService" ) # Creates a query that retrieves the user list. query: str = f""" SELECT user_list.size_for_display, user_list.size_for_search FROM user_list WHERE user_list.resource_name = '{user_list_resource_name}'""" # Issues a search request. search_results: SearchGoogleAdsStreamResponse = ( googleads_service_client.search(customer_id=customer_id, query=query) )
Ruby
query = <<~EOQUERY SELECT user_list.size_for_display, user_list.size_for_search FROM user_list WHERE user_list.resource_name = #{user_list} EOQUERY response = client.service.google_ads.search_stream( customer_id: customer_id, query: query, )
Perl
# Create a query that retrieves the user list. my $search_query = "SELECT user_list.size_for_display, user_list.size_for_search " . "FROM user_list " . "WHERE user_list.resource_name = '$user_list_resource_name'"; # Create a search Google Ads stream request that will retrieve the user list. my $search_stream_request = Google::Ads::GoogleAds::V21::Services::GoogleAdsService::SearchGoogleAdsStreamRequest ->new({ customerId => $customer_id, query => $search_query, }); # Get the GoogleAdsService. my $google_ads_service = $api_client->GoogleAdsService(); my $search_stream_handler = Google::Ads::GoogleAds::Utils::SearchStreamHandler->new({ service => $google_ads_service, request => $search_stream_request });
Ze względu na ochronę prywatności rozmiar listy użytkowników jest wyświetlany jako zero, dopóki nie będzie ona zawierać co najmniej 100 użytkowników. Następnie rozmiar jest zaokrąglany do 2 najbardziej znaczących cyfr.
Błędy podczas wykonywania OfflineUserDataJob
można pobierać za pomocą zasobu offline_user_data_job
w języku zapytań Google Ads. Pamiętaj jednak, że ten raport nie zawiera informacji o nieudanych dopasowaniach, ponieważ podczas dopasowywania porównywane są tylko hasze. Jeśli masz problemy z listami klientów, zapoznaj się z przewodnikiem rozwiązywania problemów.
Porównanie z interfejsem Google Ads
Lista może wydawać się mniejsza niż oczekiwano, gdy jest wyświetlana w sekcji Zarządzanie odbiorcami w interfejsie Google Ads. Ten widok pokazuje liczbę aktywnych użytkowników na liście. Więcej informacji znajdziesz w tym przewodniku po rozwiązywaniu problemów.
Wypełnienie listy członkami może potrwać do 24 godzin, więc jeśli przesyłasz dane na listę odbiorców częściej niż co 12 godzin, w interfejsie Google Ads może pojawić się In Progress
stan.
Krok 4. Kierowanie na listę
Możesz kierować reklamy na listę na poziomie grupy reklam lub kampanii. Proces jest podobny do innych typów kryteriów kierowania w interfejsie API.
Przykład kodu do kierowania reklam w grupie reklam na listę użytkowników
Java
private String targetAdsInAdGroupToUserList( GoogleAdsClient googleAdsClient, long customerId, long adGroupId, String userList) { // Creates the ad group criterion targeting members of the user list. AdGroupCriterion adGroupCriterion = AdGroupCriterion.newBuilder() .setAdGroup(ResourceNames.adGroup(customerId, adGroupId)) .setUserList(UserListInfo.newBuilder().setUserList(userList).build()) .build(); // Creates the operation. AdGroupCriterionOperation operation = AdGroupCriterionOperation.newBuilder().setCreate(adGroupCriterion).build(); // Creates the ad group criterion service. try (AdGroupCriterionServiceClient adGroupCriterionServiceClient = googleAdsClient.getLatestVersion().createAdGroupCriterionServiceClient()) { // Adds the ad group criterion. MutateAdGroupCriteriaResponse response = adGroupCriterionServiceClient.mutateAdGroupCriteria( Long.toString(customerId), ImmutableList.of(operation)); // Gets and prints the results. String adGroupCriterionResourceName = response.getResults(0).getResourceName(); System.out.printf( "Successfully created ad group criterion with resource name '%s' " + "targeting user list with resource name '%s' with ad group with ID %d.%n", adGroupCriterionResourceName, userList, adGroupId); return adGroupCriterionResourceName; } }
C#
private string TargetAdsInAdGroupToUserList( GoogleAdsClient client, long customerId, long adGroupId, string userListResourceName) { // Get the AdGroupCriterionService client. AdGroupCriterionServiceClient adGroupCriterionServiceClient = client.GetService (Services.V21.AdGroupCriterionService); // Create the ad group criterion targeting members of the user list. AdGroupCriterion adGroupCriterion = new AdGroupCriterion { AdGroup = ResourceNames.AdGroup(customerId, adGroupId), UserList = new UserListInfo { UserList = userListResourceName } }; // Create the operation. AdGroupCriterionOperation adGroupCriterionOperation = new AdGroupCriterionOperation { Create = adGroupCriterion }; // Add the ad group criterion, then print and return the new criterion's resource name. MutateAdGroupCriteriaResponse mutateAdGroupCriteriaResponse = adGroupCriterionServiceClient.MutateAdGroupCriteria(customerId.ToString(), new[] { adGroupCriterionOperation }); string adGroupCriterionResourceName = mutateAdGroupCriteriaResponse.Results.First().ResourceName; Console.WriteLine("Successfully created ad group criterion with resource name " + $"'{adGroupCriterionResourceName}' targeting user list with resource name " + $"'{userListResourceName}' with ad group with ID {adGroupId}."); return adGroupCriterionResourceName; }
PHP
private static function targetAdsInAdGroupToUserList( GoogleAdsClient $googleAdsClient, int $customerId, int $adGroupId, string $userListResourceName ): string { // Creates the ad group criterion targeting members of the user list. $adGroupCriterion = new AdGroupCriterion([ 'ad_group' => ResourceNames::forAdGroup($customerId, $adGroupId), 'user_list' => new UserListInfo(['user_list' => $userListResourceName]) ]); // Creates the operation. $operation = new AdGroupCriterionOperation(); $operation->setCreate($adGroupCriterion); // Issues a mutate request to add an ad group criterion. $adGroupCriterionServiceClient = $googleAdsClient->getAdGroupCriterionServiceClient(); /** @var MutateAdGroupCriteriaResponse $adGroupCriterionResponse */ $adGroupCriterionResponse = $adGroupCriterionServiceClient->mutateAdGroupCriteria( MutateAdGroupCriteriaRequest::build($customerId, [$operation]) ); $adGroupCriterionResourceName = $adGroupCriterionResponse->getResults()[0]->getResourceName(); printf( "Successfully created ad group criterion with resource name '%s' " . "targeting user list with resource name '%s' with ad group with ID %d.%s", $adGroupCriterionResourceName, $userListResourceName, $adGroupId, PHP_EOL ); return $adGroupCriterionResourceName; }
Python
def target_ads_in_ad_group_to_user_list( client: GoogleAdsClient, customer_id: str, ad_group_id: str, user_list_resource_name: str, ) -> str: """Creates an ad group criterion that targets a user list with an ad group. Args: client: an initialized GoogleAdsClient instance. customer_id: a str client customer ID used to create an ad group criterion. ad_group_id: a str ID for an ad group used to create an ad group criterion that targets members of a user list. user_list_resource_name: a str resource name for a user list. Returns: a str resource name for an ad group criterion. """ ad_group_criterion_operation: AdGroupCriterionOperation = client.get_type( "AdGroupCriterionOperation" ) # Creates the ad group criterion targeting members of the user list. ad_group_criterion: AdGroupCriterion = ad_group_criterion_operation.create ad_group_criterion.ad_group = client.get_service( "AdGroupService" ).ad_group_path(customer_id, ad_group_id) ad_group_criterion.user_list.user_list = user_list_resource_name ad_group_criterion_service: AdGroupCriterionServiceClient = ( client.get_service("AdGroupCriterionService") ) response: MutateAdGroupCriteriaResponse = ( ad_group_criterion_service.mutate_ad_group_criteria( customer_id=customer_id, operations=[ad_group_criterion_operation] ) ) resource_name: str = response.results[0].resource_name print( "Successfully created ad group criterion with resource name: " f"'{resource_name}' targeting user list with resource name: " f"'{user_list_resource_name}' and with ad group with ID " f"{ad_group_id}." ) return resource_name
Ruby
def target_ads_in_ad_group_to_user_list( client, customer_id, ad_group_id, user_list ) # Creates the ad group criterion targeting members of the user list. operation = client.operation.create_resource.ad_group_criterion do |agc| agc.ad_group = client.path.ad_group(customer_id, ad_group_id) agc.user_list = client.resource.user_list_info do |info| info.user_list = user_list end end # Issues a mutate request to create the ad group criterion. response = client.service.ad_group_criterion.mutate_ad_group_criteria( customer_id: customer_id, operations: [operation], ) ad_group_criterion_resource_name = response.results.first.resource_name puts "Successfully created ad group criterion with resource name " \ "'#{ad_group_criterion_resource_name}' targeting user list with resource name " \ "'#{user_list}' with ad group with ID #{ad_group_id}" ad_group_criterion_resource_name end
Perl
sub target_ads_in_ad_group_to_user_list { my ($api_client, $customer_id, $ad_group_id, $user_list_resource_name) = @_; # Create the ad group criterion targeting members of the user list. my $ad_group_criterion = Google::Ads::GoogleAds::V21::Resources::AdGroupCriterion->new({ adGroup => Google::Ads::GoogleAds::V21::Utils::ResourceNames::ad_group( $customer_id, $ad_group_id ), userList => Google::Ads::GoogleAds::V21::Common::UserListInfo->new({ userList => $user_list_resource_name })}); # Create the operation. my $ad_group_criterion_operation = Google::Ads::GoogleAds::V21::Services::AdGroupCriterionService::AdGroupCriterionOperation ->new({ create => $ad_group_criterion }); # Add the ad group criterion, then print and return the new criterion's resource name. my $ad_group_criteria_response = $api_client->AdGroupCriterionService()->mutate({ customerId => $customer_id, operations => [$ad_group_criterion_operation]}); my $ad_group_criterion_resource_name = $ad_group_criteria_response->{results}[0]{resourceName}; printf "Successfully created ad group criterion with resource name '%s' " . "targeting user list with resource name '%s' with ad group with ID %d.\n", $ad_group_criterion_resource_name, $user_list_resource_name, $ad_group_id; return $ad_group_criterion_resource_name; }
Kierowanie na wiele list klientów
crm_based_user_list
można połączyć z innym crm_based_user_list
tylko wtedy, gdy używasz logical_user_list
.
Wszystkie zasady dotyczące crm_based_user_list
mają zastosowanie do powstałej listy użytkowników.