プロスペクティングキャンペーン(新規顧客の獲得)を最適化するために、AppLovinは注文履歴データをAppLovinに提供することを強く推奨します。 これにより、AppLovinは既存顧客の正確なモデルを構築し、価値の高い新しいユーザーを見つけることができます。
AppLovin Shopifyアプリをインストールし、それをAds Managerアカウントに連携しているShopifyユーザーであれば、すでに準備は完了しています!
それ以外の場合は、以下の要件に従って、このデータをCSV形式でアップロードしてください。
AppLovinへの顧客データの提供は、必要な通知や同意を含む、お客様自身のプライバシーコンプライアンス要件に従うものとします。
transaction_id に基づいて自動的に注文を重複排除します。
AppLovinは、システム内にすでに存在する transaction_id を持つデータ行を無視します。
単一のファイル内に重複する transaction_id を持つ行が存在する場合、AppLovinは最も古い event_timestamp を持つ行を保持し、残りを破棄します。CSVファイルには、以下にリストされている必須ヘッダーをすべて含める必要がありますが、特定のフィールドへの入力は任意です。
列の順序は問いませんが、ヘッダー名は完全に一致する必要があります。
イベント期間: AppLovinは、利用可能なすべての注文履歴をアップロードすることを強くお勧めします。
| フィールド | 値の入力は必須? | タイプ | 説明 | 値 |
|---|---|---|---|---|
country_code | はい | String | ISO 3166 国コード | US |
currency | はい | String | ISO 4217 形式の取引通貨(3文字のコード) | USD |
email | はい | String | 顧客のメールアドレス。プレーンテキストのメールアドレスを提供してください。AppLovin側でハッシュ化します。 | customer@example.com |
event_name | はい | String | purchase である必要があります | purchase |
event_timestamp | はい | String | 購入が発生した日時
|
|
transaction_id | はい | String | 注文の一意の識別子(注文ID、チェックアウトIDなど)。これは重複排除に不可欠です。 | txn_12345 |
user_id | はい | String | お客様の社内顧客ID。 | user_abc123 |
value | はい | Double | 取引の総額。0以上の数値である必要があります。通貨記号は含めないでください。 | 99.99 |
zip | いいえ | String | 顧客の郵便番号。これは取引の請求先郵便番号である必要があります。米国の郵便番号の場合は、最初の5桁のみを含めてください。 | 12345 |
idfv | いいえ | String | ユーザーの identifier for vendors。 | f325g3gb-12fc-352f-c6c3-dz52f0f690d8 |
ifa | いいえ | String | ユーザーの identifier for advertisers。これは IDFA または GAID のいずれかです。 | 918f1d4f-d195-4a8b-af47-44683fe11db9 |
phone | いいえ | String | 顧客の電話番号。国コード(例: +1)を含める必要があります。プレーンテキストの番号を提供してください。AppLovin側でハッシュ化します。 | +14155551234 |
AppLovinは、提供されたプレーンテキストのメールアドレスと電話番号をハッシュ化します。
ご自身でハッシュ化を行いたい場合は、以下のガイドラインに慎重に従って行ってください。
ハッシュにソルト(salt)を追加しないでください。 正規化された値に対してのみ、通常の SHA-256 を使用してください。ソルト、ペッパー、または二重にハッシュ化された値は、AppLovin側で一致させることができず、値がないものとして処理されます。
emailgmail.com および googlemail.com の場合のみ、まず @ の前にあるすべてのピリオドを削除し、最初のプラス記号(+)とそれ以降のすべての文字を削除します。ドメインは変更しないでください。@ の前に何も残らない場合は、空の値を生成します。
phone1)。
その後、SHA256でハッシュ化します。
例(メールアドレスの場合):
| 入力 | 正規化後 | SHA256 |
|---|---|---|
Alice@Example.COM | alice@example.com | ff8d9819fc0e12bf0d24892e45987e249a28dce836a85cad60e28eaaa8c6d976 |
J..A.NE+work.more+extra@GMAIL.COM | jane@gmail.com | 988b074286b20c503e3015c2076533f3bf4ce5ca6f8a507ab52c2e0f98d620b7 |
Jane.Doe+Work@GoogleMail.com | janedoe@googlemail.com | 338abf9ef1c8793cadc7bcf51ed595338eb727ed9e06ce3d91d566d60b975937 |
以下にリファレンス実装を示します。それぞれ、上記の2番目の例のハッシュを出力します。実行して、同じ値が得られることを確認してください。
#include <algorithm>
#include <cctype>
#include <iostream>
#include <regex>
#include <string>
#include <openssl/sha.h>
std::string normalizeAndHash(std::string email)
{
email.erase(0, email.find_first_not_of(" \t\n\r\f\v"));
email.erase(email.find_last_not_of(" \t\n\r\f\v") + 1);
std::transform(email.begin(), email.end(), email.begin(),
[](unsigned char c) { return std::tolower(c); });
static const std::regex valid("^[!-?A-~]+@[!-?A-~]+$");
if (!std::regex_match(email, valid))
return "";
const auto at = email.find('@');
std::string local = email.substr(0, at);
const std::string domain = email.substr(at + 1);
if (domain == "gmail.com" || domain == "googlemail.com")
{
local = local.substr(0, local.find('+'));
local.erase(std::remove(local.begin(), local.end(), '.'), local.end());
if (local.empty())
return "";
}
const std::string normalized = local + "@" + domain;
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256(reinterpret_cast<const unsigned char*>(normalized.data()),
normalized.size(), hash);
static constexpr char digits[] = "0123456789abcdef";
std::string out;
for (const unsigned char value : hash)
{
out += digits[value >> 4];
out += digits[value & 15];
}
return out;
}
int main()
{
std::cout << normalizeAndHash(" J..A.NE+work.more+extra@GMAIL.COM ") << "\n";
}
using System;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
class Program
{
static readonly Regex Valid = new Regex("^[!-?A-~]+@[!-?A-~]+$");
static string NormalizeAndHash(string email)
{
string trimmed = email.Trim(' ', '\t', '\n', '\r', '\f', '\v').ToLowerInvariant();
if (!Valid.IsMatch(trimmed))
return "";
int at = trimmed.IndexOf('@');
string local = trimmed.Substring(0, at);
string domain = trimmed.Substring(at + 1);
if (domain == "gmail.com" || domain == "googlemail.com")
local = local.Split('+')[0].Replace(".", "");
if (local.Length == 0)
return "";
using (SHA256 sha256 = SHA256.Create())
{
byte[] hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(local + "@" + domain));
StringBuilder output = new StringBuilder(hash.Length * 2);
foreach (byte value in hash)
output.Append(value.ToString("x2"));
return output.ToString();
}
}
static void Main()
{
Console.WriteLine(NormalizeAndHash(" J..A.NE+work.more+extra@GMAIL.COM "));
}
}
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HexFormat;
import java.util.regex.Pattern;
public final class EmailHash
{
private static final Pattern VALID = Pattern.compile( "^[!-?A-~]+@[!-?A-~]+$" );
static String normalizeAndHash( final String email ) throws NoSuchAlgorithmException
{
final String trimmed = email.trim().toLowerCase();
if ( !VALID.matcher( trimmed ).matches() )
{
return "";
}
final int at = trimmed.indexOf( '@' );
final String domain = trimmed.substring( at + 1 );
String local = trimmed.substring( 0, at );
if ( domain.equals( "gmail.com" ) || domain.equals( "googlemail.com" ) )
{
local = local.split( "\\+", 2 )[0].replace( ".", "" );
if ( local.isEmpty() )
{
return "";
}
}
return HexFormat.of().formatHex( MessageDigest.getInstance( "SHA-256" )
.digest( ( local + "@" + domain ).getBytes( StandardCharsets.UTF_8 ) ) );
}
public static void main( final String[] args ) throws NoSuchAlgorithmException
{
System.out.println( normalizeAndHash( " J..A.NE+work.more+extra@GMAIL.COM " ) );
}
}
import { createHash } from "crypto";
function normalizeAndHash(email) {
const trimmed = email.replace(/^[ \t\n\r\f\v]+|[ \t\n\r\f\v]+$/g, "").toLowerCase();
if (!/^[!-?A-~]+@[!-?A-~]+$/.test(trimmed)) {
return "";
}
const at = trimmed.indexOf("@");
let local = trimmed.slice(0, at);
const domain = trimmed.slice(at + 1);
if (domain === "gmail.com" || domain === "googlemail.com") {
local = local.split("+")[0].replaceAll(".", "");
}
return local ? createHash("sha256").update(`${local}@${domain}`).digest("hex") : "";
}
console.log(normalizeAndHash(" J..A.NE+work.more+extra@GMAIL.COM "));
import java.security.MessageDigest
private val VALID = Regex("^[!-?A-~]+@[!-?A-~]+$")
fun normalizeAndHash(email: String): String {
val trimmed = email.trim(' ', '\t', '\n', '\r', '\u000B', '\u000C').lowercase()
if (!VALID.matches(trimmed)) return ""
val (rawLocal, domain) = trimmed.split('@')
val local = if (domain == "gmail.com" || domain == "googlemail.com") {
rawLocal.substringBefore('+').replace(".", "").ifEmpty { return "" }
} else rawLocal
return MessageDigest.getInstance("SHA-256")
.digest("$local@$domain".toByteArray())
.joinToString("") { "%02x".format(it) }
}
fun main() {
println(normalizeAndHash(" J..A.NE+work.more+extra@GMAIL.COM "))
}
import hashlib
import re
VALID = re.compile(r"^[!-?A-~]+@[!-?A-~]+$")
def normalize_and_hash(email):
email = email.strip(" \t\n\r\f\v").lower()
if not VALID.match(email):
return ""
local, _, domain = email.partition("@")
if domain in ("gmail.com", "googlemail.com"):
local = local.split("+", 1)[0].replace(".", "")
return hashlib.sha256(f"{local}@{domain}".encode()).hexdigest() if local else ""
print(normalize_and_hash(" J..A.NE+work.more+extra@GMAIL.COM "))
import CryptoKit
import Foundation
func normalizeAndHash(_ email: String) -> String {
let trimmed = email.trimmingCharacters(
in: CharacterSet(charactersIn: " \t\n\r\u{0b}\u{0c}")).lowercased()
guard trimmed.range(of: "^[!-?A-~]+@[!-?A-~]+$", options: .regularExpression) != nil
else { return "" }
let parts = trimmed.split(separator: "@")
let domain = String(parts[1])
var local = String(parts[0])
if domain == "gmail.com" || domain == "googlemail.com" {
local = local.prefix { $0 != "+" }.filter { $0 != "." }
}
guard !local.isEmpty else { return "" }
return SHA256.hash(data: Data("\(local)@\(domain)".utf8))
.map { String(format: "%02x", $0) }.joined()
}
print(normalizeAndHash(" J..A.NE+work.more+extra@GMAIL.COM "))
988b074286b20c503e3015c2076533f3bf4ce5ca6f8a507ab52c2e0f98d620b7
user_id と email が含まれている必要があります。
AppLovinは、これらの列の値が欠落している行を拒否します。event_name 列が存在し、その値が purchase である必要があります。value 列には、0以上の非負の数値(≥0)が含まれている必要があります。AX — オーランド諸島AD — アンドラAT — オーストリアBE — ベルギーDK — デンマークFO — フェロー諸島FI — フィンランドFR — フランスDE — ドイツGI — ジブラルタルGR — ギリシャGG — ガーンジーIS — アイスランドIE — アイルランドIM — マン島IT — イタリアJE — ジャージーLI — リヒテンシュタインLU — ルクセンブルクMT — マルタMC — モナコNL — オランダNO — ノルウェーPT — ポルトガルSM — サンマリノES — スペインSJ — スヴァールバル諸島およびヤンマイエン島SE — スウェーデンCH — スイスGB — イギリス有効なCSVファイルの例を以下に示します。
event_name,user_id,phone,email,event_timestamp,value,currency,transaction_id,country_code,zip,idfv,ifa
purchase,user_abc123,+14155551234,user@example.com,2025-11-10T16:45:00Z,99.99,USD,txn_12345,US,12345,f325g3gb-12fc-352f-c6c3-dz52f0f690d8,918f1d4f-d195-4a8b-af47-44683fe11db9
purchase,user_def456,+14155555678,customer@example.com,2025-11-10T16:45:00Z,149.5,USD,txn_67890,US,12345,f325g3gb-12fc-352f-c6c3-dz52f0f690d8,918f1d4f-d195-4a8b-af47-44683fe11db9
purchase,user_ghi789,+14155559012,shopper@example.com,2025-11-10T17:20:00Z,75,EUR,txn_11223,US,12345,f325g3gb-12fc-352f-c6c3-dz52f0f690d8,918f1d4f-d195-4a8b-af47-44683fe11db9