mixpanelにCloud Pub/Sub+Cloud Functionsを使ってイベントを送信してみた!

mixpanelとGoogle Cloud Pub/Sub+Cloud Functionsを連携させてみたよん。
2023.11.07

ミックスパネラーの國崎です。
今回はmixpanelにGoogleの【Cloud Pub/Sub】+【Cloud Functions】を使ってイベントデータを送信するということをやってみましたので、その辺の手順をお伝えします。

前提条件

  • Google Coludのプロジェクト作成済み
  • mixpanelのプロジェクト作成済み

やってみる

Cloud Pub/Subでトピックを作成する

まずGoogle Coludの左メニューからPub/Sub>トピックをクリック。
20231107_01

トピックを作成をクリック。
20231107_02

トピックIDを適当に決めます。
20231107_03

これでひとまずトピックは作成できました!

Cloud Functionのトリガーを関数に追加する

トピック作成後の画面上にある+CLOUD FUNCTIONSの関数をトリガーをクリック。
20231107_04

今回は第2世代で関数名を適当に決めます。
20231107_05

ソースコードの部分でランタイムはPython3.9、エントリポイントmainに変えてソースコードは以下を記述します。

▼main.py

import base64
from datetime import date
import gzip
import json
import random
import time
 
import requests
 
# Fill this out.
PROJECT_TOKEN = ""
 
 
def main(event, context):
    # Assumes the message consists of lines of JSON, each in Mixpanel's format
    msg = base64.b64decode(event["data"]).decode("utf-8")
    events = [json.loads(line) for line in msg.split("\n") if len(line) > 0]
 
    # Adjust the timestammps of each of the sample events so that
    # they appear recent. Note: this is just for this demo, do not
    # do this in production.
    for e in events:
        e["properties"]["time"] = int(date.today().strftime("%s"))
 
    # Send to Mixpanel
    tries = 0
    payload = gzip.compress(json.dumps(events).encode("utf-8"))
    while True:
        resp = requests.post(
            "https://api.mixpanel.com/import",
            params={"strict": "1"},
            auth=(PROJECT_TOKEN, ""),
            headers={"Content-Type": "application/json", "Content-Encoding": "gzip", "User-Agent": "mixpanel-pubsub"},
            data=payload,
        )
        if resp.status_code == 429 or resp.status_code >= 500:
            # Retryable errors, use exponential backoff
            tries += 1
            time.sleep(min(2 ** tries, 60) + random.randint(1, 5))
            continue
        else:
            break
 
    if resp.status_code != 200:
        # Log failures. In production, write to a dead-letter queue
        print({"message": "Import failed", "error": resp.json(), "severity": "WARN"})
    else:
        # Log success for debugging. Remove in production.
        print(
            {
                "message": "Import succeeded",
                "count": resp.json()["num_records_imported"],
                "severity": "INFO",
            }
        )

▼requirements.txt

requests

サンプルメッセージを配信してmixpanelで計測してみる

Cloud Pub/SubのUIからメッセージを送信してmixpanelに計測できるか確認してみます。
今回の以下の文を配信してみます。

{"event": "テストのイベント", "properties": {"distinct_id": "Sunrostern", "$insert_id": "28096095", "title": "Creator Giveaway for Publishing Notes", "url": "https://www.viewert.com", "score": "1", "time": 1628315585}}
{"event": "pubから送ったイベント", "properties": {"distinct_id": "feross", "$insert_id": "28059483", "title": "`at` Method for Relative Indexing", "url": "https://v8.dev/features/at-method", "score": "1", "time": 1628074042}}
{"event": "テストのイベント", "properties": {"distinct_id": "prostoalex", "$insert_id": "28069645", "title": "Home Classrooms Became a Necessity During Covid. Now They\u2019re a Selling Point", "url": "https://www.wsj.com/articles/home-classrooms-covid-real-estate-11628100036", "score": "1", "time": 1628135271}}
{"event": "pubから送ったイベント", "properties": {"distinct_id": "bingewave", "$insert_id": "28063639", "title": "Building a Live Streaming Movie App and Live TV Website \u2013 ReactJS", "url": "https://medium.com/bingewave/building-a-live-streaming-movie-app-live-tv-website-part-1-d0857aaac8ea", "score": "1", "time": 1628097439}}
{"event": "pubから送ったイベント", "properties": {"distinct_id": "jashkenas", "$insert_id": "28063632", "title": "Classic Research in Data Visualization", "url": "https://observablehq.com/@tophtucker/classic-research-in-data-visualization", "score": "1", "time": 1628097398}}
{"event": "テストのイベント", "properties": {"distinct_id": "ivandiblasi68", "$insert_id": "28091778", "title": "Il sistema sanitario irlandese colpito da un ransomware", "url": "https://www.kaspersky.it/blog/irish-health-service-ransomware/24680/", "score": "1", "time": 1628278340}}
{"event": "pubから送ったイベント", "properties": {"distinct_id": "akdav", "$insert_id": "28091776", "title": "DeFi and KYC", "url": "https://link.medium.com/bsn7z9Jmvib", "score": "1", "time": 1628278312}}
{"event": "pubから送ったイベント", "properties": {"distinct_id": "webscraping99", "$insert_id": "28085411", "title": "LinkedIn Profile Detail Scrapers \u2013 Ahmad Software Technologies", "url": "https://ahmadsoftwaretechnologies3.mypixieset.com/linkedin-profile-detail-scrapers/", "score": "1", "time": 1628246831}}
{"event": "テストのイベント", "properties": {"distinct_id": "Dorimoody", "$insert_id": "28064346", "title": "Our Children and Our Citations: Each One, Both Together", "url": "https://www.plough.com/en/topics/life/work/our-children-and-our-citations-each-one-both-together", "score": "1", "time": 1628101041}}
{"event": "pubから送ったイベント", "properties": {"distinct_id": "feross", "$insert_id": "28064342", "title": "The SEC Has Its Eye on Crypto", "url": "https://www.bloomberg.com/opinion/articles/2021-08-04/the-sec-has-its-eye-on-crypto", "score": "1", "time": 1628101019}}

mixpanelを確認してみると、きちんとイベントデータの計測を確認できてました。
20231107_07

ちなみにこの時点で計測ができない方はCloud Functionsのログを確認してみましょう。
問題なければログでImport secceededが表示されます。
20231107_09

サンプル配信で挙動が問題なければサブスクリプションの選択をし、PULLをクリックして自動化の連携は完了です。
20231107_08

今回の作業でよくわからん!と言う方がいたら、ほぼ同じことをしてますが以下の公式ドキュメントもご参考にどうぞ。

クラスメソッドが行っているmixpanelの支援

クラスメソッドではmixpanelをすでにお使いのお客様にも以下の支援サービスを提供しております。

  • PoC…検証環境提供
  • プランニング支援…KPI設計の支援/QA対応
  • 実装支援…開発の支援/SaaS連携支援
  • 伴走支援…定例など

mixpanelのKPI設計は以下記事でも紹介している専用の測定フレームワークを用いたプランニング支援をさせていただきます。

mixpanelの測定フレームワーク作り方のコツ!サンプルを例に解説!

また実装いただいた後の伴走支援では実際にお使いになられているお客様の課題感などをヒアリングさせていただき、ご要望に沿った内容での定例を設けさせていただき、成果につなげるための分析手法のご提案などをさせていただきます。

今回の記事を見てmixpanelについて詳細の話を聞きたい、興味を持ったという方はぜひぜひクラスメソッドまでお問い合わせください!!

クラスメソッドへのmixpanelお問い合わせ