はじめに
最近、PDFを単純にダウンロードさせるのではなく、
- ブラウザ上で読む
- どこまで読まれたかを見る
- どのページで離脱したかを見る
- 実際にアクティブだった時間を見る
という仕組みについて考える機会がありました。
きっかけは、PDFを共有用のWebページとして公開する PDF to Link という小さなSaaSを作ったことです。
最初は、
PDFをアップロード
↓
URLを発行
↓
共有
だけで十分だと思っていました。
しかし、実際にPDFを営業資料・提案書・Pitch Deck・ホワイトペーパーとして使うことを考えると、単純なView数だけでは足りません。
たとえば、20ページの提案書が100回開かれたとしても、
- 100人が最後まで読んだ
- 100人が1ページだけ見た
では意味が全く違います。
そこで今回は、PDFビューアのAnalyticsを設計するときに考えたポイントを整理します。
1. まず「PDFを共有する」の意味を分ける
PDFリンクには、大きく2種類あると考えています。
Raw PDF URL
たとえば、
https://example.com/files/report.pdf
のように、URLがそのままPDFファイルを指す形です。
これはかなりシンプルです。
向いている用途
- APIから直接取得したい
- iframeや別システムから参照したい
- 単純にダウンロードさせたい
-
.pdfで終わるURLが必要
一方で、人間がどう読んだかを細かく分析するには少し不向きです。
Viewer URL
もう一つは、
https://example.com/page/abc123
のようなWebページを作り、その中でPDFを表示する方式です。
こちらは、
Web Page
├─ PDF Viewer
├─ Analytics
├─ Password
├─ CTA
└─ Branding
のように、PDFの周辺にWeb機能を追加できます。
PDF to Linkもこちらの方式です。
公式サイトでも、発行されるURLはPDFそのものではなくブラウザ上のreading pageであり、PDF自体をHTMLへ変換するわけではないと説明しています。
この2つの違いは、PDF to URL の考え方としても重要です。
2. View数だけではほとんど分からない
一番簡単なAnalyticsはこれです。
viewer_open
つまり、
閲覧ページが開かれた
というイベントです。
これだけでも、
Views: 248
のような数字は作れます。
しかし、実際にはかなり情報量が少ないです。
100人が開いたとしても、
Page 1だけ見て閉じた人: 80人
最後まで読んだ人: 20人
かもしれません。
そこで次に必要になるのが、
- Page Reach
- Active Time
- Reading Depth
- Exit Page
です。
3. Active Timeをどう考えるか
最初に思いつく実装は、
const startedAt = Date.now()
window.addEventListener("beforeunload", () => {
const duration = Date.now() - startedAt
})
のようなものです。
ですが、これだとかなり問題があります。
ユーザーがPDFを開いたまま、
- 別タブへ移動
- 別アプリへ移動
- PCを放置
しても時間が増え続けます。
例えば、
PDFを開く
↓
30秒読む
↓
別タブで30分作業
↓
戻る
↓
閉じる
とすると、
Session Duration ≒ 30分30秒
になってしまいます。
実際の閲覧時間とはかなり違います。
4. visibilityState を使う
Webページで最低限見るべきなのは、
document.visibilityState
です。
例えば、
document.addEventListener("visibilitychange", () => {
if (document.visibilityState === "visible") {
// active start
} else {
// active stop
}
})
という考え方です。
これで、
visible
→ active
hidden
→ inactive
のように分けられます。
PDF to Linkでも現在、Active Timeは「documentがvisibleかつfocusedな状態」を基準として表示しています。公式ページにも Visible and focused と明記されています。
5. visibilityState だけでも完全ではない
ここが難しいところです。
たとえば、
ブラウザはactive
PDFページもvisible
でもユーザーは席を離れている
という場合があります。
この場合、visibility APIだけでは「読んでいる」と判断してしまいます。
そのため、実際にはユーザーイベントも組み合わせる方法があります。
例えば、
const activityEvents = [
"mousemove",
"keydown",
"scroll",
"touchstart",
"pointerdown"
]
などです。
概念的には、
Page Visible
AND
Window Focused
AND
Recently Active
ならActive Timeとして数える、という考え方です。
もちろんこれも完璧ではありません。
長い文章を静かに読んでいる人はマウスを動かさないこともあります。
つまり、
Active Time = Reading Time
ではありません。
正確には、
Active Time = 読んでいる可能性が比較的高い時間
くらいに考える方が安全です。
6. Reading Depthは何を意味する?
次にReading Depthです。
例えば20ページのPDFを考えます。
あるユーザーが、
1 → 2 → 3 → 4 → 5
と読んだ場合、
furthest_page = 5
とできます。
すると、
reading_depth = 5 / 20
= 25%
です。
かなり単純です。
7. しかしページジャンプがある
PDFビューアでは、ユーザーがいきなり、
Page 1 → Page 20
へジャンプする可能性があります。
この場合、
furthest_page = 20
だけを見ると、
100% reached
になります。
しかし、
全ページを読んだ
とは言えません。
PDF to Linkの現在のAnalyticsでも、この点について、
Based on the furthest page reached; jumping ahead can affect the curve.
と明示しています。
この説明はかなり大事だと思っています。
Analyticsは数字を出すだけでなく、
その数字が何を意味し、何を意味しないのか
を伝える必要があります。
8. 「Reached last page」を「Completed read」と呼ばない
ここも設計時に気をつけたいポイントです。
例えば、
Reached last page: 41%
という数字があったとしても、
Completed reading: 41%
とは言えません。
理由は単純で、
Page 1
↓
Page 32
とジャンプしただけかもしれないからです。
そのため、現在のPDF to Linkでも最終ページ到達率の近くに、
Not a completed read
という注意を入れています。
このようにAnalytics UIでは、
強い言葉を使いすぎない
ことも重要だと思います。
9. Page Engagementはどう取るか
Page Engagementでは、各ページについて例えば、
Page
Readers
Active Time
を持てます。
概念的なイベントは、
{
"session_id": "xxx",
"page": 4,
"event": "page_view",
"timestamp": 123456789
}
のようになります。
さらに、
{
"session_id": "xxx",
"page": 4,
"active_ms": 12000
}
のようにページ単位のactive timeを積算します。
集計すると、
Page 1 248 readers 26m02s
Page 2 235 readers 26m03s
Page 3 227 readers 26m29s
Page 4 220 readers 26m57s
のような形になります。
PDF to LinkのデモAnalyticsも現在この形式でページ別ReadersとActive Timeを表示しています。
10. Page Heatmapにすると分かりやすい
数字だけ並べても分かりづらいので、
1–4 ██████████
5–8 █████████
9–12 ████████
13–16 ███████
17–20 ██████
のようなHeatmapにすると、
どこから読者が減っているか
が視覚的に分かります。
ただし、ここでも注意が必要です。
読者数が減ったからといって、
そのページが悪い
とは限りません。
例えば価格表のページを見て目的を達成して離脱した可能性もあります。
Analyticsは原因を説明しません。
Analyticsが教えてくれるのは、
どこを調べるべきか
です。
11. Exit Pageは意外と難しい
次に、
どのページで離脱したか
です。
一見、
window.addEventListener("beforeunload", ...)
で取得できそうに見えます。
しかしWebでは、終了イベントは保証されません。
例えば、
- ブラウザ強制終了
- スマホでアプリをkill
- ネットワーク切断
- OSによる終了
- タブ破棄
などがあります。
そのため、
Exit Page = 必ず取れる
と考えるのは危険です。
12. Exit Unknown を残す
個人的には、
Page 1: 38 exits
Page 4: 25 exits
Page 8: 22 exits
Unknown: 52 sessions
のように、
unknown
を残す方が正直です。
現在のPDF to Linkのデモでも、
Exit page unknown
を別枠として表示しています。
これはデータ設計としてかなり大切だと思っています。
無理に100%分類すると、見た目は綺麗でもデータの意味が怪しくなります。
13. セッションデータはどう持つ?
簡略化すると、例えば以下のような構造が考えられます。
reading_session
---------------
id
document_id
visitor_id
started_at
last_seen_at
max_page
active_ms
exit_page
country
downloaded
cta_clicked
ページ単位は別テーブルです。
page_engagement
---------------
session_id
page_number
first_seen_at
last_seen_at
active_ms
view_count
すると、
Document
↓
Sessions
↓
Page Engagement
という関係になります。
14. VisitorとSessionは分ける
ここもよく混同しやすいです。
例えば同じ人が、
10:00 PDFを開く
15:00 もう一度開く
場合、
Visitors = 1
Sessions = 2
と考える方が自然です。
そのため、
Views
Visitors
Reading Sessions
は同じ数字にはなりません。
ブラウザidentifierなどを使えばある程度Visitorを推定できますが、
- Cookie削除
- Private Mode
- 別ブラウザ
- 別端末
などで同一人物判定は崩れます。
ここでも、
Unique Person
ではなく、
Browser Identifier
くらいの表現の方が安全です。
PDF to Linkでも現在Visitorsについて Browser identifiers と説明しています。
15. Country情報も100%正確ではない
Reader Locationも同じです。
IPベースで国を推定できても、
- VPN
- Proxy
- Corporate Network
- Cloud Network
などがあります。
したがって、
Country = User's actual physical location
ではありません。
分析用途では、
セッションに対して報告された国
程度の扱いが適切です。
現在のPDF to Linkでも、
Country reported for each reading session
という表現になっています。
16. DownloadとCTAは比較的分かりやすい
一方で、
Download Click
CTA Click
は比較的扱いやすいイベントです。
例えば、
track("download_clicked", {
documentId,
sessionId
})
や、
track("cta_clicked", {
documentId,
sessionId,
destination
})
のように記録できます。
営業資料なら、
PDFを開いた
↓
15ページまで到達
↓
CTAをクリック
という流れを見ることができます。
これは単なるファイルダウンロードよりも、かなり文脈のあるデータになります。
17. PDF Analyticsで「やらない方がいい表現」
今回考えていて、特に避けた方がいいと思ったのが以下です。
❌「ユーザーは3分読んだ」
実際には、
Active Time ≠ 精読時間
です。
❌「41%が最後まで読んだ」
正しくは、
41%が最終ページに到達した
です。
❌「Page 8で離脱した」
終了イベントが取れなければ、
Exit Unknown
もあります。
❌「186人が閲覧した」
Browser Identifierベースなら、
186 visitors
と、
186 human beings
は必ずしも同じではありません。
18. では何を表示するのがいいか
今のところ、自分は以下くらいが分かりやすいと思っています。
Views
Visitors
Avg. Active Time
Reached Last Page
Reading Depth
Page Engagement
Reader Locations
Exit Pages
Downloads
CTA Clicks
PDF to Linkでも現在この考え方に近いDashboardにしています。
19. PDF Viewer URLが向いているユースケース
このようなAnalyticsは、すべてのPDFに必要なわけではありません。
例えば、
請求書を自分に送る
だけなら不要です。
一方で、
Sales Proposal
相手がどこまで見たか
が気になります。
Pitch Deck
投資家が最後まで到達したか
が気になります。
White Paper
ダウンロード数ではなく、実際に読まれたか
が気になります。
Product Catalog
どのページがよく見られているか
が気になります。
こういうケースでは、Raw PDF URLよりViewer URLの方が適しています。
20. PDF共有方法を整理すると
個人的には以下のように分けています。
| 目的 | 向いている方法 |
|---|---|
| ファイル保管 | Google Drive / Dropbox |
| チーム共同作業 | Google Drive / OneDrive |
| APIで直接取得 | Raw PDF URL |
| 単純ダウンロード | Raw PDF URL |
| 読者行動の分析 | Viewer URL |
| Pitch Deck | Viewer URL |
| Proposal | Viewer URL |
| Branding | Viewer URL |
| Password | Viewer URL |
| CTA | Viewer URL |
どれか一つが優れているというより、
目的が違う
と考えています。
21. 実際にPDFをリンク化する流れ
一般ユーザー向けには、あまり複雑にしない方がよいと思っています。
基本的には、
1. PDFを選択
2. アップロード
3. Reading Pageを生成
4. URLをコピー
5. 必要ならPassword/Brandingを設定
6. Analyticsを見る
です。
具体的なユーザー向け手順は PDFをリンクにする方法 にまとめています。
22. 今後やりたいこと
PDF Analyticsを作っていると、次に欲しくなるのは、
Source × Reader Engagement
です。
例えば、
LinkedIn
Avg Depth: 72%
Email
Avg Depth: 48%
QR Code
Avg Depth: 31%
のように、
どこから来た人がよく読むのか
まで分かると面白いと思っています。
また、
Proposal opened
↓
Reader reached pricing page
↓
Slack / Webhook notification
のような通知も、営業用途では価値がありそうです。
ただ、機能を増やしすぎるとPDF共有ツールではなくCRMになってしまうので、その境界は悩んでいます。
まとめ
PDFビューアのAnalyticsを実装するとき、難しいのはイベントを取ることより、
そのイベントをどう解釈するか
だと思いました。
今回特に重要だと感じたのは以下です。
- Session DurationとActive Timeを分ける
- 最終ページ到達を「読了」と呼ばない
- Furthest Pageだけではページジャンプを区別できない
- Exit Pageは100%取得できない
- VisitorとHumanを同一視しない
- Analyticsは行動を示すが、意図までは分からない
つまり、
Analytics = Truth
ではなく、
Analytics = Behavioral Signals
です。
数字を増やすよりも、
その数字が何を意味するかを正しく説明する方が重要
だと感じています。
今回作っているPDF共有サービスはこちらです。
PDF to Link
https://pdf-to-link.com/
PDFを共有用のReading Pageとして公開し、Active Time、Reading Depth、Page Engagement、Exit Pageなどを確認できるようにしています。
同じようにPDFビューアやドキュメント分析機能を作ったことがある方がいれば、
- Active Timeをどう定義しているか
- Exit判定をどうしているか
- Reading Depth以外に見るべき指標があるか
あたりはぜひ知りたいです。