תחילת העבודה עם התאמה ללקוחות

התאמה ללקוחות מאפשרת לכם להשתמש בנתונים ממקורות אונליין ואופליין כדי להגיע ללקוחות שלכם בחיפוש Google, בכרטיסיית שופינג, ב-Gmail, ב-YouTube וברשת המדיה – וכדי לעודד אותם לאינטראקציה חוזרת. כשמשתמשים בהתאמה ללקוחות, המערכת מסתמכת על מידע שהלקוחות שיתפו איתכם כדי לטרגט מודעות ללקוחות האלה וללקוחות שדומים להם. אתם יכולים להעלות נתונים ממערכת לניהול קשרי לקוחות (CRM) בכמות גדולה, להוסיף או להסיר נתונים, או להשתמש ברשימות המשתמשים האלה כדי ליצור logical_user_list.

בסקירה הכללית של ניהול קהלים מפורטת רשימה של סוגים שונים של פלחים של קהל היעד, כדי שתוכלו להשוות בין קהלים מסוג 'התאמה ללקוחות' לבין אפשרויות אחרות של רשימות משתמשים.

מידע נוסף על התאמה ללקוחות ועל טירגוט לפי קהל

דרישות מוקדמות

לא כל החשבונות עומדים בדרישות לשימוש בהתאמה ללקוחות. כדי להשתמש בתכונה "התאמה ללקוחות", התנאים הבאים צריכים להתקיים בחשבון שלכם:

  • היסטוריה טובה של עמידה בדרישות המדיניות
  • היסטוריית תשלומים טובה

התכונות שזמינות לכם תלויות בדרישות שהחשבון עומד בהן. מידע על דרישות הסף וההגבלות זמין במדיניות בנושא התאמה ללקוחות.

לפני שמתחילים: תכנון ההטמעה

לפני שמתחילים לכתוב קוד, חשוב לתכנן את ההטמעה של התכונה 'התאמה ללקוחות'. בקטע הזה מפורט התהליך הכולל ונקודות מרכזיות שיעזרו לכם לתכנן אינטגרציה חזקה. אחרי שיש לכם תוכנית ברורה, אתם יכולים להמשיך לשלבי ההטמעה הבאים.

תהליך השימוש

זהו התהליך המומלץ ליצירה ולטירגוט של רשימת לקוחות:

  1. יוצרים רשימת לקוחות ריקה.

  2. יוצרים OfflineUserDataJob. יעיל הרבה יותר ליצור משימה גדולה אחת מאשר כמה משימות קטנות.

    חשוב לוודא שאתם ממלאים את השדה consent של customer_match_user_list_metadata בבקשות create OfflineUserDataJob. ב-remove מהבקשות לא נדרשת הסכמה. ה-API מחזיר את הערך OfflineUserDataJobError.CUSTOMER_NOT_ACCEPTED_CUSTOMER_DATA_TERMS אם הערך של consent.ad_user_data או של consent.ad_personalization במשימה מוגדר כ-DENIED.

    אם משתמש מסוים לא הסכים למתן הסכמה, אפשר ליצור משימה עם removeפעולה להסרת המזהים של המשתמש מרשימת המשתמשים.

    אם חסרה לכם הסכמה ממשתמשים ספציפיים, אתם יכולים ליצור משימה נפרדת שבה לא מגדירים את השדה consent של customer_match_user_list_metadata המשימה, ואז להוסיף מזהים של המשתמשים האלה באמצעות פעולות create למשימה הנפרדת.

  3. מוסיפים פעולות באמצעות השיטה OfflineUserDataJobService.AddOfflineUserDataJobOperations. כדי שהעיבוד יהיה אופטימלי, מומלץ להוסיף עד 10,000 מזהים בקריאה אחת. בקשת AddOfflineUserDataJobOperations אחת יכולה להכיל עד 100,000 מזהים בכל אובייקטי UserData ברשימת הפעולות.

    לדוגמה, אם לכל אחד מ-UserData האובייקטים יש UserIdentifier אחד של hashed_email ו-UserIdentifier נוסף של hashed_phone_number, אז שליחה של 5,000 אובייקטים מסוג UserData בכל בקשה היא אופטימלית, כי כל בקשה מכילה 10,000 מזהי משתמשים בסך הכול.

  4. חוזרים על השלב הקודם עד שכל הפעולות נוספות או עד שהמשימה מגיעה לקיבולת המקסימלית. אין הגבלה על מספר הפעולות שאפשר להוסיף למשימה אחת, אבל כדי שהעיבוד יהיה אופטימלי, מומלץ לא להוסיף יותר ממיליון פעולות למשימה.

  5. מריצים את המשימה. צריך להריץ את המשימה תוך 5 ימים מהיצירה שלה. אחרת, אי אפשר יהיה להריץ את העבודה.

  6. מבצעים סקר כדי לבדוק אם ההעלאה הצליחה.

  7. בודקים את מידת ההתאמה להגדרות.

  8. מטרגטים את הרשימה.

