Tính năng So khớp khách hàng cho phép bạn sử dụng dữ liệu trực tuyến và ngoại tuyến để tiếp cận cũng như thu hút lại khách hàng trên Mạng Tìm kiếm, thẻ Mua sắm, Gmail, YouTube và Mạng Hiển thị. Bằng cách sử dụng thông tin mà khách hàng đã chia sẻ với bạn, tính năng So khớp khách hàng sẽ nhắm mục tiêu quảng cáo đến những khách hàng đó và những khách hàng khác giống như họ. Bạn có thể tải dữ liệu trong hệ thống quản lý mối quan hệ khách hàng (CRM) lên hàng loạt, thêm hoặc xoá dữ liệu, hoặc sử dụng các danh sách người dùng này để tạo một logical_user_list
.
Hãy xem bài viết tổng quan về việc quản lý đối tượng để biết danh sách các loại phân khúc đối tượng khác nhau nhằm so sánh tính năng So khớp khách hàng với các lựa chọn khác về danh sách người dùng.
Tìm hiểu thêm về tính năng So khớp khách hàng và nhắm mục tiêu theo đối tượng.
Điều kiện tiên quyết
Không phải tài khoản nào cũng đủ điều kiện sử dụng tính năng So khớp khách hàng. Để sử dụng tính năng So khớp khách hàng, tài khoản của bạn phải có những điều kiện sau:
- Lịch sử tuân thủ chính sách tốt
- Lịch sử thanh toán tốt
Tuỳ thuộc vào những yêu cầu mà tài khoản của bạn đáp ứng, các tính năng bạn có thể dùng sẽ khác nhau. Tham khảo chính sách Đối sánh khách hàng để biết các yêu cầu và hạn chế về điều kiện sử dụng.
Thiết kế quy trình tích hợp
Bạn có thể thiết kế quy trình tích hợp.
Luồng sử dụng
Dưới đây là quy trình được đề xuất để tạo và nhắm mục tiêu một danh sách khách hàng:
Tạo một danh sách khách hàng trống.
Tạo một
OfflineUserDataJob
. Việc tạo một lệnh in lớn sẽ hiệu quả hơn nhiều so với việc tạo nhiều lệnh in nhỏ.Đảm bảo rằng bạn điền vào trường
consent
củacustomer_match_user_list_metadata
trong các yêu cầuOfflineUserDataJob
create
. Đối với các yêu cầuremove
, bạn không cần phải có sự đồng ý. API này trả vềOfflineUserDataJobError.CUSTOMER_NOT_ACCEPTED_CUSTOMER_DATA_TERMS
nếuconsent.ad_user_data
hoặcconsent.ad_personalization
của công việc được đặt thànhDENIED
.Nếu người dùng đã từ chối đồng ý, bạn có thể tạo một công việc bằng thao tác
remove
để xoá giá trị nhận dạng của người dùng khỏi danh sách người dùng.Nếu bạn thiếu sự đồng ý của một số người dùng cụ thể, hãy tạo một công việc riêng biệt mà bạn không đặt trường
consent
củacustomer_match_user_list_metadata
trong công việc đó, sau đó thêm giá trị nhận dạng cho những người dùng đó bằng cách sử dụng các thao táccreate
cho công việc riêng biệt đó.Thêm các thao tác bằng phương thức
OfflineUserDataJobService.AddOfflineUserDataJobOperations
. Bạn nên thêm tối đa 10.000 giá trị nhận dạng trong một lệnh gọi duy nhất để có thể xử lý tối ưu. Một yêu cầuAddOfflineUserDataJobOperations
duy nhất có thể chứa tối đa 100.000 giá trị nhận dạng trên tất cả các đối tượngUserData
trong danh sách thao tác.Ví dụ: nếu mỗi đối tượng
UserData
của bạn có mộtUserIdentifier
chohashed_email
và mộtUserIdentifier
khác chohashed_phone_number
, thì việc gửi 5.000 đối tượngUserData
cho mỗi yêu cầu là tối ưu vì mỗi yêu cầu sẽ chứa tổng cộng 10.000 mã nhận dạng người dùng.Lặp lại bước trước cho đến khi bạn thêm tất cả các thao tác hoặc cho đến khi công việc đạt đến giới hạn. Không có giới hạn về số lượng thao tác mà bạn có thể thêm vào một công việc duy nhất; tuy nhiên, bạn không nên thêm quá 1.000.000 thao tác cho mỗi công việc để có thể xử lý tối ưu.
Chạy lệnh. Bạn phải chạy lệnh trong vòng 5 ngày kể từ khi tạo. Nếu không, lệnh này sẽ không còn chạy được nữa.
Bình chọn để tải lên thành công.
Xác minh tỷ lệ khớp.
Nhắm đến danh sách.
OfflineUserDataJobService và UserDataService
Có 2 dịch vụ để tải dữ liệu So khớp khách hàng lên. Chọn dịch vụ dựa trên trường hợp sử dụng của bạn vì có thể có những hạn chế đối với một dịch vụ.
Dịch vụ tải danh sách So khớp khách hàng lên | |
---|---|
OfflineUserDataJobService (ưu tiên)
|
Hầu hết các nhà phát triển đều sử dụng dịch vụ này. Thư viện này được tối ưu hoá cho các tệp tải lên có kích thước lớn với thông lượng cao và trả về các chỉ số thành công sau khi hoàn tất. Hướng dẫn này chủ yếu tập trung vào dịch vụ này. |
UserDataService
|
Dịch vụ này được tối ưu hoá để tải lên một số ít giá trị nhận dạng tại một thời điểm với các bản cập nhật không thường xuyên và không được tối ưu hoá để chạy liên tục. Mỗi yêu cầu có giới hạn là 10 thao tác. Ngoài ra, một yêu cầu duy nhất không được chứa tổng cộng hơn 100 mục trên tất cả user_identifiers .
Để biết hướng dẫn về cách tải lên bằng dịch vụ này, hãy truy cập vào hướng dẫn để quản lý chế độ tích hợp tính năng So khớp khách hàng. Bắt đầu từ phiên bản 15 của API Google Ads, bạn nên điền sẵn trường |
Các phương pháp hay nhất
Hãy ghi nhớ các phương pháp hay nhất sau đây khi thiết kế quy trình tích hợp tính năng So khớp khách hàng:
Không cố gắng sử dụng nhiều tài khoản để sửa đổi một danh sách người dùng. Chỉ tài khoản Google Ads hoặc tài khoản đối tác dữ liệu đã tạo danh sách người dùng mới có thể sửa đổi danh sách đó.
Tối đa hoá số lượng thao tác trên mỗi
AddOfflineUserDataJobOperationsRequest
, tối đa 100.000 giá trị nhận dạng, để tránh lỗiRESOURCE_EXHAUSTED
.Đừng kết hợp các thao tác
create
vàremove
trong cùng mộtOfflineUserDataJob
. Việc này có thể dẫn đến lỗiCONFLICTING_OPERATION
.Bật
partial_failure
trongAddOfflineUserDataJobOperationsRequest
để phát hiện mọi thao tác có vấn đề trước khi chạy công việc. Các thao tác sẽ được xác thực khi tải lên mộtOfflineUserDataJob
.Tránh chạy đồng thời nhiều quy trình
OfflineUserDataJob
sửa đổi cùng một danh sách người dùng (tức là nhiều công việc cóCustomerMatchUserListMetadata.user_list
trỏ đến cùng một tên tài nguyên). Việc này có thể dẫn đến lỗiCONCURRENT_MODIFICATION
vì không được phép có nhiều tác vụ hoạt động trên cùng một danh sách cùng một lúc. Lỗi này cũng có thể xảy ra nếu bạn cố gắng sửa đổi đồng thời một danh sách thông qua giao diện người dùng Google Ads và API Google Ads. Xin lưu ý rằng điều này không áp dụng cho việc thêm các thao tác vào một công việcPENDING
. Bạn có thể thực hiện việc này bất cứ lúc nào trước khi công việc bắt đầu.Nếu bạn có hàng nghìn thao tác cần áp dụng, hãy tạo một
OfflineUserDataJob
chứa tất cả các thao tác. Đừng tạo nhiều công việc chỉ với vài trăm thao tác mỗi công việc và chạy chúng tuần tự hoặc đồng thời. Một công việc lớn duy nhất với tất cả các thao tác của bạn sẽ hiệu quả hơn nhiều so với nhiều công việc nhỏ và giảm khả năng bạn gặp phải lỗi trong quy trình làm việc.
Để biết các ý tưởng về cách tận dụng danh sách khách hàng để nhắm mục tiêu tối ưu, hãy truy cập vào Trung tâm trợ giúp.
Tạo danh sách khách hàng
Trước tiên, hãy tạo một danh sách khách hàng bằng UserListService
. Danh sách khách hàng được tạo bằng cách thiết lập trường crm_based_user_list
trên đối tượng user_list
. Bạn có thể đặt trường crm_based_user_list
trên các loại chiến dịch hỗ trợ nhắm mục tiêu danh sách khách hàng:
Tính năng So khớp khách hàng trong các loại chiến dịch | |
---|---|
Mạng Tìm kiếm | Quảng cáo xuất hiện trên mạng tìm kiếm. |
Mạng hiển thị | Quảng cáo hiển thị trên mạng hiển thị và trên Gmail chỉ khi có mẫu quảng cáo GSP. |
Tính năng Mở rộng hiển thị trên chiến dịch Tìm kiếm | Quảng cáo hiển thị trên mạng tìm kiếm và trên Gmail chỉ khi có mẫu quảng cáo GSP. |
Chiến dịch video | Quảng cáo chỉ xuất hiện trên YouTube nếu có quảng cáo TrueView trong luồng phát. |
Chiến dịch Mua sắm | Quảng cáo xuất hiện trong thẻ Mua sắm. |
crm_based_user_list
chứa 3 trường:
app_id
: Một chuỗi xác định duy nhất ứng dụng di động mà từ đó dữ liệu được thu thập. Bạn phải thực hiện bước này khi tạoCrmBasedUserList
để tải mã nhận dạng cho quảng cáo trên thiết bị di động lên.upload_key_type
: Loại khoá khớp của danh sách, có thể làCONTACT_INFO
,CRM_ID
hoặcMOBILE_ADVERTISING_ID
. Bạn không được phép kết hợp các loại dữ liệu trong cùng một danh sách. Bạn phải điền vào trường này cho tất cả danh sách khách hàng.data_source_type
: Nguồn dữ liệu của danh sách. Giá trị mặc định làFIRST_PARTY
. Khách hàng trong danh sách cho phép có thể tạo danh sách khách hàng từ bên thứ ba.
Thuộc tính membership_life_span
của danh sách người dùng cho phép bạn xác định khoảng thời gian (tính bằng ngày) mà một người dùng được coi là nằm trong danh sách. membership_life_span
của danh sách người dùng So khớp khách hàng không được vượt quá 540
. Đây cũng là giá trị mặc định.
Thuộc tính membership_status
xác định xem danh sách có chấp nhận người dùng mới hay không.
Ví dụ về mã để tạo danh sách khách hàng
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.V20.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, customer_id): """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 = client.get_service("UserListService") # Creates the user list operation. user_list_operation = client.get_type("UserListOperation") # Creates the new user list. user_list = 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 = user_list_service_client.mutate_user_lists( customer_id=customer_id, operations=[user_list_operation] ) user_list_resource_name = 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::V20::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::V20::Common::CrmBasedUserListInfo->new({ uploadKeyType => CONTACT_INFO })}); # Create the user list operation. my $user_list_operation = Google::Ads::GoogleAds::V20::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; }
Thêm dữ liệu khách hàng
Ba khoá so khớp chính là địa chỉ email, địa chỉ gửi thư và số điện thoại. Bạn có thể sử dụng mã nhận dạng người dùng và mã nhận dạng thiết bị di động làm khoá so khớp, nhưng những giải pháp này ít có khả năng duy trì trong tương lai do phụ thuộc vào cookie và mã nhận dạng thiết bị. Bạn nên tải thông tin liên hệ của người dùng lên (chẳng hạn như địa chỉ email, địa chỉ gửi thư và số điện thoại) khi có thể thay vì mã nhận dạng CRM hoặc thiết bị di động.
Mỗi danh sách người dùng chỉ có thể chứa một loại dữ liệu khách hàng duy nhất như được chỉ định bằng trường CrmBasedUserListInfo.upload_key_type
. Ngoài ra, một đối tượng UserData
(đại diện cho một người dùng duy nhất) có thể chứa tối đa 20 giá trị nhận dạng người dùng, mỗi giá trị nhận dạng đều có đối tượng UserIdentifier
riêng. Nếu có hơn 20 giá trị nhận dạng, bạn sẽ gặp lỗi TOO_MANY_USER_IDENTIFIERS
.
Google Ads chỉ sử dụng danh sách người dùng Đối sánh khách hàng để nhắm mục tiêu nếu danh sách đó đạt ngưỡng tối thiểu về số người dùng đang hoạt động tại thời điểm phân phát quảng cáo; người dùng đang hoạt động là số người dùng trong danh sách của bạn đang hoạt động trên Gmail, Mạng Tìm kiếm, YouTube hoặc Mạng Hiển thị. Tải ít nhất 5.000 thành viên lên để tăng khả năng có đủ người dùng đang hoạt động và được so khớp để nhắm mục tiêu.
Tải thông tin liên hệ của người dùng lên
Để tải địa chỉ email, địa chỉ gửi thư hoặc số điện thoại của người dùng lên, hãy đặt upload_key_type
thành CONTACT_INFO
. Xin lưu ý rằng thông tin liên hệ phải được liên kết với một Tài khoản Google để được so khớp và bạn không thể nhắm đến các tài khoản doanh nghiệp (chẳng hạn như Google Workspace).
Để bảo vệ quyền riêng tư, bạn phải băm địa chỉ email, tên, họ và số điện thoại bằng thuật toán SHA-256 trước khi tải lên. Để chuẩn hoá kết quả băm, trước khi băm một trong các giá trị này, hãy đảm bảo bạn thực hiện các thao tác sau:
- Xoá khoảng trắng ở đầu và cuối.
- Đối với tên, địa chỉ email và địa chỉ gửi thư: Chuyển đổi văn bản thành chữ thường.
- Đối với số điện thoại: Chuyển đổi từng số điện thoại sang định dạng E164 trước khi băm. Định dạng này biểu thị số điện thoại dưới dạng một số có độ dài tối đa 15 chữ số, bắt đầu bằng dấu
+
, ví dụ:+12125650000
hoặc+442070313000
. Bạn có thể bỏ qua dấu+
ở đầu (không bắt buộc).
Đối với địa chỉ email, bạn không cần xoá tất cả dấu chấm (.
) đứng trước tên miền trong địa chỉ email gmail.com
và googlemail.com
vì những dấu chấm này vẫn được chấp nhận.
Nếu thông tin liên hệ không được định dạng chính xác trước khi băm, API vẫn chấp nhận thông tin đã băm, nhưng không thể đối sánh thông tin đó với khách hàng.
Nếu muốn tải dữ liệu địa chỉ gửi thư lên, bạn phải cung cấp ít nhất:
- Mã quốc gia
- Mã bưu chính
- Tên đã băm
- Họ đã băm
Nếu thiếu bất kỳ trường nào trong số này, địa chỉ sẽ không thể được so khớp.
Mặc dù danh sách khách hàng chỉ có thể chứa một upload_key_type
, nhưng bạn có thể tải nhiều loại thông tin liên hệ lên cho một upload_key_type
của CONTACT_INFO
.
Bạn nên sử dụng tính năng này để tăng tỷ lệ khớp.
Tải mã nhận dạng CRM lên
Để điền mã CRM vào danh sách khách hàng, hãy đặt upload_key_type
thành CRM_ID
.
Mã nhận dạng CRM được so khớp từ mã nhận dạng người dùng do nhà quảng cáo tạo và chỉ định.
Thao tác này tương tự như việc tải các thực thể MOBILE_ADVERTISING_ID
lên, nhưng thay vào đó, bạn sẽ điền sẵn trường third_party_user_id
của đối tượng UserIdentifier
.
Tải mã nhận dạng thiết bị di động lên
Tương tự như tính năng So khớp khách hàng bằng email, bạn có thể thực hiện so khớp khách hàng bằng cách sử dụng Giá trị nhận dạng cho quảng cáo (IDFA) hoặc Giá trị nhận dạng cho quảng cáo của Google (AAID) trên thiết bị di động. Để làm như vậy, hãy chỉ định thuộc tính app_id
và đặt upload_key_type
thành MOBILE_ADVERTISING_ID
trước khi sử dụng danh sách người dùng để so khớp khách hàng bằng mã nhận dạng thiết bị di động.
Ví dụ về mã
Ví dụ sau đây sử dụng một OfflineUserDataJobOperation
để thêm thông tin liên hệ của khách hàng vào danh sách khách hàng.
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): """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 = { "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 = { # 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 = {"email": "charlie@example.com"} # Adds the raw records to a raw input list. raw_records = [raw_record_1, raw_record_2, raw_record_3] operations = [] # 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 = 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 = 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 = 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 = client.get_type("UserIdentifier") address_info = 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 = 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::V20::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::V20::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::V20::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::V20::Common::UserIdentifier->new({ addressInfo => Google::Ads::GoogleAds::V20::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::V20::Common::UserData->new({ userIdentifiers => [$user_identifiers]}); push( @$operations, Google::Ads::GoogleAds::V20::Services::OfflineUserDataJobService::OfflineUserDataJobOperation ->new({ create => $user_data })); } }
Xác minh tỷ lệ khớp và tỷ lệ tải danh sách lên
Sau khi OfflineUserDataJob
có SUCCESS
trạng thái, tỷ lệ trùng khớp ước tính sẽ có trong trường operation_metadata.match_rate_range
. Nếu bạn truy vấn trường này trước khi công việc hoàn tất, giá trị trong trường này có thể bằng 0. Để đảm bảo tỷ lệ khớp đã sẵn sàng cho quy trình xác minh và danh sách đã sẵn sàng cho việc nhắm mục tiêu, bạn nên thăm dò ý kiến về công việc để hoàn tất. Quá trình này có thể mất ít nhất 10 phút hoặc tối đa 24 giờ để hoàn tất.
Ví dụ về mã để kiểm tra trạng thái công việc
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.V20.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, customer_id, offline_user_data_job_resource_name): """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 = 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 = client.get_service("GoogleAdsService") results = google_ads_service.search(customer_id=customer_id, query=query) offline_user_data_job = next(iter(results)).offline_user_data_job status_name = offline_user_data_job.status.name user_list_resource_name = ( offline_user_data_job.customer_match_user_list_metadata.user_list ) print( f"Offline user data job ID '{offline_user_data_job.id}' with type " f"'{offline_user_data_job.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.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::V20::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; }
Để xác minh kích thước danh sách, bạn có thể truy vấn tài nguyên user_list
.
Ví dụ về mã để truy vấn tài nguyên 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.V20.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 = client.get_service("GoogleAdsService") # Creates a query that retrieves the user list. query = 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 = 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::V20::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 });
Vì mục đích bảo vệ quyền riêng tư, quy mô danh sách người dùng sẽ hiển thị là 0 cho đến khi danh sách có ít nhất 100 thành viên. Sau đó, kích thước được làm tròn thành 2 chữ số có nghĩa nhất.
Bạn có thể tìm nạp các lỗi trong quá trình thực thi OfflineUserDataJob
thông qua tài nguyên offline_user_data_job
bằng cách sử dụng Ngôn ngữ truy vấn Google Ads. Tuy nhiên, xin lưu ý rằng báo cáo này không chứa thông tin về bất kỳ trường hợp trùng khớp nào không thành công vì chỉ có hàm băm được so sánh khi thực hiện so khớp. Hãy tham khảo hướng dẫn khắc phục sự cố nếu bạn gặp vấn đề với danh sách khách hàng.
So sánh với giao diện người dùng Google Ads
Danh sách có thể xuất hiện nhỏ hơn dự kiến khi bạn xem trong Công cụ quản lý đối tượng trên giao diện người dùng của Google Ads. Chế độ xem này cho biết số lượng người dùng đang hoạt động trong danh sách. Để biết thêm thông tin, hãy xem hướng dẫn khắc phục sự cố này.
Vì có thể mất đến 24 giờ để danh sách được điền sẵn các thành viên, nên bạn có thể thấy In Progress
trạng thái trong giao diện người dùng Google Ads nếu tải lên danh sách đối tượng thường xuyên hơn 1 lần mỗi 12 giờ.
Nhắm mục tiêu danh sách của tôi
Bạn có thể nhắm đến danh sách của mình ở cấp nhóm quảng cáo hoặc cấp chiến dịch. Quy trình này tương tự như các loại tiêu chí nhắm mục tiêu khác trong API.
Ví dụ về mã để nhắm mục tiêu quảng cáo trong nhóm quảng cáo đến một danh sách người dùng
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.V20.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, customer_id, ad_group_id, user_list_resource_name ): """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 = client.get_type("AdGroupCriterionOperation") # Creates the ad group criterion targeting members of the user list. ad_group_criterion = 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 = client.get_service("AdGroupCriterionService") response = ad_group_criterion_service.mutate_ad_group_criteria( customer_id=customer_id, operations=[ad_group_criterion_operation] ) resource_name = 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::V20::Resources::AdGroupCriterion->new({ adGroup => Google::Ads::GoogleAds::V20::Utils::ResourceNames::ad_group( $customer_id, $ad_group_id ), userList => Google::Ads::GoogleAds::V20::Common::UserListInfo->new({ userList => $user_list_resource_name })}); # Create the operation. my $ad_group_criterion_operation = Google::Ads::GoogleAds::V20::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; }
Nhắm đến nhiều danh sách khách hàng
Bạn chỉ có thể kết hợp một crm_based_user_list
với một crm_based_user_list
khác khi dùng logical_user_list
.
Tất cả chính sách cho crm_based_user_list
đều áp dụng cho danh sách người dùng kết quả.