今回は弊社のスマートフォンアプリCrowdWorks for Worker iOS / Android の行動分析をKeen IOを使っていい感じにできるようになったお話を共有できればと思います。
背景
クラウドワークスアプリでは、ユーザー行動分析ツールとして初期の頃からFlurry Analyticsを採用していました。
2015年当時、無料の分析ツールとしてアプリに特化した点やその実績などから、Flurry Analyticsが一番良さそうということで採用しました。
使い勝手としてはGoogle Analyticsに似ていて、
- DAUの確認
- PageViewイベント、ボタンタップなどのactionイベントの利用状況確認
などをFlurry Analyticsを使って行っていました。
Flurry Analyticsはスマホアプリに特化している分なんとなく安心感のようなものもあったりして、2年以上使い続けていましたが、一方で、個人を特定したユーザ行動のトラッキングなどはできないという欠点も抱えていました。
転機
そんなとある日、Flurry Analyticsより一通のメールが...。
Your iPhone app, xxx, has just exceeded the allowed limit on the number of unique event names.You can manage the full list of event names for this app by clicking here. No additional event names will be recorded until action is taken to bring the number below the limit.
Flurry Analyticsで記録ができるPageViewやActionイベントの数には上限があって、 300を越えるイベントを記録することができない! ということらしい。 今後使い続けていくためには、重要ではないイベントを削除したりしていい感じにやりくりしていく必要が出てきました。
とはいえ、まだまだ発展途上であったクラウドワークスアプリ。今後ともどんどん機能を追加する予定はあります。当然のごとく、機能が追加されるにつれてとりたいイベントログはどんどん増えるわけです。 Flurry Analyticsのサポートに交渉して、イベント数の最大数を増やせないか調べましたが、それも無理そうでした。
以上のような経緯から、クラウドワークスではアプリのイベント計測に課題をかかえた状態となり、また普段Flurry Analyticsを使う上でできていなかったことを改善すべく、新たな分析ツールを探すこととなりました。
導入要件
同じ失敗をしないよう、新たな分析ツールの導入にあたっては要件を明確に定めました。
ユニークイベント数にしばられず使える
Flurry Analyticsはイベント数の上限:300 にかかっていました。 新たなツールでは、このような上限なく必要なイベントを必要なだけ計測できる必要があります。
ユーザーの行動が日次ベースでざっくり見られる
Flurry Analyticsで簡単に見ることができていた
- DAU
- 継続率
などのサマリは、新たなツールでも引き続き簡単に見られる必要があります。 (できれば日次でSlackに流せるとなおよい)
ユーザー個別で行動がトラッキングできる
Flurry Analyticsに無くて困っていた点です。
クラウドワークスでは、ユーザーさんから「〇〇の操作ができない」といったお問い合わせをいただくことがあります。 アプリでは、Webサーバーのように詳細なログが記録されていないため、どこの画面でどういったアクションをしたときに問題事象に出くわしてしまったのか、お問い合わせ内容だけでは判断がつかないことがしばしばあります。
お問い合わせされたユーザーさんのユーザーIDをもとに、行動トラッキングができれば、そのユーザーさんがどういう画面をみてどのようなアクションを行ったかを追うことができ、不具合の再現が大幅にしやすくなります。
行動分析をした結果をチーム内でURL共有できる
Flurry Analyticsでは、ユーザーフローを可視化するUser Pathsなどの機能を使って分析することがありますが、その結果をチームメンバーにURLで共有するのが難しいです。
チームのコミュニケーションはSlackでおこなっているため、できれば分析結果の共有の際にはURLをSlackに貼るだけでぱっと共有できることが望ましいです。
クラウドワークス上の既存のRDBの内容とテーブルをJOINして分析できる
「この仕事を契約したユーザが次にとっている行動、次に見ている仕事」などを抽出する際に、ユーザのメタデータを参照したくなることがあります。
Flurry Analyticsにはユーザの属性を設定する機能はありますが、アプリもしくはAPIを通してクラウドワークスのユーザデータベースの情報をFlurry Analytics側に同期する必要があるため、運用負荷が高く現実的ではありませんでした。 クラウドワークス側のRDBとINNER JOINして、ぱっとメタデータ情報で絞り込みなどができることが望ましいです。
他にどんなものが使える可能性があったか
Firebase Analytics
https://firebase.google.com/docs/analytics/?hl=ja
検討当時、AndroidアプリではすでにFirebase Analyticsを導入済みだったため、Keen IOを新規で導入するのに比べると導入コストが少し減らせるかも?ということで有力候補ではありました。
ただ、導入検討を進めていくと、Firebase Analyticsは、Flurry Analyticsと同様に、「ざっくりの傾向」をみるのには便利な一方で、個別のユーザーの行動をトラッキングしようとすると、BigQueryとの連携が必要になることがわかりました。
実際にFirebase AnalyticsをBigQuery連携させてみたものの、
などの理由から、Firebase Analytics+BigQueryは導入見送りとしました。
そんなとき・・・
Web側でKeen IOが採用された!
ある日のこと、Web側のチームより「ヘイユー!アプリでKeen IO使ってみない?」と話があり、次の日わたしはアプリへのKeen IOの導入に取りかかりました。
Web側でKeen IOが採用された理由は以下をご確認いただければと思います。
アプリ観点では、上記リンク先でも述べられているようにiOS/AndroidのSDKが存在することや、行動ログデータは最終的に弊社Redshiftへ連携しRedashから扱えるようになるため、導入要件として考えていたことがほぼ全て満たされるもので、これを採用しない手はありませんでした。
iOS/Androidによる行動ログ計測
Keen IOのiOS SDKはこちらを、Android SDKはこちらをご確認ください。 またKeen IOのドキュメントはこちらをご確認ください。
Event Collection
Keen IOでは、Event Collectionというイベントをとりまとめるための種別があり、アプリでどういうEvent Collectionにするかをまず決めました。
たとえばWeb側ではWeb Auto-Collectionという自動でいい感じにページの表示などを計測してくれる仕組みがあり、それを利用すると
- pageviews -- ページビュー
- clicks -- クリック (ボタンやリンクだけでなくすべてのクリック)
- form_submissions -- フォーム送信 (送信された内容も含む)
といったEvent Collectionが作られ、それぞれにページの表示イベントなどを自動でとりまとめて記録されますのでアプリでも参考に以下のように分けてみました。
- ios_views -- iOSアプリでの画面表示イベント
- android_views -- Androidアプリでの画面表示イベント
- ios_actions -- iOSアプリでのボタンタップなどのアクションイベント
- android_actions -- Androidアプリでのボタンタップなどのアクションイベント
ちなみに、弊社ではこのEvent Collectionごとに最終的にはRedshiftにテーブルを作ってデータ連携するようにしています。 この分け方については実際に運用してみてRedashからクエリを叩く時にテーブルが別れていて面倒、などチーム内でも議論がありますので、今後見直す可能性があります。
アプリからはこのviewsイベントおよびactionsイベントの計測については以下のようなメソッドを用意しています。 以降、Swiftを例に説明します。
/// viewイベント計測 static func addViewEvent(name: String, params: [String: Any]?) { let event: [String: Any] = [ "unixtime": Int(Date().timeIntervalSince1970), "session_uuid": sessionUuid(), "view": [ "name": name, "params": params ?? [:] ] ] do { try KeenClient.shared().addEvent(event, toEventCollection: "ios_views") } catch _ { // do something } } /// actionイベント計測 static func addActionEvent(name: String, params: [String: Any]?) { let event: [String: Any] = [ "unixtime": Int(Date().timeIntervalSince1970), "session_uuid": sessionUuid(), "action": [ "name": name, "params": params ?? [:] ] ] do { try KeenClient.shared().addEvent(event, toEventCollection: "ios_actions") } catch _ { // do something } }
両メソッドとも引数にname
を指定しますが、ここに画面名やアクション名を渡すようにします。
params
には必要に応じてパラメータを渡して同時に計測するようにしています。
また、unixtime
やsession_uuid
も記録しています。
unixtime
については端末時刻を単純にエポック秒で送付しているのみですが、Keen IO側の受信時間ではなく端末で実際にいつイベントが発生したのかを送るようにしています。ただこれは端末時間がずれていたりする懸念があります。
session_uuid
に関してはWebのセッションのようなユーザーの操作単位として、30分間操作の間隔があかない操作が続く間は1セッションとして同一IDをふって、そのIDで絞り込むことによりユーザーの一連の操作がどういったものかを把握できるようにしています。
例えば画面表示のイベントについては、viewDidLoad:
などのタイミングで上記メソッドを呼んでやるとKeen IOに対してイベントを飛ばすこととなります。
上記のメソッドなどKeen IOに関するコードは KeenIOService
というクラスに処理をまとめているためそのクラスに対するメソッド呼び出しになっています。
override func viewDidLoad() { super.viewDidLoad() KeenIOService.addViewEvent(name: "Hogehoge", params: ["jobOfferId" : 100]) }
Enrichment addon
上記のイベント処理だけでは単純にイベント名やそのパラメータの情報くらいしかないため、もっと情報を追加したいと思います。 Web側ではWeb Auto-Collectionという自動で色々な情報を収集してくれる仕組みがあり、さらにIPアドレスからGeo情報を出してくれたりと色々してくれますが、アプリで同様の機能がないため独自に計測するイベント決める必要があります。
Keen IOにはそのIPアドレスからGeo情報を出してくれたりする便利な機能をEnrichment addonとして個別に提供してくれています。
アプリからKeen IOに送るイベントに以下のように
KeenClient.shared().globalPropertiesDictionary = [ "ip_address": "${keen.ip}", "keen": [ "addons": [ [ "name": "keen:ip_to_geo", "input": [ "ip": "ip_address" ], "output": "geo" ], ... ], ... ]
addons
に keen:ip_to_geo
の指定を追加してやると
"geo": { "province": "Tokyo", "city": "Tokyo", "country": "Japan", "coordinates": [ 139.7677, 35.6427 ], "postal_code": "100-0001", "country_code": "JP", "continent": "Asia" },
このようにイベントに対して位置情報をあわせて記録してくれるようになります。
Enrichment addonには他にも keen:date_time_parser
を指定するとKeen IOがイベントを受信した時刻を出力してくれるものがあり、アプリで使えそうでしたのでその指定も追加しました。
Global properties
Enrichment addonで取れないものはアプリで独自にイベント情報のプロパティに追加する必要があります。 たとえば、ユーザー情報、デバイス情報などです。
こちらも以下のように追加します。 DeviceHelperなどは弊社で作成したヘルパ用クラスです。
KeenClient.shared().globalPropertiesDictionary = [ ... "user": [ "logged_in": isLoggedIn, // ログイン状態 "user_id": userId, // ユーザーID ], "device": [ "carrier_name": DeviceHelper.carrierName(), "os": "ios", "os_version": AppVersionHelper.systemVersion, "app_version": AppVersionHelper.versionName, "build_version": AppVersionHelper.buildVersion, "locale": Locale.current.identifier, "model": DeviceHelper.modelName(), "device_id": KeychainManager.sharedInstance.deviceId, ], "tracking_metadata": [ "version": trackingVersion, ], ]
ちなみに、tracking_metadata/version
というものも計測していますが、アプリから送信するこのJSON構造はアプリエンハンスにしたがって変わりうるものであるため、構造の変化に対応できるようにversion付けするようにしたものです。
この結果、最終的にアプリから送るイベントのJSON構造は次のようなものになりました。
{ "tracking_metadata": { "version": "2018021900" }, "keen": { "timestamp": "2018-04-26T08:20:58.333Z", "created_at": "2018-04-26T08:20:57.829Z", "id": "1234567890abc" }, "geo": { "province": "Tokyo", "city": "Tokyo", "country": "Japan", "coordinates": [ 139.692101, 35.689634 ], "postal_code": "163-8001", "country_code": "JP", "continent": "Asia" }, "unixtime": 1524730858, "device": { "locale": "ja_JP", "os_version": "7.0", "build_version": 2018042000, "carrier_name": "NTT DOCOMO", "app_version": "2.28.3", "os": "android", "model": "SH-02J", "device_id": "12345678-1234-1234-1234-1234567890ab" }, "user": { "logged_in": true, "user_id": 1234567890 }, "session_uuid": "87654321-4321-4321-4321-ba0987654321", "time": { "utc": { "millisecond": 333, "day_of_week_string": "Thursday", "hour": 17, "timezone_offset": 32400000, "day_of_month": 26, "day_of_week": 4, "day_of_year": 116, "second": 58, "week": 17, "year": 2018, "month": 4, "minute": 20, "quarter_of_year": 2 } }, "action": { "params": { "row": "0", "relatedJobOfferType": "otherViewing" }, "name": "JobOffer" }, "ip_address": "10.0.0.1" }
Redashで収集したデータをSQLで分析
こうして集めたKeen IOのデータは弊社で管理するRedshiftにデータ連携させ、最終的にRedashでテーブルとして参照できるようになっています。
この結果、Redashでこんな感じで、アプリの行動ログを眺めることができました!
チーム内全員でアプリの行動分析
せっかく行動ログの分析がいい感じにできるようになりましたので、最近アプリ開発チーム内でRedashからKeen IOで収集したデータを分析してみるハンズオンを行い、チームメンバー全員でアプリ内の行動分析を行えるようになりました。
このハンズオンもチーム内では好評で、「自分でも分析できるようになれた!」と喜びの声があがっています。 今後積極的に行動分析からサービスの改善に繋げていければと思います。
結果
これまで説明してきたようにKeen IOを導入してみて、いくつか見えてきたことがありますので、良かった点や課題となっている点をまとめてみたいと思います。
良かったこと
これまでの普段の分析については、RDBにたまったお仕事や支払いの情報などをRedshiftに連携しそれをRedashでSQLにて分析していました。 それがアプリの行動ログについてもKeen IOからRedash連携ができるので、行動分析がいつもの分析と遜色なく行うことができるようになりました。 SQLを使って分析する人が多い弊社において、この点は非常に大きなポイントでした。 その結果、ユーザーさんの困っていること、置かれている現状などを詳細に把握できるようになってきており、解決へのアクションにつなげられるようになりました。
課題、反省点
テーブルの分け方は事前に確認することをおすすめします。 今回、私たちはviewsとactionsでイベントを分けてデータ連携しましたが、分析の内容によってはviewsとactionsを毎回JOINするという工数が発生してしまいました。 しかもiOS, Androidでも分かれているので4つのテーブルを必ず毎回JOINするなど面倒です。 Event Collectionはviews/actionsで分けているのは良いかもしれませんが、Redshiftへデータ連携する場合には、views/actionsを一つのテーブルにしてtypeなどのカラムで判定してやるのが良かったかもしれません。
また、ここでは詳しく述べませんが、Keen IOからRedshiftに連携するまでにデータの加工などを行っています。また扱うデータの量が大きすぎて、うまく扱うためには色々な工夫が必要で大変でした。 機会があればこちらについても別途ご紹介できればと思います。
最後に
いかがでしたでしょうか。 導入にあたっての準備がいくつか必要とはいえ、Keen IOの導入によって分析の幅は圧倒的に広がりますので、ぜひお勧めしたいと思います。
現在、クラウドワークス では積極的にアプリ開発に関わるエンジニアを募集しています。 話を聞いてみたい、などでも構いませんので、お気軽に遊びにきてくださいねー。 www.wantedly.com