‫OfflineUserDataJobService ו-UserDataService

יש שני שירותים שמאפשרים להעלות נתוני התאמה ללקוחות. בחרו את השירות בהתאם לתרחיש לדוגמה, כי יכולות להיות מגבלות על שירות מסוים.

שירותי ניהול של רשימות התאמה ללקוחות
‫ OfflineUserDataJobService (האפשרות המועדפת) רוב המפתחים משתמשים בשירות הזה. הוא מותאם להעלאות גדולות עם קצב העברת נתונים גבוה, ומחזיר מדדי הצלחה בסיום. המדריך הזה מתמקד בעיקר בשירות הזה.
UserDataService השירות הזה מותאם להעלאה של מספר קטן של מזהים בכל פעם, עם עדכונים ספורדיים, והוא לא מותאם לפעול באופן רציף. יש מגבלה של 10 פעולות לכל בקשה. בנוסף, בקשה אחת לא יכולה להכיל יותר מ-100 פריטים בסך הכול בכל user_identifiers.

כדי לקבל הנחיות לגבי העלאות באמצעות השירות הזה, אפשר לעיין במדריך לניהול השילוב של התאמה ללקוחות.

צריך למלא את השדה consent של customer_match_user_list_metadata בבקשות UploadUserDataRequest create. לגבי בקשות מסוג remove, לא נדרשת הסכמה. אם הערך של consent.ad_user_data או של consent.ad_personalization הוא DENIED, ה-API מחזיר תשובה שבה הערך של received_operations_count הוא אפס, כדי לציין שהבקשה לא עובדה. אם למזהה יש ערך הסכמה של DENIED, אפשר לבקש להסיר את המזהה מרשימת המשתמשים באמצעות הפעולה remove של UploadUserDataRequest.

שיטות מומלצות

כשאתם מתכננים את השילוב של "התאמה ללקוחות", כדאי לפעול לפי השיטות המומלצות הבאות:

  • אל תנסו להשתמש בכמה חשבונות כדי לשנות רשימת משתמשים אחת. אפשר לשנות רשימת משתמשים רק בחשבון Google Ads או בחשבון של שותף נתונים שיצר אותה.

  • כדי להימנע משגיאות RESOURCE_EXHAUSTED, מומלץ למקסם את מספר הפעולות לכל AddOfflineUserDataJobOperationsRequest,עד 100, 000 מזהים.

  • אל תערבבו בין פעולות create ו-remove באותו OfflineUserDataJob. אם תעשו את זה, יכול להיות שתקבלו את השגיאה CONFLICTING_OPERATION.

  • מפעילים את partial_failure ב-AddOfflineUserDataJobOperationsRequest כדי לזהות פעולות בעייתיות לפני שמריצים את העבודה. הפעולות מאומתות כשהן מועלות אל OfflineUserDataJob.

  • כדי למנוע שגיאות מסוג CONCURRENT_MODIFICATION כשמעדכנים רשימות משתמשים:

    לא מומלץ להפעיל כמה תהליכים של OfflineUserDataJob במצב RUNNING בו-זמנית אם הם מטרגטים את אותו שם משאב של רשימת משתמשים, שצוין ב-CustomerMatchUserListMetadata.user_list. השגיאה מתרחשת כי כמה משימות מנסות לשנות את אותה רשימה בו-זמנית. ההתנגשות הזו יכולה לקרות גם אם משנים את הרשימה דרך ממשק המשתמש של Google Ads בזמן שמתבצע עיבוד של משימה ב-API.

    ההגבלה הזו חלה על משימות שהתחילו, כלומר במצב RUNNING. לעומת זאת, אפשר לשלוח בבטחה כמה בקשות AddOfflineUserDataJobOperations להוספת נתונים לטבלה אחת OfflineUserDataJob כשהיא עדיין במצב PENDING. אפשר להוסיף פעולות למשימה בכל שלב לפני שמפעילים את התהליך באמצעות הקריאה ל-RunOfflineUserDataJob.

  • אם יש לכם אלפי פעולות להחלה, צריך ליצור קובץ OfflineUserDataJob אחד שמכיל את כל הפעולות. לא מומלץ ליצור כמה משימות עם כמה מאות פעולות בכל אחת ולהריץ אותן ברצף או בו-זמנית. הרבה יותר יעיל להפעיל משימה אחת גדולה עם כל הפעולות מאשר כמה משימות קטנות, וזה גם מקטין את הסיכוי שתיתקלו בשגיאות בתהליך העבודה.

