ユーザー提供データ マッチング(UPDM)では、収集したユーザーに関する自社データ(ウェブサイト、アプリ、実店舗からの情報など)と、Google 広告データ全体(Google 所有および運営のデータを含む)におけるそのユーザーのログイン中のアクティビティ データが結合されます。これには、Google マーケティング プラットフォーム(GMP)サービスを通じて購入したデータ(ディスプレイ&ビデオ 360 を使用して購入した YouTube など)が含まれます。Google が所有および運営していない他の GMP サービスはサポートされていません。
ユーザー提供データのマッチングを利用するには、広告イベントが Google の広告データ上でログイン済みのユーザーと関連付けられている必要があります。
このドキュメントでは、ユーザー提供データ照合機能について説明し、設定と使用に関するガイダンスを提供します。
プライベート クラウド マッチの概要
広告に関する貴重な分析情報を得るには、複数のソースからデータを統合することが必要になることがよくあります。このデータ パイプラインの問題に対する独自のソリューションを構築するには、多大な時間とエンジニアリングの投資が必要です。Ads Data Hub のプライベート クラウド マッチは、このプロセスを効率化します。Ads Data Hub クエリ テンプレートを使用して、BigQuery にマッチテーブルを作成し、Ads Data Hub クエリで使用して広告データとファーストパーティ データを照合できます。自社データを使ってクエリを拡充すると、カスタマー エクスペリエンスが豊かになり、広告業界におけるトラッキング手法の変化にも対応しやすくなります。
ユーザー提供データ マッチングは、Google が所有および運営する広告枠でのみログイン中のユーザーが利用可能なため、今後のサードパーティ Cookie のサポート終了による影響を受けません。第三者データよりも業界の変化に対応できるため、より豊富な分析情報を取得でき、顧客エンゲージメントの向上につながります。
プロセスの概要
- データ取り込みと照合の設定
- ファーストパーティ データが BigQuery にあり、サービス アカウントにそのデータへの読み取り権限があることを確認します。データ取り込みを設定するをご覧ください。
- ファーストパーティ データの取り込みと照合
- お客様が自社データをフォーマットして BigQuery データセットにアップロードします。
- ユーザーは、Private Cloud Match 分析クエリを作成してスケジュールを設定することで、データ照合リクエストを開始します。
- Google は、プロジェクトと Google 所有のデータ(Google のユーザー ID とハッシュ化されたユーザー提供データを含む)のデータを結合して、照合テーブルを構築し、更新します。
- ファーストパーティ データを取り込むをご覧ください。
- 照合されたデータに基づく Ads Data Hub の継続的なクエリ
- マッチテーブルに対してクエリを実行する方法は、Ads Data Hub で通常のクエリを実行する方法と同じです。一致したデータをクエリするをご覧ください。
プライバシー要件について
顧客データの収集
ユーザー提供データ マッチングを使用する場合は、ファーストパーティ データをアップロードする必要があります。たとえば、ウェブサイト、アプリ、実店舗などで収集した情報や、顧客が直接共有した情報などが該当します。
以下を行ってください:
- 広告主様に代わってサービスを提供する第三者と顧客データを共有していることをプライバシー ポリシーで開示すること、また、法律上必要な場合はそのような共有について同意を得ること
- 顧客データをアップロードする際には、Google が承認する API かインターフェースのみを使用すること
- 該当するすべての法令(自主規制によるガイドラインまたは業界が定めるガイドラインを含む)に準拠すること
ファーストパーティによる同意取得の確認
Ads Data Hub でファーストパーティ データを使用するには、EU ユーザーの同意ポリシーと Ads Data Hub ポリシーに則って、Google へのデータ共有に対する EEA のエンドユーザーによる適切な同意を取得していることを確認する必要があります。同意取得の確認は、Ads Data Hub アカウントごとに、新しいファーストパーティ データをアップロードするたびに行う必要があります。1 人のユーザーがアカウント全体を代表してこの確認を行うことができます。
分析クエリに適用される同じ Google サービス クエリルールが UPDM クエリにも適用されます。たとえば、マッチテーブルを作成する際、EEA 内のユーザーに対してサービス間クエリを実行することはできません。
Ads Data Hub で同意獲得を確認する方法については、欧州経済領域の同意に関する要件をご覧ください。
データサイズ
エンドユーザーのプライバシーを保護するため、ユーザー提供データ照合では、データのサイズに関して次の要件が適用されます。
- ユーザー リストに 1,000 件以上のレコードをアップロードする必要があります。
データ取り込みを設定する
始める前に、以下のことを確認してください。
- ファーストパーティ データは BigQuery に保存されている必要があります。VPC-SC 境界がある場合、このファーストパーティ データは VPC-SC 内に配置する必要があります。
- Ads Data Hub のサービス アカウントには、ファーストパーティ データへの読み取り権限が必要です。
- 自社データは正しくフォーマットされ、ハッシュ化されている必要があります。詳しくは、次のセクションをご覧ください。
それ以外に、Private Cloud Match の追加オンボーディングはありません。分析クエリを実行できる場合は、プライベート クラウド マッチクエリを実行できます。
ファーストパーティ データの取り込みと照合
入力用にデータをフォーマットする
データを正しく照合するには、次の形式要件を満たしている必要があります。
- 次の入力フィールドの説明で指定されている場合は、SHA256 ハッシュを使用してアップロードする必要があります。
- 入力フィールドは文字列としてフォーマットする必要があります。たとえば、BigQuery の SHA256 ハッシュ関数を Base64 エンコード関数(TO_BASE64)とともに使用している場合は、次の変換
TO_BASE64(SHA256(user_data))
を使用します。 - UPDM は Base64 エンコードをサポートしています。ファーストパーティ データのエンコードは、Ads Data Hub クエリで使用されるデコードと一致している必要があります。ファーストパーティ データのエンコードを変更する場合は、同じベースからデコードするように Ads Data Hub クエリを更新する必要があります。次の例では、Base64 エンコードを使用します。
ユーザー ID
- 書式なしテキスト
- ハッシュ化: なし
メール
- 先頭と末尾の空白文字を削除する
- 文字はすべて小文字にしてください
- メールアドレス(Email)には必ずドメイン名(gmail.com や hotmail.co.jp など)を含めます。
- アクセントを削除する(例: è、é、ê、ë を e に変更する)
gmail.com
とgooglemail.com
のメールアドレスのドメイン名の前にあるすべてのピリオド(.)を削除する- ハッシュ化: Base64 エンコードされた SHA256
有効: TO_BASE64(SHA256("jeffersonloveshiking@gmail.com"))
無効: TO_BASE64(SHA256(" Jéfferson.Lôves.Hiking@gmail.com "))
電話
- 空白文字を削除する
- E.164 形式にする - 米国の例: +14155552671、英国の例: +442071838750
- 特殊記号はすべて削除する(ただし、国コードの直前の “+” はそのままにする)
- ハッシュ化: Base64 エンコードされた SHA256
有効: TO_BASE64(SHA256("+18005550101"))
無効: TO_BASE64(SHA256("(800) 555-0101"))
名
- 空白文字を削除する
- 文字はすべて小文字にしてください
- 敬称(Mrs.、Mr., 様博士
- アクセント文字(è、é、ê、ë など)は削除しないでください。
- ハッシュ化: Base64 エンコードされた SHA256
有効: TO_BASE64(SHA256("daní"))
無効: TO_BASE64(SHA256("Mrs. Daní"))
姓
- 空白文字を削除する
- 文字はすべて小文字にしてください
- 姓名の後に付く接尾辞(Jr.、Sr.、2nd、3rd、II、III、PHD、MD
- アクセント文字(è、é、ê、ë など)は削除しないでください。
- ハッシュ化: Base64 エンコードされた SHA256
有効: TO_BASE64(SHA256("délacruz"))
無効: TO_BASE64(SHA256("dé la Cruz, Jr."))
国
- 顧客データがすべて同じ国のものである場合も、国コードを含めてください
- 国データはハッシュ化しないでください
- ISO 3166-1 alpha-2 の国コードを使用する
- ハッシュ化: なし
有効: US
無効: United States of America
または USA
郵便番号
- 郵便番号のデータはハッシュ化しないでください
- 米国の郵便番号と国際郵便番号の両方を使用できます
- 米国の場合:
- 指定できるのは 5 桁の郵便番号です(例: 94043)
- 5 桁の後に 4 桁の拡張コードが続く形式も使用できます(例: 94043-1351、940431351)
- その他の国の場合:
- 書式設定は不要です(小文字にしたり、スペースや特殊文字を削除したりする必要はありません)。
- 郵便番号の拡張コード部分は省略してください
- ハッシュ化: なし
ハッシュ検証とデータ エンコード
次のハッシュ検証スクリプトを使用して、データが正しくフォーマットされていることを確認できます。
JavaScript
/**
* @fileoverview Provides the hashing algorithm, as well as some valid hashes of
* sample data for testing.
*/
async function hash(token) {
// Removes leading or trailing spaces and converts all characters to lowercase.
const formattedToken = token.trim().toLowerCase();
// Hashes the formatted string using the SHA-256 hashing algorithm.
const hashBuffer = await crypto.subtle.digest(
'SHA-256', (new TextEncoder()).encode(formattedToken));
// Converts the hash buffer to a base64-encoded string and returns it.
const base64Str = btoa(String.fromCharCode(...new Uint8Array(hashBuffer)));
return base64Str;
}
function main() {
// Expected hash for test@gmail.com:
// h5JGBrQTGorO7q6IaFMfu5cSqqB6XTp1aybOD11spnQ=
hash('test@gmail.com').then(result => console.log(result));
// Expected hash for +18005551212:
// YdkRG+0+bZz8G8O1yzWkAmh8TxVGvuBhor1ET73WTEQ=
hash('+18005551212').then(result => console.log(result));
// Expected hash for John: ltljLzY1ZMwwMlIUCc8iqFLyAy7sCZ7VlnwNAAzsYHo=
hash('John').then(result => console.log(result));
// Expected hash for Doe: eZ75KhGvkY4/t0HfQpNPO1aO0tk6wd908bjUGieTKm8=
hash('Doe').then(result => console.log(result));
}
main()
Python
"""Provides the hashing algorithm, as well as some valid hashes of sample data for testing.
Supports: Python 2, Python 3
Sample hashes:
- Email 'test@gmail.com': h5JGBrQTGorO7q6IaFMfu5cSqqB6XTp1aybOD11spnQ=
- Phone '+18005551212': YdkRG+0+bZz8G8O1yzWkAmh8TxVGvuBhor1ET73WTEQ=
- First name 'John': ltljLzY1ZMwwMlIUCc8iqFLyAy7sCZ7VlnwNAAzsYHo=
- Last name 'Doe': eZ75KhGvkY4/t0HfQpNPO1aO0tk6wd908bjUGieTKm8=
"""
import base64
import hashlib
def hash(token):
# Generates a base64-encoded SHA-256 hash of a normalized input string.
return base64.b64encode(
hashlib.sha256(
token.strip().lower().encode('utf-8')).digest()).decode('utf-8')
def print_hash(token, expected=None):
# Computes and displays the hash of a token, with optional validation.
hashed = hash(token)
if expected is not None and hashed != expected:
print(
'ERROR: Incorrect hash for token "{}". Expected "{}", got "{}"'.format(
token, expected, hashed))
return
print('Hash: "{}"\t(Token: {})'.format(hashed, token))
def main():
# Tests the hash function with sample tokens and expected results.
print_hash(
'test@gmail.com', expected='h5JGBrQTGorO7q6IaFMfu5cSqqB6XTp1aybOD11spnQ=')
print_hash(
'+18005551212', expected='YdkRG+0+bZz8G8O1yzWkAmh8TxVGvuBhor1ET73WTEQ=')
print_hash('John', expected='ltljLzY1ZMwwMlIUCc8iqFLyAy7sCZ7VlnwNAAzsYHo=')
print_hash('Doe', expected='eZ75KhGvkY4/t0HfQpNPO1aO0tk6wd908bjUGieTKm8=')
if __name__ == '__main__':
main()
Go
/*
Provides the hashing algorithm, as well as some valid hashes of sample data for testing.
Sample hashes:
- Email 'test@gmail.com': h5JGBrQTGorO7q6IaFMfu5cSqqB6XTp1aybOD11spnQ=
- Phone '+18005551212': YdkRG+0+bZz8G8O1yzWkAmh8TxVGvuBhor1ET73WTEQ=
- First name 'John': ltljLzY1ZMwwMlIUCc8iqFLyAy7sCZ7VlnwNAAzsYHo=
- Last name 'Doe': eZ75KhGvkY4/t0HfQpNPO1aO0tk6wd908bjUGieTKm8=
*/
package main
import (
"crypto/sha256"
"encoding/base64"
"fmt"
"strings"
)
// Hash hashes an email, phone, first name, or last name into the correct format.
func Hash(token string) string {
formatted := strings.TrimSpace(strings.ToLower(token))
hashed := sha256.Sum256([]byte(formatted))
encoded := base64.StdEncoding.EncodeToString(hashed[:])
return encoded
}
// PrintHash prints the hash for a token.
func PrintHash(token string) {
fmt.Printf("Hash: \"%s\"\t(Token: %s)\n", Hash(token), token)
}
func main() {
PrintHash("test@gmail.com")
PrintHash("+18005551212")
PrintHash("John")
PrintHash("Doe")
}
Java
package updm.hashing;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
/**
* Example of the hashing algorithm.
*
* <p>Sample hashes:
*
* <ul>
* <li>Email 'test@gmail.com': h5JGBrQTGorO7q6IaFMfu5cSqqB6XTp1aybOD11spnQ=
* <li>Phone '+18005551212': YdkRG+0+bZz8G8O1yzWkAmh8TxVGvuBhor1ET73WTEQ=
* <li>First name 'John': ltljLzY1ZMwwMlIUCc8iqFLyAy7sCZ7VlnwNAAzsYHo=
* <li>Last name 'Doe': eZ75KhGvkY4/t0HfQpNPO1aO0tk6wd908bjUGieTKm8=
* </ul>
*/
public final class HashExample {
private HashExample() {}
public static String hash(String token) {
// Normalizes and hashes the input token using SHA-256 and Base64 encoding.
String formattedToken = token.toLowerCase().strip();
byte[] hash;
try {
hash = MessageDigest.getInstance("SHA-256").digest(formattedToken.getBytes(UTF_8));
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("SHA-256 not supported", e);
}
return Base64.getEncoder().encodeToString(hash);
}
public static void printHash(String token) {
// Calculates and prints the hash for the given token.
System.out.printf("Hash: \"%s\"\t(Token: %s)\n", hash(token), token);
}
public static void main(String[] args) {
// Executes hash calculations and prints results for sample tokens.
printHash("test@gmail.com");
printHash("+18005551212");
printHash("John");
printHash("Doe");
}
}
SQL
/*
Provides the hashing algorithm, as well as some valid hashes of sample data for testing.
The following code uses Google Standard SQL and can be run on BigQuery to generate match tables from unhashed data.
Sample hashes:
- Email 'test@gmail.com': h5JGBrQTGorO7q6IaFMfu5cSqqB6XTp1aybOD11spnQ=
- Phone '+18005551212': YdkRG+0+bZz8G8O1yzWkAmh8TxVGvuBhor1ET73WTEQ=
- First name 'John': ltljLzY1ZMwwMlIUCc8iqFLyAy7sCZ7VlnwNAAzsYHo=
- Last name 'Doe': eZ75KhGvkY4/t0HfQpNPO1aO0tk6wd908bjUGieTKm8=
The unhashed input table schema is assumed to be:
- Column name: UserID, Type: String
- Column name: Email, Type: String
- Column name: Phone, Type: String
- Column name: FirstName, Type: String
- Column name: LastName, Type: String
- Column name: PostalCode, Type: String
- Column name: CountryCode, Type: String
*/
-- Creates a new table with Base64-encoded SHA-256 hashes of specified columns.
CREATE TABLE `your_project_name.your_dataset_name.output_hashed_table_name`
AS
SELECT
UserID,
TO_BASE64(SHA256(LOWER(Email))) AS Email,
TO_BASE64(SHA256(Phone)) AS Phone,
TO_BASE64(SHA256(LOWER(FirstName))) AS FirstName,
TO_BASE64(SHA256(LOWER(LastName))) AS LastName,
PostalCode,
CountryCode,
FROM
`your_project_name.your_dataset_name.input_unhashed_table_name`;
統合キー
ユーザー提供データの組み合わせによっては、他の組み合わせよりも効果的なものがあります。以下は、ユーザー提供データのさまざまな組み合わせを相対的な強度の順に並べたリストです。住所を使用する場合は、名、姓、国、郵便番号を含める必要があります。
- メールアドレス、電話番号、住所(最も強い)
- 電話番号、住所
- メール、住所
- メールアドレス、電話番号
- 住所
- 電話
- メール(最も弱い)
一致テーブルを作成する
[レポート] > [レポートを作成] > [プライベート クラウドのマッチテーブルの生成] > [テンプレートを使用] をクリックします。 省略可: データがまだハッシュ化されていない場合は、[プライベート クラウドのマッチテーブルの生成(ハッシュ化)] を選択できます。
// Create a new match table using your first party data with this template. /* Parameters: Manually remove all the parameters tagged with @ prefix and replace them with column names from your first party table: * @user_id * @email * @phone * @first_name * @last_name * @country_code * @postal_code And your BigQuery table information: * @my_project: Your BigQuery project where the first party table is. * @my_dataset: Your dataset where the first party table is. * @my_first_party_table: Your first party table. */ CREATE OR REPLACE TABLE adh.updm_match_table AS ( SELECT CAST(@user_id AS BYTES) AS user_id, @email AS email, @phone AS phone, @first_name AS first_name, @last_name AS last_name, @country_code AS country, @postal_code AS zip_code FROM `@my_project.@my_dataset.@my_first_party_table` );
パラメータ名を列名に置き換えて、適切なエイリアスを指定します。
[スケジュールを設定] をクリックして、照合テーブルを更新する頻度を設定します。実行ごとに現在の照合テーブルが上書きされます。
一致したデータをクエリする
マッチテーブルをクエリする
マッチテーブルにプライバシー チェックの発動に十分なデータが蓄積されている場合は、テーブルでクエリを実行できます。
ファーストパーティ データ(1PD)の元のテーブルは my_data
で表されます。これには、個人を特定できる情報(PII)と PII 以外のデータの両方が含まれます。元のテーブルを使用すると、照合テーブルと比較して、スコープ内のすべてのファーストパーティ データを表すため、レポートの分析情報を増やすことができます。
Ads Data Hub スキーマ内で user_id
フィールドを含むテーブルは、それぞれ対応するマッチテーブルを持ちます。たとえば adh.google_ads_impressions
テーブルに対しては adh.google_ads_impressions_updm
というマッチテーブルが自動的に生成され、後者にはユーザー ID が含まれています。ポリシー分離ネットワーク テーブル用に個別のマッチテーブルが作成されます。たとえば adh.google_ads_impressions_policy_isolated_network
テーブルに対しては adh.google_ads_impressions_policy_isolated_network_updm
というマッチテーブルが自動的に生成され、後者にはユーザー ID が含まれています。
生成されたテーブルには、元のテーブルのユーザーの中から、user_id
によるマッチがあったものだけを抽出したサブセットが格納されています。たとえば、元のテーブルにユーザー A とユーザー B のデータが含まれていて、ユーザー A のみにマッチがある場合、ユーザー B はマッチテーブルに格納されません。
マッチテーブルには customer_data_user_id
という列があり、ユーザー ID がバイト型で保存されます。
クエリを記述する際は、フィールドのデータ型を考慮することが重要です。SQL の比較演算子では、比較するリテラル同士は同じデータ型であることを期待されます。自社データのテーブルの user_id
の格納方法によっては、データをマッチングする前に、テーブル内の値のエンコードが必要となることもあります。マッチングを成功させるには、結合キーをバイトに型変換する必要があります。
JOIN ON
adh.google_ads_impressions_updm.customer_data_user_id = CAST(my_data.user_id AS BYTES)
また、SQL の文字列比較では大文字と小文字が区別されます。正確な比較ができるよう、必要に応じて双方の文字列をエンコードしてください。
サンプルクエリ
一致したユーザー数をカウントする
このクエリは、Google 広告のインプレッション テーブルで一致したユーザーの数をカウントします。
/* Count matched users in Google Ads impressions table */
SELECT COUNT(DISTINCT user_id)
FROM adh.google_ads_impressions_updm
マッチ率を計算する
すべてのユーザーがマッチングの対象となるわけではありません。たとえば、ログアウトしているユーザー、お子様、同意していないユーザーは UPDM で照合されません。is_updm_eligible
フィールドを使用すると、より正確な UPDM 一致率を計算できます。is_updm_eligible
フィールドは 2024 年 10 月 1 日から利用可能になっています。このフィールドを使用して、その日付より前の照合率を計算することはできません。
/* Calculate the UPDM match rate */
CREATE TEMP TABLE total_events OPTIONS(privacy_checked_export=TRUE) AS
SELECT
customer_id,
COUNT(*) AS n
FROM adh.google_ads_impressions
WHERE is_updm_eligible
GROUP BY 1;
CREATE TEMP TABLE matched_events OPTIONS(privacy_checked_export=TRUE) AS
SELECT
customer_id,
COUNT(*) AS n
FROM adh.google_ads_impressions_updm
GROUP BY 1;
SELECT
customer_id,
SAFE_DIVIDE(matched_events.n, total_events.n) AS match_rate
FROM total_events
LEFT JOIN matched_events
USING (customer_id)
ファーストパーティ データと Google 広告データを結合する
このクエリは、ファーストパーティ データを Google 広告データと結合する方法を示しています。
/* Join first-party data with Google Ads data. The customer_data_user_id field
contains your ID as BYTES. You need to cast your join key into BYTES for
successful matches. */
SELECT
inventory_type,
COUNT(*) AS impressions
FROM
adh.yt_reserve_impressions_updm AS google_data_imp
LEFT JOIN
`my_data`
ON
google_data_imp.customer_data_user_id = CAST(my_data.user_id AS BYTES)
GROUP BY
inventory_type
UPDM に関するよくある質問
UPDM に関するよくある質問の一覧については、UPDM に関するよくある質問をご覧ください。