Slide 1

Slide 1 text

Web技術を駆使して ユーザーの画面を「録画」する @yukukotani 2024/08/24 - フロントエンドカンファレンス北海道

Slide 2

Slide 2 text

自己紹介 小谷 優空 - @yukukotani ・VP of Technology @ Ubie, Inc. ・Maintainer of KumaUI ・Student @ Univ. Tsukuba

Slide 3

Slide 3 text

うまいスープカレー

Slide 4

Slide 4 text

今日の趣旨 Webにおける画面録画(セッションリプレイ)の仕組みを覗いてみよう! 明日から業務に役立つ話はきっとありません Web技術にワクワクしましょう

Slide 5

Slide 5 text

Session Replay とは Webアプリにおけるユーザーの画面操作をそのまま視覚的に再生できるツー" 顧客インサイト抽E エラー分 ユーザーサポート

Slide 6

Slide 6 text

Demo

Slide 7

Slide 7 text

なぜ自作するのか

Slide 8

Slide 8 text

なぜ自作するのか toCプロダクトで全件録画すると課金爆発 $ B 月間100万セッションとすると$2,000G B サンプリングできるけど、ユーザーサポートとかには全件録画が欲しい →自作により、開発人件費を考慮しないコストは10%程度に着地

Slide 9

Slide 9 text

なぜ自作するのか 自社でデータを持ちたˆ x 完全無料で使えるSaaSもあるが(Clarity)、学習利用されQ x もちろん匿名化されるとはいえ、自然言語入力とかも使われるとやや怖ˆ x セルフホスト版もあるが、運用コストが高# x 機能がリッチすぎてミドルウェアが多く大€ x 結果的にお金もそれなりにかかる

Slide 10

Slide 10 text

仕組み概観

Slide 11

Slide 11 text

基本的なアイデア 画面を動画ファイルとして録画できるWeb APIはない・・・ →DOM全体を clone して画面に反映すれば完全再現できるじゃん!

Slide 12

Slide 12 text

基本的なアイデア もちろん様々な問題があるので工夫が必W F ブラウザを跨いだ再生は F DOMに反映されない画面操作は F DOMが変わるたびに全更新してたら重くない?

Slide 13

Slide 13 text

録画 初期描画のDOMとその後の変化を、タイムスタンプと共にイベントとして記録 逐次イベント記録 Browser

Slide 14

Slide 14 text

再生 sandbox化したiframeによって、Viewer自体とは独立した環境を用意

Slide 15

Slide 15 text

再生 タイムスタンプに合わせて実際にイベントをiframeに反映していく DOM描画 スクロール 文字入力 DOM更新 iframe

Slide 16

Slide 16 text

アーキテクチャ ・検索系メタデータはDB、イベントデータはオブジェクトストレージ(GCS) ・GCSにはTTLを設定(録画の有効期限)

Slide 17

Slide 17 text

イベント詳解

Slide 18

Slide 18 text

初期描画イベント

Slide 19

Slide 19 text

初期描画イベント:録画 DOM全体をシリアライズして記$ 木構' 各要素にユニークIDを振る 要素ごとのユニークID

Slide 20

Slide 20 text

初期描画イベント:録画 色々なことを考慮してシリアライズすy p 再生時はwindowのlocationが異なy p → 画像のsrcなどは相対パスから絶対パスに変E p 再生時にassetが変わってる・消えてる可能性があy p → linkのスタイルシートはDOM内にインラインI p ユーザーが任意の要素を差し込めてしま5 p → 再生側にXSSされないようscriptタグは除却

Slide 21

Slide 21 text

初期描画イベント:再生 デシリアライズした要素をiframeに描画 IDと要素のマッピングは記憶しておく

Slide 22

Slide 22 text

文字入力イベント

Slide 23

Slide 23 text

文字入力イベント:録画 ユーザーの入力は inputイベントを拾って記録する

Slide 24

Slide 24 text

文字入力イベント:録画 機械的な入力(リセットボタン等)はinputイベントが発火しない!

Slide 25

Slide 25 text

文字入力イベント:録画 https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

Slide 26

Slide 26 text

文字入力イベント:録画 input要素のPropertyDescriptorをオーバーライドして補足する オリジナルの処理に加えて イベント記録処理を追加 オリジナルの処理に加えて イベント記録処理を追加 オリジナルのPropertyDescriptorを取り出しておく

Slide 27

Slide 27 text

setTimeoutに包むことで 次のイベントループに逃す 文字入力イベント:録画 (小ネタ)本来のプロパティ更新をブロッキングするとパフォーマンス低下する →次のイベントループに逃して非同期にイベント記録処理

Slide 28

Slide 28 text

文字入力イベント:録画 属性からセンシティブな入力を判定し、イベントを記録しないように 再生側ではなく録画側で弾いているため、データ送信・保持は一切ない

Slide 29

Slide 29 text

文字入力イベント:再生 初期描画時に振ったユニークIDから 要素を探して更新

Slide 30

Slide 30 text

DOM更新イベント

Slide 31

Slide 31 text

DOM更新イベント https://developer.mozilla.org/ja/docs/Web/API/MutationObserver

Slide 32

Slide 32 text

DOM更新イベント:録画 MutationObserverでdocument監% 5 要素の追加・削 5 属性の変 5 文字ノードの変更 DOM更新部分の親要素 追加した文字ノード 削除したフォーム要素

Slide 33

Slide 33 text

DOM更新イベント:録画 変更内容をイベントとして記録 初期描画時に振った ユニークIDで参照 新規ノードにも ユニークIDを降る

Slide 34

Slide 34 text

DOM更新イベント:再生 更新があった部分のみに差分を反映 仮想DOMの差分更新と似ている ユニークIDから更新対象を取得 追加するノードは新規作成

Slide 35

Slide 35 text

他にもたくさん考えることが 時間の都合で割愛' d iframQ d ShadowDOW d document.adoptedStyleSheets d canvas d 画面リサイズ・スクロール・マウス移0 d Web Components (Custom Elements d イベントのスロットリング

Slide 36

Slide 36 text

自作しなくても便利OSSがあります プリミティブな録画&再生の仕組みを提供してくれるライブラリ SentryやPostHogでも使われている ※イベントの保存とかはスコープ外

Slide 37

Slide 37 text

保存周りも近日中にOSSにします サクッと自社クラウドに載せて動かせるやつを出すので乞うご期待

Slide 38

Slide 38 text

ありがとうございました