במאמר שיטות מומלצות לשימוש בהתאמה ללקוחות מוסבר איך להשתמש ברשימות הלקוחות כדי לבצע טירגוט אופטימלי.

שלב 1: יוצרים רשימת לקוחות

יוצרים רשימת לקוחות באמצעות UserListService. רשימות לקוחות נוצרות על ידי הגדרת השדה crm_based_user_list באובייקט user_list. אפשר להגדיר את השדה crm_based_user_list בסוגי קמפיינים שתומכים בטירגוט רשימות לקוחות:

התאמה ללקוחות בסוגים שונים של קמפיינים
רשת החיפוש המודעות מוצגות ברשת החיפוש של Google.
רשת המדיה המודעות מוצגות ברשת המדיה של Google.
הרחבה לרשת המדיה בקמפיינים לרשת החיפוש המודעות מוצגות ברשת החיפוש של Google וברשת המדיה של Google.
קמפיינים ליצירת ביקוש המודעות מוצגות ב-YouTube, ב-Discover וב-Gmail (הן מטרגטות באמצעות משאב Audience ב-AdGroupCriterion.audience).
קמפיינים למיקסום ביצועים המודעות מוצגות בכל הפלטפורמות של Google (משמשות כאות לזיהוי קהלים ב-AssetGroupSignal.audience).
קמפיינים של מודעות וידאו המודעות מוצגות ב-YouTube.
קמפיינים של שופינג מודעות מוצגות בכרטיסייה 'שופינג'.

השדה crm_based_user_list מכיל שלושה שדות:

  • ‫app_id: מחרוזת שמזהה באופן ייחודי את האפליקציה לנייד שממנה נאספו הנתונים. הדרישה הזו חלה כשיוצרים CrmBasedUserList כדי להעלות מזהים לצורכי פרסום במובייל.

  • ‫upload_key_type: סוג מפתח תואם ברשימה, שיכול להיות CONTACT_INFO,‏ CRM_ID או MOBILE_ADVERTISING_ID. אסור לכלול סוגי נתונים שונים באותה רשימה. השדה הזה נדרש בכל רשימות הלקוחות.

  • ‫data_source_type: מקור הנתונים של הרשימה. ערך ברירת המחדל הוא FIRST_PARTY. לקוחות ברשימת ההיתרים יכולים ליצור רשימות לקוחות ממקורות של צד שלישי (THIRD_PARTY_CREDIT_BUREAU,‏ THIRD_PARTY_VOTER_FILE או THIRD_PARTY_PARTNER_DATA). אפשר לשלב עם רשימות אחרות רק רשימות ממקורות של FIRST_PARTY.

המאפיין membership_life_span של רשימת המשתמשים מאפשר להגדיר את התקופה, בימים, שבה משתמש נחשב כמשתייך לרשימה. הערך של membership_life_span ברשימת משתמשים מסוג "התאמה ללקוחות" לא יכול להיות גדול מ-540, שהוא גם ערך ברירת המחדל.

המאפיין membership_status מגדיר אם הרשימה מקבלת משתמשים חדשים.

דוגמה לקוד ליצירת רשימת לקוחות

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.V25.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::V25::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::V25::Common::CrmBasedUserListInfo->new({
          uploadKeyType => CONTACT_INFO
        })});

  # Create the user list operation.
  my $user_list_operation =
    Google::Ads::GoogleAds::V25::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;
}
      

curl

שלב 2: מוסיפים חברים לרשימת המשתמשים

