概要:People-Based Attribution(PBA)は、AppsFlyerの新しいWeb計測ソリューションであるWeb Performance Measurementに置き換えられます。この記事では、変更点、移行手順、およびレポートやサーバーサイド連携で使用する項目の完全なマッピングについて説明します。
Web計測をアップグレードする理由
Web計測の重要性は、これまで以上に高まっています。Webサイトは、多くのユーザーがコンバージョンする場所であると同時に、モバイルアプリへの導線が始まる場所でもあります。単なるランディングページではなく、クイズ形式のフロー、パーソナライズされたオンボーディング、ペイウォール、Webストアなどを含む、ユーザー獲得のための一連のファネルとして機能しており、多くの場合、より獲得意向の高いユーザーを、より低い獲得コストで獲得できます。
AppsFlyerでは、Web計測をモバイルと同等の水準へと引き上げます。従来のWeb向けプロダクトであるPeople-Based Attribution(PBA)は、AppsFlyerの中核となるアトリビューションエンジンと統合データモデルを基盤としたWeb Performance Measurementに置き換えられます。Web Performance Measurementでは、現在PBAで提供されているすべての機能に加えて、以下の機能が利用できます。
- データの集約:Webとモバイルアプリの計測を1か所に統合し、コスト集約、最適化ポストバック、クリエイティブ最適化もまとめて利用できます。
- より適切な予算配分:自社のビジネスロジックに合わせて柔軟にアトリビューションを設定できるため、実際に成果を上げているキャンペーンへ予算を集中できます。
- ROASの向上:より詳細な最適化ポストバックをアドネットワークへ送信できるほか、より多くのコンバージョンを計測できる完全なサーバーサイド実装に対応しています。これにより、アドネットワークはより質の高いシグナルをもとに最適化できます。
- 真のクロスプラットフォームROI:Web、アプリ、その他あらゆるプラットフォームをまたぐ、すべてのユーザージャーニーを計測できます。
- シンプルで統一されたレポート:すべてのプラットフォームに対して、1つのダッシュボードと共通のデータレポートを利用でき、データは1時間ごとに更新されます。
注意
切り替えに必要な作業は最小限です。現在と同じWeb SDKをそのまま利用できるため、Webサイトのコードを変更する必要はありません。
重要
数値には一部差異が生じることがあります。Web Performance Measurementのアトリビューションロジックは、より高度かつ柔軟になっているため、PBAの数値とは完全には一致しません。
Web Performance MeasurementとPBAの比較
| 機能 | 説明 | PBA | Web Performance Measurement |
|---|---|---|---|
| データ | |||
| データの更新頻度 | レポートでデータを確認できるまでの速さ | ✖️ 日次 | ✓ 1時間ごとのレポート、データの更新頻度は約2時間毎 |
| データモデル | モバイルアトリビューションデータとのスキーマ整合性 | ✖️ モバイルとは異なる | ✓ モバイルと統一されており、容易に結合・分析可能 |
| レポート | |||
| アクティビティダッシュボード | イベント発生時刻を基準としたダッシュボード | ✓ 対応 | ✓ 対応 |
| コホートダッシュボード | 獲得コホートごとのパフォーマンスを時系列で分析 | ✖️ 非対応 | ✓ 対応 |
| Data Lockerのローデータレポート | Data Lockerエクスポートによるアトリビューションローデータへのアクセス | ✓ 対応 | ✓ 対応 |
| 広告単位の粒度 | キャンペーンから広告単位までのレポート内訳 | ✖️ 管理画面のみ。ローデータでは非対応 | ✓ 管理画面とローデータの両方で、キャンペーン以下の詳細な粒度に対応 |
| クロスプラットフォームLTV | Webとモバイルのユーザージャーニーを統合し、LTVとして計測 | ✖️ 非対応 | ✓ 対応 |
| コストとシグナル | |||
| Webコスト | Webキャンペーンの広告費を取り込み、レポート | ✖️ 非対応 | ✓ 対応 |
| 最適化ポストバック | 最適化用のシグナルをアドネットワークへ送信 | ✖️ 非対応 | ✓ 対応 |
| 実装 | |||
| Web SDK(Pixel): | Webサイトへの訪問およびイベントを計測するクライアントサイドSDK | ✓ 対応 | ✓ 同じSDKを使用。コード変更は不要 |
| S2S対応 | Webサイトへの訪問およびイベントをサーバーサイドで完全に計測 | ✖️ イベントのみ | ✓ イベントと訪問に対応。完全なサーバーサイド実装が可能 |
| アトリビューションエンジン | |||
| アトリビューション期間 | 設定可能なルックバック期間、アトリビューション期間、リエンゲージメント期間、非アクティブ期間 | ✖️ クリックルックバック期間のみ | ✓ 種類の期間を設定可能(完全に制御可能) |
| カスタムUAイベント | 初回訪問以外で、ユーザー獲得とみなすイベントを定義 | ✖️ 初回訪問のみ | ✓ 任意のカスタムイベント(例:サインアップ、購入) |
| UAとリターゲティング | 新規獲得とリエンゲージメントを分けて貢献度を評価 | ✖️ UAという概念はなく、イベントはラストタッチに紐づけてアトリビューション | ✓ UAとリターゲティング専用のビューを提供し、双方にアトリビューションの貢献度を付与 |
移行手順
以下の表では、移行を5つのステップに分けて説明します。Webアプリの作成はすべてのお客様が対象です。それ以外のステップは、S2S APIやData Lockerレポートなど、現在利用しているPBA機能によって異なります。
| 対応内容 | 対象 | 対応内容の詳細 |
|---|---|---|
| Webアプリを作成する | すべてのお客様 | 新しいWebアプリを作成する際、Web SDK ID項目で既存のWeb Dev Keyを選択します。これにより、現在のWebサイトコードをそのまま利用でき、コードの変更は不要です。その後、新しいアプリでアトリビューション設定を行います。 |
| 新しいS2S APIへ移行する | PBA S2S APIを利用している場合 | 新しいS2S APIを設定します。Webサイトへの訪問とイベントの両方に対応しているため、完全なサーバーサイド実装が可能です。以下の「S2S API移行」の参考資料を参照してください。 |
| 新しいData Lockerレポートへ移行する | PBAのData Lockerレポートを利用している場合 | UIで新しいWebレポートを有効化し、BI/ETLの参照先を新しいデータへ切り替えます。新しいレポートでは、モバイルアプリ、Webサイト、CTV、PCを含むすべてのプラットフォームで共通のスキーマを使用します。以下の「ローデータ項目のマッピング」の参考資料を参照してください。 |
| アトリビューションパラメーターを確認する | 推奨 | PBAでは独自のメディアソースアトリビューションルールが適用されていました。Web Performance Measurementでは、より高度なトラフィックソース判定を使用することで、分析精度が向上しています。レポートでどのような値になるかを把握できるよう、両者の違いを確認してください。以下の「トラフィックソース判定の比較」の参考資料を参照してください。 |
| アプリをプロダクトラインにまとめる | 任意 | プロダクトラインを作成し、Webアプリとモバイルアプリを同じグループにまとめることで、クロスプラットフォームのユーザーLTVレポートを利用できます(PBAのBrand Bundleに類似した機能です)。 |
注意
数値には一部差異が生じることがあります。Web Performance Measurementのアトリビューションロジックは、より高度かつ柔軟になっているため、PBAの数値とは完全には一致しません。セッションの記録ロジック自体に変更はなく、業界標準と同様、アクティビティが継続している間は30分間を1つのセッションとして扱います。
提供終了となる機能
| 機能 | 変更内容 | 詳細 |
|---|---|---|
| コンバージョンパス | すでに提供終了済みです。 | — |
| Webアシストインストール(後から発生したモバイルインストールに貢献した、Webキャンペーンへ貢献度を付与する機能) | 「Webアシストインストール」専用のビューは提供されません。 |
Web-to-Appのジャーニーは、Smart ScriptおよびSmart Bannerで計測します。クロスプラットフォームレポートでは、完全に同一ではないものの、類似した分析が可能です。PBAと同様、CUIDを基準とします:
|
| 過去データの再計算 | デフォルトの30分間の遅延期間を超えて、過去にさかのぼった再計算は行われません。 | アトリビューションは30分間の遅延後に確定します。これにより、その30分間の間にユーザーが自身を識別するための時間が確保されます。 |
| ローデータ項目 | Webでは、モバイル関連の項目が非推奨となります。一部の項目名が変更され、一部の値も変更されます。 | 以下の「ローデータ項目のマッピング」の参考資料を参照してください。 |
| 遅延して到着するS2Sイベント | イベント発生日のUTC日付が終了してから30分以上経過して到着したイベントも引き続き受け付けられますが、そのイベント時刻はAppsFlyerがイベントを受信した時刻に置き換えられます。 | イベントを1日分まとめて一括送信するのではなく、リアルタイムで送信してください。可能であれば、イベント発生後30分以内の送信を推奨します。正確なアトリビューションを行うには、イベントが発生した時刻に近いタイミングでイベントを受信することが重要です。これは、Webの挙動を既存のモバイルの挙動と統一するものです。 |
参考資料:ローデータレポートの変更
PBAのローデータレポート(Website visitsおよびWebsite events)に含まれる各項目と、新しいEnd User Eventsレポートの項目との対応関係をまとめています。ソース:PBA ローデータレポート
対象:PBAのWebsite visitsおよびWebsite eventsレポート
- 変更なし:項目名とデータの両方が同じです。
- 名称変更:データは同じですが、カラム名が変更されています。
- 再定義:項目名は同じ、または類似していますが、データまたは値の形式が変更されています(再利用する際は注意が必要です)。
- 非推奨:新しいレポートには対応する項目がありません。
| 項目名 | 説明 | ステータス | 新しい項目 / 注記 |
|---|---|---|---|
advertising_id |
Advertising ID (GAID) | 非推奨 | PBAでは、クロスプラットフォームで紐づけられたモバイル/デバイスの広告IDです。クロスプラットフォームLTVおよびユーザージャーニーレポートはCUIDを基準としており、この項目は使用しません。 |
af_web_id |
Web SDKから送信されるCookie ID | 名称変更 |
appsflyer_id_value。同じWeb Cookieです。 |
amazon_aid |
Amazon Fire TVの広告ID | 非推奨 | モバイル/デバイスIDであり、Webには関係ありません。 |
android_id |
AndroidのデバイスID | 非推奨 | モバイル/デバイスIDであり、Webには関係ありません。 |
app_id |
直近にインストールされたアプリのID | 非推奨 | モバイルのクロスプラットフォーム項目です。新しいレポートにおけるWebアプリの識別子はunified_app_id("website-{domain}")であり、異なる概念です。 |
app_name |
直近のアプリ名 | 変更なし |
app_name
|
app_version |
直近のアプリバージョン | 非推奨 | モバイルのクロスプラットフォーム項目であり、Webには関係ありません。 |
appsflyer_id |
AppsFlyer (インストール) ID | 非推奨 | モバイルのインストールIDです。新しいappsflyer_id_valueはWeb Cookie(af_web_id)を指しており、別の識別子です。 |
attributed_touch_time |
アトリビューションされたWeb訪問のタイムスタンプ | 名称変更 |
event_time__attribution。アトリビューションされたタッチ(エンゲージメント)の時刻です。 |
attributed_touch_type |
タッチポイントの種類。常に"web visit" | 非推奨 | PBAでは固定値でした。訪問とイベントの区別は、現在はend_user_event_type(SESSION / IN_APP)で表されます。 |
bundle_id |
PBAのbundle ID | 非推奨 | クロスプラットフォームレポートでは、プロダクトラインによるグルーピング(Web+モバイルアプリ)に置き換えられます。 |
campaign |
Webサイト訪問にアトリビューションされたキャンペーン | 名称変更 |
campaign_name
|
campaign_id |
Webサイト訪問にアトリビューションされたキャンペーンID | 変更なし |
campaign_id
|
city |
IPアドレスをもとに判定 | 変更なし |
city
|
country_code |
IPアドレスをもとに判定 | 変更なし |
country_code
|
customer_user_id |
顧客ユーザーID (CUID) | 変更なし |
customer_user_id
|
device_type |
デバイスの種類 | 名称変更 |
device_category。値も異なります("Desktop"から"MOBILE_PHONE" / "TV"などに変更)。 |
dma |
IPアドレスをもとに判定 | 変更なし |
dma
|
event_name |
訪問:常に"website visit"。イベント:送信されたイベント名 | 再定義 | 訪問時は空になります(PBAでは"website visit"と記録されていました)。イベントについては変更ありません。 |
event_revenue |
購入通貨でのイベント収益額 | 名称変更 |
revenue_value_original
|
event_revenue_currency |
event_revenueの3桁の通貨コード
|
名称変更 |
revenue_currency_original
|
event_revenue_usd |
event_revenueをUSDに換算した金額 |
名称変更 |
revenue_usd
|
event_source |
Web SDKまたはServer-to-server | 変更なし |
event_source
|
event_time |
訪問:訪問時刻。イベント:イベント発生時刻 | 変更なし |
event_time
|
event_type |
標準イベント / コンバージョンイベント / Webサイト訪問 | 再定義 | コンバージョンイベントを示す区分は廃止されます。訪問とイベントの区別はend_user_event_type(SESSION / IN_APP)で表されます。 |
event_url |
イベントが発生したWebページのURL(訪問時はOriginal URLと同じ) | 変更なし |
event_url。現在は、URLクエリパラメーター(UTMなど)を確認する主要な項目としても使用されます。 |
event_value |
イベント:JSON形式のイベント詳細。訪問:null | 変更なし |
event_value
|
idfa |
広告ID | 非推奨 | モバイル/デバイスIDであり、Webには関係ありません。 |
idfv |
広告ID | 非推奨 | モバイル/デバイスIDであり、Webには関係ありません。 |
imei |
デバイス識別子 | 非推奨 | モバイル/デバイスIDであり、Webには関係ありません。 |
install_time |
直近のアプリインストール時刻 | 非推奨 | モバイルのクロスプラットフォーム項目です。Webにおけるユーザー獲得(コンバージョン)の時刻はevent_time__conversionで表され、別の概念です。 |
ip |
訪問者のIPアドレス | 名称変更 |
ip_address_value。値は同じです。また、ハッシュ化方式を示すip_address_typeが追加されます。 |
language |
ユーザーエージェントから取得した言語(例:"English") | 再定義 |
language。値の形式がISO 639-1および国コード形式に変更されます。 |
media_channel |
Webサイト訪問にアトリビューションされたメディアチャネル("Ad") | 非推奨 | 必要に応じてsub_param_1-5で対応できます。 |
media_source |
Webサイト訪問にアトリビューションされたメディアソース | 変更なし |
media_source
|
media_type |
Webサイト訪問にアトリビューションされたメディアタイプ("Paid") | 非推奨 | Webでは空になります。オーガニックか有料かの区別は、現在はis_organicの真偽値で表されます。 |
oaid |
広告ID | 非推奨 | モバイル/デバイスIDであり、Webには関係ありません。 |
original_url |
アトリビューションされた訪問時にユーザーをリダイレクトしたURL | 名称変更 |
event_urlに統合されます(訪問時はevent_urlがOriginal URLと同じになります)。独立したカラムは廃止されます。 |
platform |
プラットフォーム("macOS"、"Windows"など) | 再定義 | プラットフォームは常に"WEBSITE"になります。OSの情報はos_version / user_agent へ移動します。 |
postal_code |
IPアドレスをもとに判定 | 変更なし |
postal_code
|
query_params |
リダイレクト元URLのクエリパラメーター(JSON形式) | 非推奨 | 生のクエリ文字列はevent_urlに含まれます。JSONとして解析された専用カラムは廃止されます。 |
referrer |
アトリビューションされたWebサイト訪問のHTTPリファラー | 名称変更 |
http_referrer
|
region |
IPアドレスをもとに判定("NA"など) | 名称変更 |
continent。大陸コード(例:"NA")が入ります。 |
state |
IPアドレスをもとに判定 | 変更なし |
state
|
Data Locker ETL移行向け:そのまま使えるコーディングエージェント用プロンプト
この移行をスムーズに進められるよう、AIコーディングエージェント(Claude Code、Cursorなど)ですぐに使えるプロンプトを用意しました。エージェントに既存のETLコードへのアクセス権を付与し、以下のプロンプトを貼り付けてください。このプロンプトには、すべてのフィールドマッピングと挙動上の違いが含まれています。エージェントは現在のパイプラインを把握したうえで、新しいレポート向けに再構築します。
You are migrating an ETL pipeline from AppsFlyer's legacy PBA Data Locker raw-data reports (Website visits + Website events) to AppsFlyer's Web Performance Measurement Data Locker report (End User Events). Everything you need is in this prompt: the structural changes, the complete field-by-field mapping, and the validation steps. Do not guess anything beyond what is written here; if something is ambiguous, ask me.
## Step 1: Learn the current pipeline
Before writing any code, explore the existing codebase and produce an inventory:
1. Which PBA reports we consume (Website visits, Website events, or both) and where they are ingested.
2. Every PBA field we read, and where each is used downstream (transforms, joins, dashboards, alerts, exports).
3. The load cadence and scheduling assumptions (PBA delivered daily).
4. Any logic that separates or joins visit rows and event rows.
5. Any filters, groupings, or hardcoded values keyed on PBA field values (e.g. media_source names, channel labels, event_type, platform values).
Present this inventory to me and wait for my confirmation before proceeding.
## Step 2: Ask me these questions
1. Is the new End User Events report already enabled in Data Locker (enabled from the AppsFlyer UI)? If not, I need to enable it first.
2. What is our new web app's Unified App ID? Format: "website-{domain}" (e.g. website-www.example.com). If I don't know it, I'll get it from the AppsFlyer dashboard before we continue.
3. Do we want a parallel-run period (old and new pipelines side by side, comparing outputs) or a direct cutover? Recommend parallel-run.
4. Should the new pipeline also consume the Conversions report (unique attribution instances, no duplicate rows) or the cross-platform End User Events report (CUID-deduplicated, web+mobile user-level)? Default scope is the platform-level End User Events report, the direct successor of the PBA reports.
## Structural changes to design around
1. **One report instead of two.** PBA split visits and events into two reports. The new End User Events report holds both: visits are rows with end_user_event_type = 'SESSION', events are rows with end_user_event_type = 'IN_APP'. Only IN_APP rows carry a valid event_name; on SESSION rows event_name is empty (PBA wrote "website visit" there).
2. **One schema across platforms.** The report is shared by website, mobile, CTV, and PC. Always filter platform = 'WEBSITE' to isolate web data.
3. **Dual attribution credit, deduplicate.** The same action can appear twice: a primary-credit row and a secondary-credit row (original UA source, for UA-view LTV). Filter is_primary_attribution = true by default to avoid double-counting. Drop the filter only for dedicated UA-view vs retargeting-view analysis using conversion_type.
4. **Hourly instead of daily.** The new report delivers hourly with approximately 2 hours of data freshness. Redesign incremental loads around hourly batches instead of a daily drop.
5. **Organic vs paid.** PBA's media_type ("Paid") is gone. Use the is_organic boolean; never infer organic/paid from media_source.
6. **User counting.** Count and join users with COALESCE(customer_user_id, appsflyer_id_value), the stable customer user ID first, the cookie-based ID as fallback.
7. **Empty values.** STRING fields are '', NUMERIC fields are NULL.
## Field-by-field mapping (PBA → End User Events)
Status legend: Unchanged = same name and data. Renamed = same data, new column. Redefined = data or value format changes (handle with care). Deprecated = no equivalent.
| PBA field | Status | New field / handling |
|---|---|---|
| advertising_id | Deprecated | Mobile/device ID. Cross-platform reports are CUID-based; drop it. |
| af_web_id | Renamed | appsflyer_id_value, same web cookie. |
| amazon_aid | Deprecated | Mobile/device ID, not relevant for web. |
| android_id | Deprecated | Mobile/device ID, not relevant for web. |
| app_id | Deprecated | Mobile cross-platform field. The new web app identifier is unified_app_id ("website-{domain}"), a different concept, not a rename. |
| app_name | Unchanged | app_name. |
| app_version | Deprecated | Mobile cross-platform field. |
| appsflyer_id | Deprecated | Mobile install ID. Note: the new appsflyer_id_value is the web cookie (PBA's af_web_id), NOT this field. |
| attributed_touch_time | Renamed | event_time__attribution. |
| attributed_touch_type | Deprecated | Was a constant. Visit-vs-event now lives in end_user_event_type. |
| bundle_id | Deprecated | Replaced by the Product Line grouping in the cross-platform report. |
| campaign | Renamed | campaign_name. |
| campaign_id | Unchanged | campaign_id. |
| city | Unchanged | city. |
| country_code | Unchanged | country_code. |
| customer_user_id | Unchanged | customer_user_id. |
| device_type | Renamed + values change | device_category, values differ (e.g. "Desktop" → "MOBILE_PHONE" / "TV" style values). Update any value-keyed logic. |
| dma | Unchanged | dma. |
| event_name | Redefined | Events: unchanged. Visits: now empty (PBA wrote "website visit"). Use end_user_event_type = 'SESSION' to identify visits. |
| event_revenue | Renamed | revenue_value_original. |
| event_revenue_currency | Renamed | revenue_currency_original. |
| event_revenue_usd | Renamed | revenue_usd. |
| event_source | Unchanged | event_source. |
| event_time | Unchanged | event_time. |
| event_type | Redefined | "Conversion event" marking no longer exists. Visit-vs-event lives in end_user_event_type (SESSION / IN_APP). |
| event_url | Unchanged | event_url, now also the primary place URL query params (UTMs, etc.) are read from. |
| event_value | Unchanged | event_value. |
| idfa / idfv / imei / oaid | Deprecated | Mobile/device IDs, not relevant for web. |
| install_time | Deprecated | Mobile field. The web user-acquisition time is event_time__conversion, a separate concept. |
| ip | Renamed | ip_address_value (plus ip_address_type for the hashing method). |
| language | Redefined | language, format changes to ISO 639-1 + country code (was e.g. "English"). |
| media_channel | Deprecated | Can be covered by sub_param_1-5 if needed. |
| media_source | Unchanged | media_source (but see value renames below). |
| media_type | Deprecated | Use the is_organic boolean instead. |
| original_url | Renamed | Consolidated into event_url (on visits, event_url equals the original URL). Standalone column gone. |
| platform | Redefined | platform is always "WEBSITE". The OS moved to os_version / user_agent. |
| postal_code | Unchanged | postal_code. |
| query_params | Deprecated | The raw query string lives in event_url; the parsed-JSON column is gone. Re-implement parsing from event_url if needed. |
| referrer | Renamed | http_referrer. |
| region | Renamed | continent, continent code (e.g. "NA"). |
| state | Unchanged | state. |
## Attributed-value changes (update filters and groupings)
The attribution engine resolves traffic sources differently, so some VALUES change even where field names don't:
- media_source renames: doubleclick_int → dv360_int (Google display/video via UTM); "X Ads" → "Twitter" (Twitter via UTM). More PID values now remap to display names (e.g. iossearchads_int → Apple Search Ads, metweb_int → Facebook Ads, tiktokweb_int → tiktokglobal_int, snapweb_int → snapchat_int).
- Channel labels change format: Direct / Organic search / Social media / Email / Ad / Referral / Other become DIRECT / ORGANIC_SEARCH / SOCIAL_MEDIA / EMAIL / AD / REFERRAL / OTHER.
- Click-ID coverage expanded (more networks resolve from click IDs); dclid alone no longer resolves; fbclid is not used.
Scan the codebase for any filter, CASE, join key, or dashboard grouping keyed on these old values and update them.
## Step 3: Build
1. Propose the new ETL design (ingestion, schema, incremental hourly logic, the mandatory filters from "Structural changes").
2. After my approval, implement it, reusing our existing conventions and infrastructure.
3. For every Deprecated field the inventory found in downstream use, list the consumer and propose a resolution (drop, replace with the suggested alternative, or flag to the business owner).
## Step 4: Validate
1. Run both pipelines on the same day range and compare: visits (SESSION rows) vs PBA website visits, events (IN_APP rows) vs PBA website events, and revenue totals.
2. Expect differences, not equality: the new attribution logic is more advanced, so attributed dimensions (media_source, campaign) will not match PBA exactly. Session counting logic is unchanged (30 minutes of activity), so visit volumes should be in the same ballpark.
3. Verify the is_primary_attribution filter is applied everywhere; its absence shows up as inflated event counts.
4. Produce a short migration report: what was mapped, what was dropped, what changed in values, and any open items for the business owner.
参考資料:PBA Web-S2Sから新しいS2S APIへの移行
PBAのWeb Server-to-server events API(Web-S2S)経由でイベントを送信している場合は、新しいS2S APIへ移行してください。新しいAPIは訪問とイベントの両方に対応しているため、Webサイト全体をサーバーサイドで実装できます。PBAのS2Sではイベントのみ受け付けていました。
エンドポイントと認証
| PBA Web-S2S | 新しい S2S API | |
|---|---|---|
| Base URL | https://webs2s.appsflyer.com |
https://events.appsflyer.com |
| Event call | POST /v1/{bundleId}/event |
POST /v2.0/s2s/inapps/app/web/{appId} |
| Visit call | 利用不可(訪問はWeb SDKからのみ送信) | POST /v2.0/s2s/visits/app/web/{appId} |
| Identity call |
POST /v1/{bundleId}/setcuid(CUIDとWebユーザーを紐づけるための別リクエスト) |
なし。ID情報は、すべてのイベント/訪問リクエストのuser_idオブジェクト内で直接送信 |
| App identifier |
URLパス内のbundleId(Brand Bundle ID) |
URLパス内のappId=Webのunified_app_id("website-{domain}") |
| Authentication |
すべてのリクエストのJSONボディ内にwebDevKey
|
S2S API keyを含むAuthorizationヘッダー |
| Content type | application/json |
application/json |
| Success response | 200 OK | 202 Accepted |
ペイロードフィールドのマッピング
| PBA Web-S2Sフィールド | 新しいS2Sフィールド | 注意 |
|---|---|---|
customerUserId |
user_id.customer_user_id |
user_idオブジェクト内にネストされます。 |
afUserId |
user_id.appsflyer_id |
user_idオブジェクト内にネストされます。customer_user_idまたはappsflyer_idの少なくとも一方を送信してください。ユーザーが識別されている場合は、可能な限り両方を送信してください。 |
webDevKey |
— | リクエストボディから削除されます。認証はAuthorizationヘッダーへ移動し、アプリはURLパス内のappIdで識別されます。 |
eventType(常にEVENT) |
— | 削除されます。エンドポイント(/inappsまたは/visits)によってタイプが決まります。 |
eventName |
event_name |
1〜64文字。@ = + -は使用できません。 |
timestamp(Unix ms、13桁) |
timestamp(Unix ms) |
形式は同じです。すべてのリクエストで送信することを推奨します。省略した場合は、AppsFlyerが受信した時刻が使用されます。 |
eventValue |
event_value |
自由形式。custom_parametersサブオブジェクトに対応しています。 |
eventRevenue |
event_revenue |
任意項目になります(PBAではダッシュボード表示のために必須でした)。 |
eventRevenueCurrency |
event_revenue_currency |
任意項目になります(PBAではダッシュボード表示のために必須でした)。 |
referrer |
http_referrer |
名称変更。 |
userAgent |
user_agent |
名称変更。 |
ip |
ip |
変更なし。 |
| — | event_url |
新規項目。訪問では必須、イベントでは任意。 |
| — | customer_dedup_id |
新規項目。別の送信元(例:Web SDK)から同じイベントが到着した場合に重複排除します。 |
| — |
email_hashed, phone_number_hashed, phone_number_e164_hashed, first_name_hashed, last_name_hashed
|
新規項目。ID情報を補完するために、正規化された値をSHA256(64文字の小文字16進数)でハッシュ化した値を送信します。 |
S2S APIに関する注意事項
- 訪問もサーバーサイドで送信できるようになります:PBAのS2Sではイベントのみ受け付けており、訪問はWeb SDKから送信する必要がありました。新しい/visitsエンドポイントにより、Webサイト全体をサーバーサイドで実装できます。
- setcuidの別リクエストは不要になります:PBAではWeb SDKが必須だったため、CUIDとWebユーザーを紐づけるために別リクエストが必要でした。新しいAPIではすべてのリクエストでID情報を直接送信するため、このステップは不要です。
- 遅延データの受付期間:イベントと訪問は、1日分をまとめて一括送信するのではなく、リアルタイムで送信してください。可能であれば、イベント発生から30分以内の送信を推奨します。イベントが発生したUTC日付の終了から30分以上経過して到着したデータも受け付けられますが、そのイベント時刻はAppsFlyerが受信した時刻に置き換えられます。
S2Sサービス移行向け:そのまま使えるコーディングエージェント用プロンプト
PBA Server-to-server API経由でイベントを送信している場合に備えて、AIコーディングエージェント(Claude Code、Cursorなど)ですぐに使えるプロンプトを用意しました。エージェントにAppsFlyerへイベントを送信しているサービスへのアクセス権を付与し、以下のプロンプトを貼り付けてください。このプロンプトには、すべてのエンドポイントとペイロードのマッピングが含まれています。エージェントは現在の実装を把握したうえで、更新後の実装を構築します。
You are migrating a server-side integration from AppsFlyer's legacy PBA Web S2S events API (webs2s.appsflyer.com) to AppsFlyer's new S2S API for Web Performance Measurement (events.appsflyer.com). Everything you need is in this prompt: endpoints, authentication, the complete payload mapping, and the behavior changes. Do not guess anything beyond what is written here; if something is ambiguous, ask me.
## Step 0: Ask me these questions before touching code
1. Should we modify the existing service in place, or create a new service/module alongside it (allowing a parallel-run and clean cutover)? Recommend a new module alongside.
2. Do I know our new web app's Unified App ID? Format: "website-{domain}" (e.g. website-www.example.com). It replaces PBA's bundle ID in the URL path. If I don't know it, I'll get it from the AppsFlyer dashboard before we continue.
3. Do I have the new S2S API key? Authentication moved from the webDevKey in the request body to an Authorization header carrying this key. If I don't have it, I'll retrieve it from the AppsFlyer dashboard.
4. Do we want to send events only (like PBA), or adopt the new visits endpoint too? The new API supports server-side visits, so the website can run fully server-side; PBA accepted events only.
5. Is the AppsFlyer Web SDK still running on our site? (Determines whether visits come from the SDK and whether we need event deduplication between SDK and S2S.)
## Step 1: Learn the current service
Explore the codebase and produce an inventory:
1. Every call site to webs2s.appsflyer.com, the /event calls and any /setcuid calls.
2. The fields populated on each call (customerUserId, afUserId, eventName, eventValue, eventRevenue, timestamp, referrer, userAgent, ip, etc.) and where their values come from.
3. Error handling and monitoring keyed on the 200 OK response.
4. Retry, batching, and queueing behavior.
Present this inventory to me and wait for my confirmation before proceeding.
## What changed: endpoints and authentication
| | PBA Web-S2S (old) | New S2S API |
|---|---|---|
| Base URL | https://webs2s.appsflyer.com | https://events.appsflyer.com |
| Event call | POST /v1/{bundleId}/event | POST /v2.0/s2s/inapps/app/web/{appId} |
| Visit call | Not available | POST /v2.0/s2s/visits/app/web/{appId} |
| Identity call | POST /v1/{bundleId}/setcuid | None, identity is inline in the user_id object on every call |
| App identifier in path | bundleId (brand bundle ID) | appId = the web Unified App ID ("website-{domain}") |
| Authentication | webDevKey in the JSON body | Authorization header with the S2S API key |
| Content type | application/json | application/json (415 if missing) |
| Success response | 200 OK | 202 Accepted |
## Payload field mapping
| PBA field | New field | Note |
|---|---|---|
| customerUserId | user_id.customer_user_id | Nested in the user_id object. |
| afUserId | user_id.appsflyer_id | Nested in the user_id object. Send at least one of customer_user_id or appsflyer_id; send both whenever the user is identified. |
| webDevKey | (removed) | Auth moved to the Authorization header; the app is identified by appId in the path. |
| eventType (always "EVENT") | (removed) | The endpoint (/inapps vs /visits) determines the type. |
| eventName | event_name | 1-64 chars; cannot contain @ = + - characters. |
| timestamp (Unix ms) | timestamp (Unix ms) | Same format. Recommended on every call; if omitted, AppsFlyer uses receive time. |
| eventValue | event_value | Free-form; supports a custom_parameters sub-object. |
| eventRevenue | event_revenue | Now optional (PBA required it for dashboards). |
| eventRevenueCurrency | event_revenue_currency | Now optional (PBA required it for dashboards). |
| referrer | http_referrer | Renamed. |
| userAgent | user_agent | Renamed. |
| ip | ip | Unchanged. |
| (new) | event_url | Required on visits; optional on events. |
| (new) | customer_dedup_id | Deduplicates against the same event arriving from another source (e.g. the Web SDK). |
| (new) | email_hashed, phone_number_hashed, phone_number_e164_hashed, first_name_hashed, last_name_hashed | SHA256 (64-char lowercase hex) of normalized values, for identity enrichment. |
## Behavior changes and gotchas
1. **appId is the Unified App ID, not the "Web SDK ID".** The AppsFlyer app settings page shows a "Web SDK ID" UUID (the former Web Dev Key, kept for SDK continuity). The S2S path must carry the Unified App ID ("website-{domain}"), never that UUID. A 401 "app not found" usually means a wrong appId in the path or a missing/invalid Authorization header.
2. **Success is 202, not 200.** Update health checks, retries, and alerting accordingly.
3. **Don't validate against the old endpoint.** The legacy endpoint may still return 200, but that response is not proof that data reached Web Performance Measurement. Always verify events actually appear in the new web app's data.
4. **Drop the setcuid flow entirely.** Identity travels inline in the user_id object on every event and visit.
5. **Visits before events.** The system expects a visit before any event from a user; events for a user with no prior visit are classified as organic. Visits come from the Web SDK, or, new, from the /visits endpoint.
6. **Send in real time; don't batch.** Send every event and visit as it happens, preferably within 30 minutes of the event occurring. Data that arrives later than 30 minutes after the end of the UTC day in which the event occurred is still accepted, but its event time is replaced with the receive time, which distorts attribution. Always send a timestamp. Note that the approximately 30-minute attribution delay you may read about is a separate, server-side hold on AppsFlyer's side, nothing for us to implement.
7. **Full server-side option (if we adopt visits).** With no Web SDK, our server owns the web user identifier: generate a stable ID for first-time visitors, persist it as a server-set first-party HTTP cookie (Set-Cookie header, not JavaScript; JS cookies are capped at approximately 7 days on Safari), reuse it on every request, and send it as user_id.appsflyer_id. The visit payload must include event_url (and should include ip, user_agent, http_referrer for attribution quality).
8. **SDK + S2S together.** If both send the same event, populate customer_dedup_id so AppsFlyer keeps one copy.
## Step 2: Build
1. Propose the design: new client/module, config (base URL, appId, API key storage in our secrets manager, never hardcoded), payload builders for events (and visits, if in scope), and the response/retry handling for 202.
2. After my approval, implement it following our existing conventions.
3. Map every field from the inventory through the payload mapping above; flag any field we currently send that has no new equivalent.
## Step 3: Validate
1. Send a test event (and visit, if in scope) and confirm a 202 response.
2. Verify the test data appears in the new web app in AppsFlyer (dashboard or Data Locker); this is the real success signal, not the HTTP response.
3. Confirm event names comply with the new constraints (1-64 chars, no @ = + -).
4. If running in parallel with the old service, compare event volumes between old and new for a few days before cutover, then decommission the old calls including setcuid.
参考資料:トラフィックソース判定におけるPBAとWeb Performance Measurementの違い
メディアソース、チャネル、キャンペーンの値がPBAでレポートされていた内容と異なる場合、その理由は以下のとおりです。どちらも基本的な仕組みは同じで、Web訪問時のURLパラメーターとリファラーをもとに、優先順位に従って判定し、最初に一致した条件をメディアソースとして採用します。ただし、いくつかのルールが変更されており、その結果、レポートに表示される値にも違いが生じます。ソース:PBAのメディアソースアトリビューションルール、トラフィックソース判定について
メディアソースの値の名称変更
| 判定条件 | PBAの値 | 新しい値 |
|---|---|---|
| Googleのディスプレイ / 動画(utm_source=Google+utm_medium=cpm / display / banner / video / listing) | doubleclick_int |
dv360_int |
| UTM経由のTwitter(twitter+cpc) | X Ads |
Web Performance Measurementでは、より多くのPID値が表示名へ変換されます。たとえば、iossearchads_intはApple Search Ads、metweb_intはFacebook Ads、twitterweb_intはTwitter、tiktokweb_intはtiktokglobal_int、snapweb_intはsnapchat_intに変換されます。従来のローデータ値を前提に構築されたレポートでは、これらの新しい値を考慮する必要があります。
クリックIDの対応範囲拡大とdclidの廃止
PBAでは、3種類のクリックIDを判定に使用していました。gclidはgoogleadwords_int、dclidはdoubleclick_int、msclkidはbingsearch_intとして判定されます。
Web Performance Measurementでは、より多くのクリックIDに対応しています。gclid / wbraid / gbraidはgoogleadwords_int、msclkid はbingsearch_int、twclidはTwitter、vmcidはyahoogemini_int、sccidはsnapchat_int、li_fat_idはlinkedin_int、ttclidはtiktokglobal_int、tbclidはtaboola_int、ob_click_id / dicboはoutbrain_int、yclidはyandex_int、rdt_cidはreddit_intとして判定されます。
警告
挙動に2つの変更があります。dclid単体ではトラフィックソースの判定に使用されなくなりました(PBAではdoubleclick_intとして判定されていました)。また、fbclidは明示的に使用されません。
UTMカスタムルールの拡張
utm_source + utm_mediumを使用したカスタムマッピングは、Web Performance Measurementでより幅広く対応するようになっています。paid、paid_search、paid-searchなど、より多くのutm_mediumの表記に対応するほか、PBAでは限定的な単一のutm_mediumルールのみだったTikTok、Snapchat、Pinterestについても対応範囲が拡大されています。カスタムルールに一致しない場合は、どちらもutm_sourceの元の値をそのまま使用します。
チャネル
チャネルの値も形式が変更されます。PBAのDirect / Organic search / Social media / Email / Ad / Referral / Otherから、新しいDIRECT / ORGANIC_SEARCH / SOCIAL_MEDIA / EMAIL / AD / REFERRAL / OTHERへ変更されます。従来のラベルを条件にしているフィルターやグルーピングは更新する必要があります。