【体験談】直帰率94%を治そうとしてサイトを心肺停止させた話
GA4で直帰率94%を確認し、13個の回遊改善を自作CMSに実装。デプロイ直後に全記事ページが壊れた体験から、UX分析・改善設計・障害対応・環境整備の教訓を共有します。
コラム
kkm
Backend Engineer / AWS / Django
GA4で直帰率94%を確認し、13個の回遊改善を自作CMSに実装。デプロイ直後に全記事ページが壊れた体験から、UX分析・改善設計・障害対応・環境整備の教訓を共有します。
手術は成功したが、患者は一時心肺停止した
「手術は成功しました。ただ、患者は一時心肺停止しました」。医者にこう言われたら、成功とは何だったのかと問い詰めたくなります。
このサイトで、まさにそれをやりました。
記事ページの回遊率を上げるためにUI改善を13個入れました。施策の方向性は正しかったし、今もちゃんと動いています。ただ、デプロイした直後に全記事ページが表示不能になりました。JavaScriptのシンタックスエラーでインタラクティブな要素がすべて死に、hotfixを4連発で打って蘇生しています。
なぜこうなったのか。時間を巻き戻します。
94%が1記事で帰っていく
GA4を開いて最初に目に入ったのがこの数字でした。
| 指標 | モバイル | デスクトップ | 業界平均(ブログ) |
|---|---|---|---|
| 1記事離脱率 | 94.0% | 90.1% | 70〜90% |
| ページ/セッション | 1.09 | 1.19 | 1.2〜1.5 |
| 平均エンゲージメント | 21秒 | 30秒 | — |
| スクロール90%到達率 | 26% | 34% | — |
サイトを立ち上げて数週間の時点でのデータです。離脱率やエンゲージメント時間そのものは、開設間もないブログとしては標準的な範囲でした。記事を読んでくれている人はちゃんと読んでくれている。問題はそこではありません。
ページ/セッションが1.09。ほぼ全員が1記事だけ読んで帰っています。
流入元別に見ると傾向がはっきりします。SNS経由の流入が最も多いのですが、そのうち95.9%が1記事で離脱。検索経由だと12.8%、ダイレクトだと16.0%が2記事以上読んでいました。
面白いのは、2記事以上読んだ人の平均が4.4記事だったことです。一度回遊に入ると深く読んでくれる。ただ、その「一度」がほとんど発生していない。
最後まで読まないと他の記事に気づけない
なぜ回遊が起きないのか。改善前の記事ページを見直して、すぐにわかりました。
他の記事への導線がフッター付近にしかない。記事を最後までスクロールしないと、サイトに他にどんな記事があるのか一切わからない構造になっていました。
スクロール90%到達率がモバイルで26%ということは、74%の人は記事の途中で読むのをやめて帰っています。その人たちの画面には、他の記事の存在が一度も映っていません。
エンゲージメント時間の分布を見ると、モバイルの31%が5秒以内に離脱しています。タイトルか冒頭だけ見て去っていく層です。この人たちにフッターの関連記事が届くわけがない。
読者は「他の記事を読まない」のではなく「他の記事があることに気づけない」状態でした。回遊率が低い原因は記事の質ではなく、ページの構造にあった。
「邪魔にならない」を最優先にした13の施策
原因が構造にあるとわかったので、記事ページ内に回遊導線を追加することにしました。
設計で最も重視したのは「邪魔にならないこと」です。ポップアップやモーダルで「この記事も読んで!」と叫ぶサイト、あれは読んでいる側からすると本当にうるさい。「ここにこういう記事もありますよ」と、さりげなく提案するくらいがちょうどいい。
| 施策 | 配置 | 狙い |
|---|---|---|
| プログレスバー + 残り読了時間 | ヘッダー下 | あとどれくらいかわかると読み続けやすい |
| TL;DR 要点表示 | 記事冒頭 | 要点を先に見せて読む判断を助ける |
| 目次スムーススクロール | 目次 | 読みたいセクションへの移動を快適にする |
| 記事途中の関連記事カード | 2つ目のH2の前 | 途中で他の記事を認識してもらう |
| 関連記事の自動生成 | 記事下部 | カテゴリ最新 + 人気記事を自動で表示 |
| ニュースティッカー | ヘッダー直下 | 最新記事の存在を常に示す。閉じ可能 |
| サイドバー人気記事 | デスクトップ右側 | 目次の下に人気記事5件 |
| カテゴリタブバー | ヘッダー直下 | カテゴリ移動を常に可能に。Smart Hide対応 |
| モバイルボトムナビ | 画面下部固定 | 検索・ページ内検索・目次の3機能 |
| ページ内検索(表記揺れ対応) | ボトムナビから起動 | ひらがな/カタカナ/全角半角を吸収する検索 |
| API公開キャッシュ | サーバー設定 | 動的取得するAPIレスポンスをキャッシュ |
| APIフィールド拡充 | バックエンド | カード描画に必要な情報をAPIで返す |
回遊導線だけでなく、滞在時間の改善(プログレスバー、TL;DR)とモバイル操作性(ボトムナビ、ページ内検索)にも手を入れています。回遊導線をいくら増やしても、そもそも記事を読んでもらえなければ意味がないからです。
技術的にはCMSの公開APIで記事データを取得し、バニラJavaScriptで描画する構成です。フレームワークは使っていません。テンプレートに直接書いています。
一方で、見送った施策もあります。
| 見送った施策 | 理由 |
|---|---|
| フローティング「次に読む」ボタン | 差し込みカード・関連記事・ティッカーと重複してしつこい |
| ウェルカムバー(初回訪問者向け) | 3秒で消えるバーに効果があるとは思えない |
| パンくず強化 | 既存パンくず + カテゴリタブで十分 |
| 無限スクロール | 実装したが同じ記事が繰り返し表示されるバグが出て削除 |
無限スクロールは実装までしたのですが、同じ記事が何度もロードされる問題が出て削除しました。入れるべきでないものを見送る判断も、設計の一部です。全部入れればいいというものではない。
自分で検討して自分で壊せるのが自作CMSの醍醐味
WordPressであれば「関連記事プラグインを入れる」「人気記事ウィジェットを追加する」で済む話かもしれません。
ただ、「2つ目のH2の前に同カテゴリの記事カードを1枚だけ差し込む」とか「ニュースティッカーをsessionStorageで閉じた状態を記憶する」とか、そういう細かい制御はプラグインでは難しいことが多い。できたとしても、プラグイン同士の競合やアップデート時の動作保証に気を配る必要があります。
このサイトはPython製のCMSで構築しています。テンプレートもAPI設計も自分でコントロールできるので、GA4のデータを見て「ここにこれを出したい」と思ったら、その通りに実装できます。
裏を返せば、「自分が書いたコードで自分のサイトを壊せる」ということでもあります。WordPressなら本体が壊れることはまずありませんが、自作CMSではテンプレートの書き方ひとつで全ページが動かなくなります。
そしてデプロイボタンを押した
13の施策を1つのPRにまとめてmainブランチにマージし、本番にデプロイしました。ここから連鎖的に問題が起きます。
CSSが反映されない
デプロイ後、新しいUIのスタイルが一切適用されていませんでした。
このサイトでは、テンプレート内のCSS/JSを静的ファイルにビルドする仕組みを使っています。ビルドが走るタイミングはCMS管理画面からページを保存したときなのですが、今回はテンプレートへの直接変更なので、そのトリガーが発生しない。新しいTailwindクラスを書いたのにCSSが生成されていない状態でした。
デプロイ後に自動でビルドを走らせるよう設定しましたが、処理が遅すぎて即revert。代わりに全ページを再公開するコマンドを作って対応しています。
全記事ページのJavaScriptが壊れた
これが一番まずかった。
13の施策で大量のJavaScriptをテンプレートに追加したのですが、複数のscriptブロックに分けて書いていました。ビルド時にこれらが1つのscriptブロックに統合されるのですが、その過程で閉じタグが消失。JavaScriptのシンタックスエラーが発生し、全記事ページのインタラクティブな要素が動かなくなりました。
この修正にhotfixを4本投入しています。閉じタグの復元、scriptブロックの統合、コメントの除去と、問題を1つずつ潰していきました。
無限スクロールが同じ記事を繰り返す
記事末端で次の記事を自動ロードする機能も入れていたのですが、APIのオフセット指定が正しくなく、同じ記事が何度も表示される。修正を試みるよりも、他の回遊導線で十分と判断し、機能ごと削除しました。
| 問題 | 原因 | 対応 |
|---|---|---|
| CSSが反映されない | テンプレート変更ではCSS再ビルドが走らない | 全ページ再公開コマンドを作成 |
| JS全壊 | ビルド時のscript統合で閉じタグが消失 | hotfix 4本で復旧 |
| 無限スクロールが同じ記事を繰り返す | APIオフセットの実装不備 | 機能ごと削除 |
| 再公開コマンドが403エラー | CodeBuildロールにS3/CloudFront権限がない | IAMポリシー追加 |
1つのPRから、8つの後続PRが生まれました。うち4つがhotfix、2つがリリースPR、2つが周辺対応です。
dev環境は「ある」。使っていないだけだ
このサイトにはdev環境が存在します。Terraformで本番と同じ構成を定義してあり、いつでも立ち上げられる状態です。ただ、使っていません。
理由は運用コストです。AWSの各種リソースを常時稼働させると、個人サイトの規模には見合わない費用が発生します。サイト開設直後で記事数も少なく、テストもCIも通している。今回の問題はテストでは検出できない種類のもの(asset publisherのビルド時の挙動)だったので、dev環境があっても気づけたかどうかは微妙なところです。
この判断自体は、個人サイトの初期フェーズとしては妥当だったと今でも思います。
ただし、これが企業のサイトだったら話は別です。
全記事ページが表示不能になるということは、その間のトラフィック・広告収益・ユーザーの信頼がすべて失われるということです。「dev環境の運用コストが高いから本番で確認する」は通りません。staging環境でのデプロイ検証、CSS/JSビルドのCI統合、カナリアリリースなど、本番投入前に問題を検出する仕組みは必須です。
個人サイトで済むミスと、企業サイトで許されないミスの境界は、「壊れたときに誰が困るか」で決まります。自分だけなら即hotfixで済みますが、顧客がいるなら環境を整えてから手術してください。
今回の経験を経て、このサイトでもdev環境の運用を検討し始めています。記事数が増えれば影響範囲も広がるし、次にテンプレートに大きな変更を入れるときに同じことはしたくない。
手術は成功しました。患者は一時心肺停止しましたが、今は元気に動いています。次はもう少し慎重にメスを入れようと思います。