שלושת המפתחות העיקריים להתאמה הם כתובת אימייל, כתובת למשלוח דואר ומספר טלפון. אתם יכולים להשתמש במזהה המשתמש ובמזהה המכשיר הנייד כמפתחות להתאמה, אבל הפתרונות האלה פחות מוכנים לעתיד, כי הם מסתמכים על קובצי Cookie ועל מזהה המכשיר. אם אפשר, מומלץ להעלות פרטים ליצירת קשר עם המשתמשים, כמו כתובת אימייל, כתובת למשלוח דואר ומספר טלפון, במקום מזהי ניהול קשרי לקוחות (CRM) או Mobile ID (mID).

כל רשימת משתמשים יכולה להכיל רק סוג אחד של נתוני לקוחות, כפי שצוין בשדה CrmBasedUserListInfo.upload_key_type. בנוסף, אובייקט UserData שמייצג משתמש יחיד יכול להכיל עד 20 מזהי משתמשים, ולכל אחד מהם יש אובייקט UserIdentifier משלו. אם מציינים יותר מ-20 מזהים, מוצגת השגיאה TOO_MANY_USER_IDENTIFIERS.

מערכת Google Ads משתמשת ברשימת משתמשים מסוג התאמה ללקוחות לטירגוט רק אם היא עומדת במספר מינימלי של משתמשים פעילים בזמן הצגת המודעה. משתמשים פעילים הם מספר המשתמשים ברשימה שמבצעים פעילות ב-Gmail, ברשת החיפוש, ב-YouTube או ברשת המדיה. כדי להגדיל את הסיכוי שיהיו מספיק משתמשים פעילים שתואמים לטירגוט,מומלץ להעלות לפחות 5, 000 חברים.

העלאה של פרטים ליצירת קשר של משתמשים

כדי להעלות כתובות אימייל, כתובות למשלוח דואר או מספרי טלפון של משתמשים, מגדירים את upload_key_type לערך CONTACT_INFO. כדי שתהיה התאמה, הפרטים ליצירת קשר צריכים להיות משויכים לחשבון Google. אי אפשר לטרגט חשבונות ארגוניים, כמו Google Workspace.

מטעמי בעיות שקשורות לפרטיות, צריך לבצע גיבוב של כתובות האימייל, השמות הפרטיים, שמות המשפחה ומספרי הטלפון באמצעות האלגוריתם SHA-256 לפני שמעלים אותם. כדי לבצע סטנדרטיזציה של תוצאות הגיבוב, צריך לבצע את הפעולות הבאות לפני שמגבבים את הערכים האלה:

אם הפורמט של הפרטים ליצירת קשר לא תקין לפני הגיבוב, ה-API עדיין יקבל את הפרטים המגובבים, אבל לא תהיה אפשרות להתאים אותם ללקוח.

אם אתם רוצים להעלות נתונים של כתובות למשלוח דואר, אתם צריכים לכלול לפחות:

  • קוד מדינה
  • מיקוד
  • שם פרטי מגובב
  • שם משפחה מגובב

אם אחד מהשדות האלה חסר, לא ניתן להתאים את הכתובת.

רשימות לקוחות יכולות להכיל רק upload_key_type אחד, אבל אפשר להעלות כמה סוגים של פרטים ליצירת קשר עבור upload_key_type של CONTACT_INFO. מומלץ להשתמש באפשרות הזו כדי להגדיל את אחוז הלקוחות לטירגוט.

פורמט כתובת האימייל להמרות משופרות

כדי להבטיח את אחוזי הלקוחות לטירגוט הגבוהים ביותר להמרות משופרות, צריך להגדיר את הפורמט של כתובות האימייל ולגבב אותן בצורה נכונה לפי השלבים הבאים:

  1. החלת נורמליזציה סטנדרטית (כל כתובות האימייל):

    • מסירים רווחים לבנים בתחילת הטקסט ובסופו ב-ASCII.
    • ממירים את כל התווים בכתובת האימייל לאותיות קטנות.
  2. החלת נורמליזציה ספציפית לדומיין (רק ב-gmail.com וב-googlemail.com):

    • אחרי שהופכים את האותיות בכתובת האימייל לאותיות קטנות, בודקים אם הדומיין (אחרי הסמל @) הוא gmail.com או googlemail.com.
    • הסרת נקודות (.): בחלק של שם המשתמש (לפני הסמל @ ), מסירים את כל התווים של הנקודות.
    • הסרת סיומות פלוס (+): מסירים את סימן הפלוס הראשון (+) ואת כל התווים שאחריו עד לסמל @.
      • דוגמה: Jane.Doe+Shopping@googlemail.com הופך קודם ל-jane.doe+shopping@googlemail.com (אותיות קטנות), ואז ל-janedoe@googlemail.com (כללים של Gmail ו-Googlemail).
    • דומיינים אחרים: בכל דומיין שאינו gmail.com או googlemail.com, אין להסיר נקודות או סיומות פלוס משם המשתמש. החלת נורמליזציה רגילה בלבד (הסרת רווחים לבנים והמרה לאותיות קטנות).
      • לדוגמה: user.name+NYC@Example.com עובר נורמליזציה ל-user.name+nyc@example.com.
  3. מגבבים את כתובת האימייל המנורמלת:

    • מקודדים את מחרוזת כתובת האימייל שעברה נרמול כבייטים של UTF-8.
    • מבצעים גיבוב (hash) של בייטים בקידוד UTF-8 באמצעות האלגוריתם SHA-256.
    • מעצבים את התקציר שנוצר כמחרוזת הקסדצימלית באותיות קטנות (64 תווים).
