ServiceWorker を使用している場合、WebPush は サイト を閲覧していない状態でも受け取ることができます。
この状態だと、サイト上の JavaScript に実装しているリスナで event の受信ができません。
OneSignal の場合、 WebHook URL の設定があり、URL を設定すると event 発生時、OneSignal の JavaScript が POST リクエストを送信してくれます。

サーバ側に POST の受け皿となるプログラムを配置し、このプログラム経由で、Google Analytics に Measurement Protocol で event を送信できるか試してみました。結果を以下に記載します。


参考

Webhook の設定方法は以下に記載があります。

以下は、CORS に関するリンクになります。


前提

バックエンド、フロントエンドには、それぞれ以下、ライブラリを使用しています。

バックエンド

Django 、 wagtail、 puput、 djangorestframework を使用しています。

  • Django (1.11.11)
  • wagtail (1.13.1)
  • puput (0.9.2.1)
  • djangorestframework (3.6.4)

フロントエンド

react と、 React Material Web Components、react-helmet を使用しています。

  • react@16.2.0
  • rmwc@1.1.2
  • react-helmet@5.2.0

実装

OneSignal で Webhooks URL を設定する

OneSinal の init に webhooks 属性を追加します。
cors を true にすると、X-OneSignal-Eventいう Request Header を付与されて、Webhooks URL に POST 送信 が行われます。

    var OneSignal = window.OneSignal || [];
    OneSignal.push(["init", {
      appId: "${config.oneSignalAppId}",
      autoRegister: false,
      allowLocalhostAsSecureOrigin: true,
      notifyButton: {
          enable: false /* Set to false to hide */
      },
      webhooks: {
         cors: true, // Defaults to false if omitted
         "notification.displayed": "https://mutter.monotalk.xyz/notification/collect/",
         "notification.clicked": "https://mutter.monotalk.xyz/notification/collect/",
         "notification.dismissed": "https://mutter.monotalk.xyz/notification/collect/"
      }
    }]);

サーバ側の実装

サーバ側は、 Django REST framework を使って実装しました。

  • rest_framework.py
    api_view デコレータで POST のみを受け付けるようにしました。
    Header の設定有無で、HTTP_400_BAD_REQUEST返すようにしましたが、referrer のチェック等の実装しておいたほうがいいかもしれません。
    Header のチェックで問題がなければ、POST されたデータを、Measurement Protocol の形式に変換して送信します。
    content-type は、x-www-form-urlencoded なので、辞書をデータとして直接送信します。

    from django.http import Http404
    from rest_framework import status
    from rest_framework.decorators import api_view
    import json
    import requests
    
    @api_view(['POST'])
    def collect_notification_event(request):
        """
        List all code snippets, or create a new snippet.
        """
        event = request.META.get('HTTP_X_ONESIGNAL_EVENT', None)
        if event not in ["notification.clicked","notification.displayed","notification.dismissed"]:
            return Response(status=status.HTTP_400_BAD_REQUEST)
    
        if request.method == 'POST':
            json_data = request.data
            payload = {"v": "1", 
                       "t": "event", 
                       "tid": "UA-xxxxxxxx-x",
                       "cid": json_data.get("userId", ""),
                       "hl": "ja",
                       "ni": "1",
                       "ec": "Notification",
                       "ea": json_data.get("event", ""),
                       "el": json_data.get("heading", "")
                      }
            r = requests.post("https://www.google-analytics.com/collect", data=payload)
            return Response(status=r.status_code)
        else:
            return Response(status=status.HTTP_400_BAD_REQUEST)
    

  • urls.py

    from home.api.rest_framework import collect_notification_event
    urlpatterns = [
        url(r'^notification/collect/$', collect_notification_event, name='collect_notification_event')
    ]
    


動作確認 OneSingal から、WebPush を送信する

ブラウザを閉じた状態で OneSingnal から、WebPush を送信しないと動作確認できないのかと思いましたが、開いた状態でもブラウザの Network タブを確認すると、Webhook URl に POST リクエストが送信されていることが確認できます。

OneSingal の Webhook を使用して、 イベントを送信してみました。
POST データの受信ができれば、データ形式を変換して Google Analytics 以外の解析基盤にも送付できます。
MixPanel も導入したので、そちらに送付するコードもそのうち書いてみたいと思いました。
以上です。

コメント