# Push Eventsテーブル

ベータ機能
Mobile Pushは現在ベータ版です。このドキュメントで説明されているスキーマと実装の詳細はサンプルとして提供されており、変更される可能性があります。独自のトラッキング要件とビジネスニーズに基づいて、独自のテーブルスキーマを設計してください。

## 概要

Engage StudioでMobile Push通知を実装すると、モバイルアプリはユーザーインタラクションをトラッキングし、イベントデータをTreasure Dataに送信します。このデータは、Treasure Dataデータベース内の専用テーブル（推奨名: `push_events`）に保存されます。

このドキュメントでは、サンプルスキーマ、イベントタイプ、プッシュ通知イベントデータの操作に関するベストプラクティスについて説明します。**注意:** ここで提供されているスキーマはサンプルです。アプリケーションの要件とデータガバナンスポリシーに基づいてカスタマイズしてください。

## テーブルスキーマ

### サンプルテーブル構造

ニーズに合わせてカスタマイズ
以下に示すテーブル構造はサンプル実装です。以下に基づいて独自のスキーマを設計してください:

- トラッキング要件
- データガバナンスとプライバシーポリシー
- 分析とレポーティングのニーズ
- コンプライアンス要件（GDPR、CCPAなど）


| カラム名 | データ型 | 必須 | 説明 |
|  --- | --- | --- | --- |
| `time` | INTEGER | はい | イベント発生時のUnixタイムスタンプ（秒） |
| `type` | STRING | はい | イベントタイプ: `delivery`, `open`, `dismiss`, `link_open`, `deeplink_open`, `token_register` |
| `td_td_campaign_id` | STRING | はい | Engage Studioからのキャンペーン識別子（通知ペイロードから渡される） |
| `platform` | STRING | はい | モバイルプラットフォーム: `android` または `ios` |
| `fcm_token` | STRING | いいえ | Firebase Cloud Messagingデバイストークン（`token_register`イベントに必須） |
| `user_id` | STRING | いいえ | ユーザーがログインしている場合のユーザー識別子（例: 顧客ID、メールハッシュ値） |
| `value` | STRING | いいえ | 追加データ（例: `link_open`または`deeplink_open`のURL） |
| `device_model` | STRING | いいえ | デバイスモデル（オプション拡張） |
| `os_version` | STRING | いいえ | オペレーティングシステムバージョン（オプション拡張） |
| `app_version` | STRING | いいえ | アプリケーションバージョン（オプション拡張） |


### サンプルテーブル作成クエリ


```sql
-- サンプルpush_eventsテーブル作成（ニーズに合わせてカスタマイズしてください）
CREATE TABLE IF NOT EXISTS mobile.push_events (
  time INTEGER,
  type STRING,
  td_td_campaign_id STRING,
  platform STRING,
  fcm_token STRING,
  user_id STRING,
  value STRING,
  device_model STRING,
  os_version STRING,
  app_version STRING
)
```

## イベントタイプ

### 1. Deliveryイベント

プッシュ通知が正常に配信され、ユーザーに表示されたときにログに記録されます。

**イベントタイプ:** `delivery`

**サンプルイベント:**


```json
{
  "time": 1734134400,
  "type": "delivery",
  "td_campaign_id": "cmp_20251214_promo",
    "platform": "android",
  "user_id": "user_12345"
}
```

**トラッキングタイミング:**