import hashlib
import re


def normalize_and_hash_email(email: str) -> str:
    """Normalizes and SHA-256 hashes an email address for enhanced conversions."""
    normalized = email.strip().lower()
    parts = normalized.split("@")
    if len(parts) != 2:
        raise ValueError("Invalid email address format.")
    username, domain = parts
    if domain in ("gmail.com", "googlemail.com"):
        username = username.replace(".", "")
        username = re.sub(r"\+.*$", "", username)
    normalized = f"{username}@{domain}"
    return hashlib.sha256(normalized.encode("utf-8")).hexdigest()

העלאת מזהים של מערכת CRM

כדי לאכלס את רשימת הלקוחות במזהי CRM, מגדירים את upload_key_type לערך CRM_ID. מזהי CRM מותאמים ממזהה משתמש שנוצר ומוקצה על ידי המפרסם. התהליך דומה להעלאה של MOBILE_ADVERTISING_ID מופעים, אבל במקום זאת מאכלסים את השדה third_party_user_id של האובייקט UserIdentifier.

העלאת Mobile ID (mID)

בדומה להתאמה ללקוחות באמצעות כתובות אימייל, אתם יכולים לבצע התאמה ללקוחות באמצעות מזהי מכשירים ניידים מסוג מזהה למפרסמים (IDFA) או מזהה פרסום של Google‏ (AAID). כדי לעשות את זה, צריך לציין את המאפיין app_id ולהגדיר את upload_key_type כ-MOBILE_ADVERTISING_ID לפני שמשתמשים ברשימת משתמשים לצורך התאמה ללקוחות באמצעות מזהי מכשירים ניידים.

קוד לדוגמה

בדוגמה הבאה נעשה שימוש ב-OfflineUserDataJobOperation כדי להוסיף פרטים ליצירת קשר עם לקוחות לרשימת לקוחות.

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, dashes, and parentheses that will be removed later.
        .put("phone", "+1 (800) 555-0101")
        .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 (.) and plus (+) suffix before the Gmail domain.
        .put("email", "alex.2+myalias@gmail.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-555-0102")
        .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(normalizeAndHashEmailAddress(sha256Digest, rawRecord.get("email")))
            .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(
                normalizeAndHashPhoneNumber(sha256Digest, rawRecord.get("phone")))
            .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, dashes, and parentheses that will be removed later.
    'phone' => '+1 (800) 555-0101'
];
$rawRecords[] = $rawRecord1;

// The second user data has an email address, a mailing address, and a phone number.
$rawRecord2 = [
    // Email address that includes a period (.) and plus (+) suffix before the Gmail domain.
    'email' => 'alex.2+myalias@gmail.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-555-0102',
];
$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::normalizeAndHashEmailAddress($rawRecord['email'])
            ]
        );
        // 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::normalizeAndHashPhoneNumber($rawRecord['phone'])
            ]
        );
        // Adds the hashed phone number 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::V25::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::V25::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::V25::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::V25::Common::UserIdentifier->new({
              addressInfo =>
                Google::Ads::GoogleAds::V25::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::V25::Common::UserData->new({
          userIdentifiers => [$user_identifiers]});
      push(
        @$operations,
        Google::Ads::GoogleAds::V25::Services::OfflineUserDataJobService::OfflineUserDataJobOperation
          ->new({
            create => $user_data
          }));
    }
  }
      

curl

