🎥

オブザーバビリティツールの費用を抑えたい!rrwebで作るセッションリプレイ

2024/12/11に公開

この記事はCommune Advent Calendar 2024シリーズ1の11日目の記事です。

この記事について

オブザーバビリティツールにはユーザーの操作を視覚的に再現するセッションリプレイ機能があります。これによりトラブル解決の時間が短縮できます。また、ユーザーのブラウザで発生したエラーとそれを引き起こした操作を把握できるので、エラー対応の精度が向上します。
当然ですが、操作を記録するほどツールの利用料は上がります。

いくつかのオブザーバビリティツールはオープンソースのrrwebというライブラリをベースに使っているようです。[1][2]
https://www.rrweb.io/
これを使って有償ツールと同じようなことができるか試してみました。

書いたこと

  • rrwebの基本的な使い方
  • セッションリプレイ機能のミニマムな実装例

書いていないこと

  • 有償ツールとの機能比較や精緻なコスト比較

rrwebの使い方

以下のテスト用フォームを使って検証します。

ユーザーの操作を記録し再生してみます。

入力内容、マウスの軌跡や操作が視覚的に再現できます。
実装は以下のようにとても簡単です。
https://github.com/rrweb-io/rrweb/blob/master/docs/recipes/record-and-replay.md

入力内容をマスクする

OptionsmaskAllInputstrueにすると入力内容をマスクできます。記録時にマスクされるので、パスワードや個人情報などの機微な情報が記録データに含まれることを防ぎます。なお、一部の項目だけマスクすることもできるので、ユーザーサポートにとって入力内容が重要な場合も対応できそうです。

記録データ

構造

いつどこで何をしたかが記録されています。以下はフォームへa,b,cと一文字ずつ入力した時の記録データの一部です。

  {
       "type": 3,
       "data": {
           "source": 5,
           "text": "a",
           "isChecked": false,
           "id": 67
       },
       "timestamp": 1733667459665
   },
   {
       "type": 3,
       "data": {
           "source": 5,
           "text": "ab",
           "isChecked": false,
           "id": 67
       },
       "timestamp": 1733667460081
   },
   {
       "type": 3,
       "data": {
           "source": 5,
           "text": "abc",
           "isChecked": false,
           "id": 67
       },
       "timestamp": 1733667460454
   },

このようにtimestamp付きで操作が記録されるのでユーザーの操作を再生できます。
ちなみにマスクを有効にするとtextは*で記録されます。

    {
        "type": 3,
        "data": {
            "source": 5,
            "text": "****",
            "isChecked": false,
            "id": 84
        },
        "timestamp": 1733756116917
    },
    {
        "type": 3,
        "data": {
            "source": 5,
            "text": "*****",
            "isChecked": false,
            "id": 84
        },
        "timestamp": 1733756117113
    },
    {
        "type": 3,
        "data": {
            "source": 5,
            "text": "******",
            "isChecked": false,
            "id": 84
        },
        "timestamp": 1733756117284
    },

サイズ

検証用のフォームで数秒程度操作するだけで2万行ほど出力されました。一般的なアプリケーションはDOMの数がもっと多いのでサイズはかなり大きいと思います。ドキュメントには記録する操作を減らしたりデータを圧縮してサイズを減らす方法が載っています。

https://github.com/rrweb-io/rrweb/blob/master/docs/recipes/optimize-storage.md#sampling
記録する操作を減らす例です。

rrweb.record({
 emit(event) {},
 sampling: {
   // do not record mouse movement
   mousemove: false
   // do not record mouse interaction
   mouseInteraction: false
   // set the interval of scrolling event
   scroll: 150 // do not emit twice in 150ms
   // set the interval of media interaction event
   media: 800
   // set the timing of record input
   input: 'last' // When input multiple characters, only record the final input
 }
})

この設定では複数の文字入力は最後の入力時のみ記録され、マウスの軌跡や操作は記録されません。

