【Adjust】リアルタイムコールバック機能を使ってみる

XTechグループ 2 Advent Calendar 2020 の11日目は
iXIT株式会社エンジニアの鎌倉(@ixit_kamakura)が担当いたします:information_desk_person:

はじめに
---
長い(短い？)夏が終わり、涼しさを感じる季節に移り変わった頃、営業さんからとある要望が伝えられました。

営業さん「広告流入元別に、(サービス側の管理画面で)ユーザーの動向を探りたいのですが、可能ですか？」

残念なことに、当時はDBのユーザー情報に広告流入元識別子が紐づいていなかったため、この要望にお答えすることができなかったのですが
最終的にAdjustリアルタイムコールバックを使用して、DBのユーザー情報に広告流入元識別子を紐付け、サービス側の管理画面でユーザーの動向を探れるようにしましたので、今回は「**Adjustリアルタイムコールバックを使用して、DBのユーザー情報に広告流入元識別子を紐付ける**」実装について書きたいと思います。

Adjustリアルタイムコールバックとは
---
Adjustがイベントを計測した数秒後に、広告ID、アトリビューションの詳細、アプリデータをサーバーに直接送信できる機能のこと(公式ドキュメント：https://help.adjust.com/ja/article/callbacks)

アプリ名、AdjustのデバイスIDなど、 [デフォルトで用意されている項目](https://help.adjust.com/ja/article/best-practices-callbacks#recommended-placeholders-for-all-callback-urls)であれば、Adjustの管理画面から設定することで値が取れますが、クライアントサイドにて実装を行うことでユーザーIDなどの値もパラメータに含めることが可能です。

今回は、ユーザーIDをパラメータに含めるようにクライアントサイドに実装していただいた上で、サーバーサイドの実装を行いました。
（クライアントサイドの実装に関しては他の記事を併用いただけますと幸いです。）

システム構成
---
- PHP 7.1.7
- CakePHP3.4.7
- mysql 10.0.31


作業内容
---

1. リアルタイムコールバックがコールされるタイミングを決める
1. DBにカラム追加&テーブル作成を行う
1. Adjustの管理画面にて、リアルタイムコールバックの設定を行う
1. リアルタイムコールバックを受信するためのコントローラーを作成する

1.リアルタイムコールバックがコールされるタイミングを決める
---
まず、ユーザーがどのアクションをした際にリアルタイムコールバックをコールするか決める必要があります。
※ 全てのアクションに設定することも可能ですが、サーバー負荷がかかってしまいます。。

今回は、既にサービスがローンチしていることを踏まえ、下記アクション時にコールするように設定しました。
・ 新規会員登録時
・ 該当アプリにて多く行われるであろうアクション(記録系アプリなら「記録」ボタンの押下 etc)

サービスのローンチ前でしたら、新規会員登録時だけでも良い気がします。

2. DBにカラム追加&テーブル作成を行う
---
ユーザー情報に広告流入元識別子を紐付けること、管理画面にて動向を探ることが目的なので
・usersテーブルに「tracker」カラムを追加
　→ 広告流入元の識別子をユーザー情報へと紐づける
・tracker_managersテーブルを新規作成
　→ 広告流入元識別子と広告名の対応を記録する
の作業を行いました。
※ 広告流入元の識別子だけでは管理画面実装時に何の広告かわかりにくいので、tracker_managersテーブルを用意しています。

最終的には下記のDB構造になりました。

usersテーブル

| Field         | Type             | Null | Key | Default | Extra          |
|---------------|------------------|------|-----|---------|----------------|
| id  　　　     | int(11) unsigned | NO   | PRI |         | auto_increment |
| tracker_token | varchar(255)     | YES  |     |         |                |
| created       | datetime         | NO   |     |         |                |
| modified      | datetime         | YES  |     |         |                |
| deleted       | datetime         | YES  |     |         |                |

tracker_managersテーブル

| Field         | Type             | Null | Key | Default | Extra          |
|---------------|------------------|------|-----|---------|----------------|
| id            | int(11) unsigned | NO   | PRI |         | auto_increment |
| tracker_token | varchar(255)     | YES  |     |         |                |
| tracker_name  | varchar(255)     | YES  |     |         |                |
| created       | datetime         | NO   |     |         |                |
| modified      | datetime         | YES  |     |         |                |
| deleted       | datetime         | YES  |     |         |                |

3. Adjustの管理画面にて、リアルタイムコールバックの設定を行う
---
(設定した直後からリアルタイムコールバックがコールされるため、場合によっては実装が終わるまでは設定をしない方が良いかもしれないです)

Adjustの管理画面からアプリ設定>その他の設定>ローデータエクスポート>リアルタイムコールバックと進みます。

次に、上記で策定した「リアルタイムコールバックをコールするタイミング」を検索窓から探し出し、右の鉛筆マークをクリックし、コールバックURLを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489170/21c02b2f-e781-95f9-01a1-1a5341be92b4.png)

今回は、デフォルトで用意されている `tracker` `tracker_name` に加え、クライアントサイドに設定していただいた `user_id` を取得したいので、下記のように設定しました。
`https://ドメイン名/callback?tracker={tracker}&tracker_name={tracker_name}`

`user_id`については、クライアントサイドで実装していただくことで自動的に付加されるそうです。
つまりは、最終的には下記のURLを受信することになります。
`https://ドメイン名/callback?tracker={tracker}&tracker_name={tracker_name}&user_id={user_id}`

4. リアルタイムコールバックを受信するためのコントローラーを作成する
---
次に、リアルタイムコールバックを受信するためのコントローラーを作成します。
コールバックURLが飛んできた場合に、リアルタイムコールバック受信用のコントローラーを呼ぶために まずはルーティングの設定を行います。

```config/routes.php
use Cake\Core\Plugin;
use Cake\Routing\Router;

Router::defaultRouteClass('DashedRoute');

// https://ドメイン名/callback を受信したら、AdjustControllerのreceiveAdjustRealtimeCallbackの処理を走らせる
Router::scope('/', function ($routes) {
    $routes->connect('callback', ['controller' => 'Adjust', 'action' => 'receiveAdjustRealtimeCallback', 'method' => 'POST']);
});

Plugin::routes();
```

設定した値はクエリパラメータとして下記の形で渡ってくるので、
`https://ドメイン名/callback?tracker={tracker}&tracker_name={tracker_name}&user_id={user_id}`

コントローラーにて
値を取得、トラッカー管理テーブルに登録されていなかったらレコードを追加、ユーザー情報にtrackerが紐づいていなかったらレコードを追加する処理を実装しました。

```AdjustController.php
public function receiveAdjustRealtimeCallback()
    {
        $data = $this->request->getQuery();
            // トラッカー管理テーブルに登録済か
            $trackerEntity = $this->TrackerManagers->findByTrackerToken($data['tracker'])->first();
            if (empty($trackerEntity)) {
                $record = $this->TrackerManagers->newEntity();
                $record->tracker_token = $data['tracker'];
                $record->tracker_name = $data['tracker_name'];
                $this->TrackerManager->save($record);
            }

            // ユーザー情報には既にtrackerが紐づいているか
            $userEntity = $this->Users->get($data['user_id']);
            if (empty($userEntity->tracker_token)) {
                $userEntity->tracker_token = $data['tracker'];
                $this->Users->save($userEntity);
            }
    }
```

これで作業は終了です。
指定したアクションをユーザーが実行するたびにDBへ値が記録されるようになりました:thumbsup:

最後に
---
今回の実装によって、ユーザーがどの広告から流入してきたかが紐づきましたので 
管理画面の追加実装を行うことで


広告Aから流入してきた人はアクティブ率が高い
広告Bから流入してきた人は、課金回数が多い
など、サービス側の管理画面で広告流入元に紐づいたユーザー群の特性を確認することが可能になると思います。

これらを分析することによって

アクティブ率が高いユーザーの流入元の広告カテゴリにより出稿すれば アプリ全体のアクティブ率がUPするのでは？:rocket:
課金回数が多いユーザーの流入元の広告カテゴリにより出稿すれば 売上が上がるのでは？:rocket::rocket:

など 次の施策の考案へと繋がると思います。
そして、 より効果的な施策を打つ → 効果測定 → 予想と実際の値との差を確認、、、とPDCAサイクルを回していけるのではないでしょうか。

こちらの記事が、Adjustリアルタイムコールバックをこれから利用する方のお役に立ちましたら嬉しいです。
また、不備等ございましたら ご指摘いただけますと幸いです。

[XTechグループ 2 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/xtech-group2)はまだまだ続きます:tada:
来週月曜日の執筆担当は @katsuhiro-ito さんです。引き続きお楽しみください。