- **Android**: `MyFirebaseMessagingService`で`onMessageReceived()`が呼ばれたとき
- **iOS（フォアグラウンド）**: `UNUserNotificationCenterDelegate`で`willPresent notification`が呼ばれたとき
- **iOS（バックグラウンド）**: `content-available: 1`を持つ通知に対して`didReceiveRemoteNotification`が呼ばれたとき。これには[iOS開発者ガイド](/ja/products/marketing-cloud/engage-studio/channels/mobile-push/developer-guide-ios#enabling-delivery-and-dismiss-tracking-required-app-side-setup)で説明されているアプリ側のセットアップが必要です。


### 2. Openイベント

ユーザーが通知をタップしてアプリを開いたときにログに記録されます。

**イベントタイプ:** `open`

**サンプルイベント:**


```json
{
  "time": 1734134410,
  "type": "open",
  "td_campaign_id": "cmp_20251214_promo",
    "platform": "ios",
  "user_id": "user_12345"
}
```

**トラッキングタイミング:**

- **Android**: 通知がタップされ、`MainActivity`が`PushAction.OPEN`インテントを受信したとき
- **iOS**: `didReceive response`が`UNNotificationDefaultActionIdentifier`で呼ばれたとき


### 3. Dismissイベント

ユーザーが通知を開かずに削除（スワイプ）したときにログに記録されます。

**イベントタイプ:** `dismiss`

**サンプルイベント:**


```json
{
  "time": 1734134420,
  "type": "dismiss",
  "td_campaign_id": "cmp_20251214_promo",
    "platform": "android",
  "user_id": "user_12345"
}
```

**トラッキングタイミング:**

- **Android**: 通知で`deleteIntent`がトリガーされたとき
- **iOS**: `didReceive response`が`UNNotificationDismissActionIdentifier`で呼ばれたとき


### 4. Link Openイベント

ユーザーが通知からWebリンクをタップしたときにログに記録されます。

**イベントタイプ:** `link_open`

**サンプルイベント:**


```json
{
  "time": 1734134430,
  "type": "link_open",
  "td_campaign_id": "cmp_20251214_promo",
    "platform": "android",
  "user_id": "user_12345",
  "value": "https://example.com/promo?utm_campaign=promo"
}
```

**トラッキングタイミング:**

- **Android**: `PushAction.ACTION_LINK`のアクションボタンがタップされたとき
- **iOS**: 識別子`ACTION_OPEN_LINK`のアクションボタンがタップされたとき


**注意:** `value`フィールドには開かれた完全なURLが含まれます。

### 5. Deeplink Openイベント

ユーザーが通知からアプリディープリンクをタップしたときにログに記録されます。

**イベントタイプ:** `deeplink_open`

**サンプルイベント:**


```json
{
  "time": 1734134440,
  "type": "deeplink_open",
  "td_campaign_id": "cmp_20251214_promo",
    "platform": "ios",
  "user_id": "user_12345",
  "value": "myapp://product/12345"
}
```

**トラッキングタイミング:**

- **Android**: `PushAction.ACTION_DEEPLINK`のアクションボタンがタップされたとき
- **iOS**: 識別子`ACTION_OPEN_DEEPLINK`のアクションボタンがタップされたとき


**注意:** `value`フィールドにはディープリンクURIが含まれます。

### 6. Token Registerイベント

アプリがFCMデバイストークンをTreasure Dataに登録または更新したときにログに記録されます。

**イベントタイプ:** `token_register`

**サンプルイベント:**


```json
{
  "time": 1734134400,
  "type": "token_register",
  "fcm_token": "dQw4w9WgXcQ:APA91bF...",
  "platform": "android",
  "user_id": "user_12345",
  "app_version": "1.2.3",
  "os_version": "14",
  "device_model": "Pixel 7"
}
```

**トラッキングタイミング:**

- **Android**: `MyFirebaseMessagingService`で`onNewToken()`が呼ばれたとき
- **iOS**: `MessagingDelegate`で`didReceiveRegistrationToken`が呼ばれたとき
- トークンが最新であることを確認するため、アプリ起動時にもトリガーされます


**注意:**

- ログイン済みユーザーの場合、`user_id`を含める必要があります
- 匿名ユーザーの場合、`user_id`は`null`にできます — ユーザーがログイン後に関連付けられます


## ユーザーID関連付け

### トークンとユーザーのリンク

`token_register`イベントは、デバイストークンをユーザーIDにリンクするために重要です。関連付けの仕組みは次のとおりです:

#### シナリオ1: ユーザーが既にログイン済み

ユーザーがアプリをインストールし、既にログインしている（またはすぐにログインする）場合:


```json
{
  "type": "token_register",
  "fcm_token": "ABC123...",
  "user_id": "user_12345",
  "platform": "android"
}
```

トークンは即座にユーザーに関連付けられます。

#### シナリオ2: 匿名ユーザー（未ログイン）

ユーザーがアプリをインストールしたが、まだログインしていない場合:


```json
{
  "type": "token_register",
  "fcm_token": "ABC123...",
  "user_id": null,
  "platform": "android"
}
```

トークンは登録されますが、まだユーザーにリンクされていません。

#### シナリオ3: ユーザーが後でログイン

以前は匿名だったユーザーがログインした場合、新しい`token_register`イベントを送信します:


```json
{
  "type": "token_register",
  "fcm_token": "ABC123...",
  "user_id": "user_12345",
  "platform": "android"
}
```

Treasure Dataは、この`fcm_token`を持つすべての過去のイベントを`user_12345`にリンクできるようになります。

### 名前解決クエリ

匿名トークンをユーザーに解決するには、次のクエリを使用します:


```sql
WITH latest_tokens AS (
  SELECT
    fcm_token,
    user_id,
    time,
    ROW_NUMBER() OVER (PARTITION BY fcm_token ORDER BY time DESC) AS rn
  FROM mobile.push_events
  WHERE type = 'token_register'
    AND user_id IS NOT NULL
)
SELECT
  fcm_token,
  user_id
FROM latest_tokens
WHERE rn = 1
```

## 分析クエリ

### キャンペーンパフォーマンス概要

すべてのキャンペーンの配信率、開封率、クリック率を取得:


```sql
SELECT
  td_campaign_id,
  COUNT(CASE WHEN type = 'delivery' THEN 1 END) AS deliveries,
  COUNT(CASE WHEN type = 'open' THEN 1 END) AS opens,
  COUNT(CASE WHEN type = 'link_open' OR type = 'deeplink_open' THEN 1 END) AS clicks,
  COUNT(CASE WHEN type = 'dismiss' THEN 1 END) AS dismissals,
  ROUND(100.0 * COUNT(CASE WHEN type = 'open' THEN 1 END) / NULLIF(COUNT(CASE WHEN type = 'delivery' THEN 1 END), 0), 2) AS open_rate_pct,
  ROUND(100.0 * COUNT(CASE WHEN type = 'link_open' OR type = 'deeplink_open' THEN 1 END) / NULLIF(COUNT(CASE WHEN type = 'delivery' THEN 1 END), 0), 2) AS click_rate_pct
FROM mobile.push_events
WHERE time >= CAST(strftime('%s', 'now', '-30 days') AS INTEGER)
GROUP BY td_campaign_id
ORDER BY deliveries DESC
```

### プラットフォーム比較

AndroidとiOSのパフォーマンスを比較:


```sql
SELECT
  platform,
  COUNT(CASE WHEN type = 'delivery' THEN 1 END) AS deliveries,
  COUNT(CASE WHEN type = 'open' THEN 1 END) AS opens,
  ROUND(100.0 * COUNT(CASE WHEN type = 'open' THEN 1 END) / NULLIF(COUNT(CASE WHEN type = 'delivery' THEN 1 END), 0), 2) AS open_rate_pct
FROM mobile.push_events
WHERE td_campaign_id = 'cmp_20251214_promo'
GROUP BY platform
```

### 開封までの時間分析

ユーザーが通知を開くまでの時間を分析:


```sql
WITH delivery_times AS (
  SELECT
    td_campaign_id,
    user_id,
    fcm_token,
    time AS delivery_time
  FROM mobile.push_events
  WHERE type = 'delivery'
),
open_times AS (
  SELECT
    td_campaign_id,
    user_id,
    fcm_token,
    time AS open_time
  FROM mobile.push_events
  WHERE type = 'open'
)
SELECT
  CASE
    WHEN (o.open_time - d.delivery_time) < 60 THEN '< 1 minute'
    WHEN (o.open_time - d.delivery_time) < 300 THEN '1-5 minutes'
    WHEN (o.open_time - d.delivery_time) < 3600 THEN '5-60 minutes'
    WHEN (o.open_time - d.delivery_time) < 86400 THEN '1-24 hours'
    ELSE '> 24 hours'
  END AS time_bucket,
  COUNT(*) AS count
FROM delivery_times d
JOIN open_times o
  ON d.td_campaign_id = o.td_campaign_id
  AND d.user_id = o.user_id
  AND d.fcm_token = o.fcm_token
GROUP BY time_bucket
ORDER BY MIN(o.open_time - d.delivery_time)
```

### 最もクリックされたリンク

最も多くクリックされたリンクを特定:


```sql
SELECT
  td_campaign_id,
  value AS clicked_url,
  COUNT(*) AS click_count,
  COUNT(DISTINCT user_id) AS unique_users
FROM mobile.push_events
WHERE type IN ('link_open', 'deeplink_open')
  AND value IS NOT NULL
GROUP BY td_campaign_id, value
ORDER BY click_count DESC
LIMIT 20
```

### デイリーアクティブトークン

デイリーアクティブデバイストークンをトラッキング:


```sql
SELECT
  DATE(time, 'unixepoch') AS event_date,
  platform,
  COUNT(DISTINCT fcm_token) AS active_tokens
FROM mobile.push_events
WHERE time >= CAST(strftime('%s', 'now', '-30 days') AS INTEGER)
  AND type IN ('delivery', 'open', 'link_open', 'deeplink_open')
GROUP BY event_date, platform
ORDER BY event_date DESC, platform
```

### ユーザーエンゲージメントファネル

特定のキャンペーンのエンゲージメントファネルを分析:


```sql
WITH funnel_data AS (
  SELECT
    user_id,
    MAX(CASE WHEN type = 'delivery' THEN 1 ELSE 0 END) AS delivered,
    MAX(CASE WHEN type = 'open' THEN 1 ELSE 0 END) AS opened,
    MAX(CASE WHEN type IN ('link_open', 'deeplink_open') THEN 1 ELSE 0 END) AS clicked
  FROM mobile.push_events
  WHERE td_campaign_id = 'cmp_20251214_promo'
  GROUP BY user_id
)
SELECT
  SUM(delivered) AS total_delivered,
  SUM(opened) AS total_opened,
  SUM(clicked) AS total_clicked,
  ROUND(100.0 * SUM(opened) / NULLIF(SUM(delivered), 0), 2) AS open_rate_pct,
  ROUND(100.0 * SUM(clicked) / NULLIF(SUM(opened), 0), 2) AS click_through_rate_pct
FROM funnel_data
```

## データ保持とアーカイブ

### パーティション戦略

大規模デプロイメントでは、日付別にテーブルをパーティション化することを検討してください:


```sql
-- 月次パーティションテーブルを作成
CREATE TABLE mobile.push_events_202512 AS
SELECT * FROM mobile.push_events
WHERE time >= 1733011200 AND time < 1735689600
```

### 古いイベントのアーカイブ

90日以上前のイベントを別のテーブルにアーカイブ:


```sql
CREATE TABLE mobile.push_events_archive AS
SELECT * FROM mobile.push_events
WHERE time < CAST(strftime('%s', 'now', '-90 days') AS INTEGER)
```

メインテーブルから削除:


```sql
DELETE FROM mobile.push_events
WHERE time < CAST(strftime('%s', 'now', '-90 days') AS INTEGER)
```

## ベストプラクティス

### 1. Push Events専用テーブルを使用

**推奨:** プッシュ通知イベントを別の`push_events`テーブルに保存します。

**理由:** プッシュイベントは一般的なアプリイベント（例: `event_app`）とは異なるスキーマを持つため、クエリと分析が容易になります。

### 2. 利用可能な場合はユーザーIDを含める

ユーザーがログインしている場合は、常にイベントに`user_id`を含めてください。これにより次のことが可能になります:

- ユーザーレベルの分析
- クロスデバイストラッキング
- パーソナライズされたキャンペーン最適化


### 3. イベントのバッチアップロード

イベントをバッチ（リクエストあたり最大500イベント）でアップロードして:

- ネットワークオーバーヘッドを削減
- アプリパフォーマンスを向上
- ネットワーク状態が悪い場合でも確実な配信を保証


### 4. リトライロジックの実装

イベントアップロードが失敗した場合:

- イベントをローカルキューに保持
- 指数バックオフでリトライ
- 最大リトライ試行回数を制限（例: 3〜5回）


### 5. イベント品質の監視

定期的に次のことを確認:

- 必須フィールドの欠落（`td_campaign_id`、`platform`、`type`）
- 重複イベント（同じ`td_campaign_id` + `user_id` + `fcm_token` + `type` + `time`）
- 異常なイベントパターン（例: 配信なしの開封）


### 6. 必要に応じてカスタムフィールドを追加

ビジネスに関連する追加フィールドでスキーマを拡張:

- `device_model`: デバイスタイプ別のパフォーマンストラッキング
- `os_version`: OS固有の問題の特定
- `app_version`: イベントとアプリリリースの関連付け
- `location`: 地理ベースの分析（プライバシーコンプライアンスを確保）


## セキュリティとプライバシー

### データ保護

- **PIIをログに記録しない**: イベントにメールアドレス、電話番号、その他の個人を特定できる情報を保存しないでください
- **ユーザーIDをハッシュ化**: Treasure Dataに送信する前にユーザーIDのハッシュ化を検討してください
- **書き込み専用キーを使用**: モバイルアプリは書き込み専用APIキーを使用し、マスターキーは絶対に使用しないでください
- **転送中の暗号化**: すべてのデータアップロードはHTTPSを使用します


### GDPR/プライバシーコンプライアンス

アプリがプライバシー規制地域のユーザーにサービスを提供する場合:

- イベントをトラッキングする前にユーザーの同意を取得
- オプトアウトメカニズムを提供
- データ削除ワークフローを実装
- データ保持ポリシーを文書化


## 関連ドキュメント

- [Mobile Pushセットアップ](/ja/products/marketing-cloud/engage-studio/channels/mobile-push/mobile-push-setup) - FirebaseとTreasure Data統合の設定
- [Android開発者ガイド](/ja/products/marketing-cloud/engage-studio/channels/mobile-push/developer-guide-android) - Androidでプッシュ通知を実装
- [iOS開発者ガイド](/ja/products/marketing-cloud/engage-studio/channels/mobile-push/developer-guide-ios) - iOSでプッシュ通知を実装
- [キャンペーン作成](/ja/products/marketing-cloud/engage-studio/channels/mobile-push) - Mobile Pushキャンペーンの作成と送信