セッションリプレイの活用例

ユーザーサポートチームが記録データをトラブルシューティングに活用するケースを想定してミニマムな環境を作ってみました。

構成と役割

Google Cloudのリソース

Firestore

ユーザーIDやタイムスタンプなど検索に使うためのメタデータを保存

Cloud Storage

ユーザーの記録データを保存

Cloud Run

APIやアプリケーションのデプロイ先

アプリケーション

Recording API

メタデータやユーザーの記録データをFirestoreとGCSへ保存するAPI

Search & Replay App

ユーザーの記録データを検索、再生するアプリケーション

過去の記録データは利用頻度が低いはずなので、FirestoreのTTLやCloud Storageのオブジェクトライフサイクルを使って一定期間を過ぎたら自動削除するのが良いと思います。
データ保存処理の信頼性を上げる場合はLoad BalancingやCloud Run jobsを使うのが良いかもしれないです。

Recording APIの実装

https://github.com/mongamae-nioh/simple-session-replay-app/tree/main/recording-api
ユーザーの操作を記録するAPIの実装です。ユーザーサポートが検索するので対象ユーザーや操作時間をメタデータとしてFirestoreへ保存、rrwebで作成される記録データをCloud Storageのバケットへ保存します。ユーザーIDなどユーザーが特定できる情報とあわせてAPIへ送りましょう。

Search & Replay Appの実装

https://github.com/mongamae-nioh/simple-session-replay-app/tree/main/session-replay
ユーザーIDやタイムスタンプで記録データを検索して再生するアプリケーションの実装です。

完成したアプリケーション

ユーザーIDと日時で検索し、セッションリプレイが見られるアプリができました。

コスト

以下の想定でざっくりGoogle Cloudの利用料を見積もりました。

  • ユーザーのアプリ滞在時間:5分
  • 1ユーザーあたりの記録データサイズ:500KB
  • 1日に保存される記録データの数:100万ファイル

今回のミニマム構成だと月額約$600でした。見積結果
記録する操作を減らしたり記録データを圧縮することでコストはもっと抑えられそうです。

ためしに、有償ツールで想定と同程度のボリュームで見積もると、二度見するくらいの料金になりましたが計算を間違えているかもしれないので書かないでおきます🙏

実運用する前に

以下の点を事前に検討する必要があります。

  • ユーザーへ操作を記録することの承諾を求める
  • ユーザーはいつでもオプトアウトできる仕組みを提供する
  • コスト最適化のため、エラー発生時のみ記録するなど記録条件を検討する

入力内容をマスクするとはいえ、操作記録に対するユーザーの違和感を払拭したり必要なデータだけ記録してコストを抑えることは事前に検討する必要があります。
なお、Sentryはエラーが発生したときに記録される再生のサンプルレート設定が可能[3][4]なので、有償のツールでコストを抑えたいならこちらを使うのも選択肢です。

さいごに、自前でセッションリプレイを実装するぞという気概を持った方はぜひrrwebを使ってみてください!

おまけ

ヒートマップはsimpleheatというライブラリで再現できました。
https://github.com/mourner/simpleheat


今回のフォームはプランの説明を不親切にしてどれを選択すれば良いか迷うケースを再現しました。迷った箇所がヒートマップで把握できるのでUX改善に活用できます。

ただ、このライブラリはほぼ更新されていないのが気になるのでもし他によいツールをご存知でしたらコメントで教えてください。Visual Heatmapはいつか試そうと思います。

脚注
  1. Datadog "The RUM Browser SDK is open source and leverages the open source rrweb project." ↩︎

  2. Sentry "A session replay is not a video recording. It's a video-like reproduction of a user session, built using the rrweb recording library" ↩︎

  3. replaysOnErrorSampleRatedオプションで可能です ↩︎

  4. 現在Datadogは柔軟なサンプリングレートをサポートしていないようです(ドキュメント↩︎

コミューン株式会社

Discussion