שלב 3: בודקים את העלאת הרשימה ואת אחוז הלקוחות לטירגוט

אחרי שסטטוס SUCCESS של OfflineUserDataJob ישתנה, שיעור ההתאמה המשוער יהיה זמין בשדה operation_metadata.match_rate_range. אם תשלחו שאילתה לשדה הזה לפני שהמשימה תסתיים, יכול להיות שהערך בשדה יהיה אפס. כדי לוודא שאחוז הלקוחות לטירגוט מוכן לאימות ושהרשימה מוכנה לטירגוט, מומלץ לבדוק את סטטוס העבודה כדי לראות אם היא הושלמה. התהליך יכול להימשך בין 10 דקות ל-24 שעות.

דוגמה לקוד לבדיקת סטטוס המשרה

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.V25.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::V25::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;
}
      

curl

כדי לאמת את גודל הרשימה, אפשר לשלוח שאילתה למשאב user_list.

קוד לדוגמה לשליחת שאילתה למשאב 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.V25.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::V25::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
  });
      

curl

מטעמי פרטיות, גודל רשימת המשתמשים מוצג כ-0 עד שהרשימה כוללת לפחות 100 משתמשים. לאחר מכן, הגודל מעוגל לשתי הספרות המשמעותיות ביותר.

אפשר לאחזר שגיאות שמתרחשות במהלך ההפעלה של OfflineUserDataJob דרך המשאב offline_user_data_job באמצעות שפת השאילתות של Google Ads. עם זאת, הדוח הזה לא מכיל מידע על התאמות שנכשלו, כי רק ערכי ה-hash מושווים כשמבצעים התאמות. אם נתקלתם בבעיות ברשימות של הלקוחות, אתם יכולים לעיין במדריך לפתרון בעיות.

השוואה לממשק המשתמש של Google Ads

יכול להיות שרשימה תיראה קטנה יותר מהצפוי כשצופים בה במרכז ניהול הקהלים בממשק המשתמש של Google Ads. בתצוגה הזו מוצג מספר המשתמשים הפעילים ברשימה. מידע נוסף מופיע במדריך לפתרון בעיות.

יכול להיות שיעברו עד 24 שעות עד שהרשימה תאוכלס בחברים, לכן יכול להיות שיוצג סטטוס In Progress בממשק המשתמש של Google Ads אם תעלו רשימת קהלים בתדירות גבוהה יותר מפעם אחת בכל 12 שעות.

שלב 4: טירגוט הרשימה

אתם יכולים לטרגט את הרשימה ברמת קבוצת המודעות או ברמת הקמפיין. התהליך דומה לתהליך של סוגים אחרים של קריטריונים לטירגוט ב-API.

דוגמה לקוד לטירגוט מודעות בקבוצת מודעות לרשימת משתמשים

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.V25.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::V25::Resources::AdGroupCriterion->new({
      adGroup => Google::Ads::GoogleAds::V25::Utils::ResourceNames::ad_group(
        $customer_id, $ad_group_id
      ),
      userList => Google::Ads::GoogleAds::V25::Common::UserListInfo->new({
          userList => $user_list_resource_name
        })});

  # Create the operation.
  my $ad_group_criterion_operation =
    Google::Ads::GoogleAds::V25::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;
}
      

curl

טירגוט של כמה רשימות לקוחות

אפשר לשלב crm_based_user_list עם crm_based_user_list אחר רק כשמשתמשים בlogical_user_list. כל כללי המדיניות של crm_based_user_list חלים על רשימת המשתמשים שנוצרה.

ניהול ועדכון של הרשימות

אחרי שיוצרים רשימות של לקוחות, סביר להניח שצריך לעדכן אותן מדי פעם כדי לשקף שינויים בבסיס הלקוחות. ‫Google Ads API מאפשר לכם לנהל את הרשימות הקיימות על ידי הוספה או הסרה של חברים.

הפעולות העיקריות לעדכון הרשימות כוללות:

  • הוספת משתמשים חדשים: הוספה של נתוני לקוחות חדשים לרשימה קיימת.
  • להסיר משתמשים ספציפיים: להסיר משתמשים ספציפיים מרשימה על סמך המזהים שלהם.
  • החלפת כל החברים: מנקים רשימה קיימת ומחליפים את התוכן שלה לגמרי, אבל מומלץ להוסיף ולהסיר במקום זאת.

איך מנהלים רשימות של לקוחות