顔文字のサイトの検索を改善しようとして、まず「利用者は何を検索して、何が空振りしているのか」を見ようとした。GA4 の拡張計測で「サイト内検索」を有効にしてある。ここに溜まっているはずだ。

0件だった。 60日分で、1件も無い。

なぜ効かないのか

GA4 の拡張計測は、ページ読み込み時の URL に ?q=(既定の検索パラメータ)があるかを見て view_search_results を発火する。それだけだ。

うちのサイト内検索は、どれもクライアントサイドで動く。入力のたびに JavaScript が結果を描き替え、history.replaceState で URL を書き換えるだけで、ページ読み込みが起きない。だから拡張計測は一度も発火しない。検索語は1つも拾われない。

4サイトで実測した(過去60日)。

サイトview_search_results の発火中身
kaomoji0ページ内で打たれた検索語は1件も無い
emoji10すべて ?q= 付きで直接開かれた分。ページ内の検索ではない
shiritori0同上
maps0同上

emoji の10件は、外部からリンクで ?q= 付きの URL を開いたものだ。サイト内で検索窓に打った語は、4サイト合わせてゼロだった。

拡張計測の「サイト内検索」は、フォームを送信してページが遷移する昔ながらの検索を想定している。SPA 的な検索には、設定を有効にしても何も起きない。エラーも出ない。数字が0のまま、静かに何も起きない。

読み違えの罠: searchTerm を単独で引かない

調べている途中で、一度読み違えた。

GA4 の探索で searchTerm をディメンションにして件数を出すと、searchTerm を持たないイベント(page_view など)が全部「(空)」の1行に合算される。この行の件数は数千になる。「イベントは来ているのに語が取れていない」ように見える。

違う。それは検索イベントではなく、検索と無関係なイベントの合計だ。eventName = view_search_results で絞ってから数える。 絞ったら0だった。

自分で送る

拡張計測に頼るのをやめて、検索が確定したところで自分で送ることにした。

// 検索が確定したとき
gtag("event", "view_search_results", {
  search_term: q,
  result_count: results.length,
  matched_by: how,   // word / synonym
});
if (results.length === 0) {
  gtag("event", "search_zero_result", { search_term: q });
}

要点が3つある。

1. 打鍵ごとに送らない。 「あ」「あり」「ありが」… と前方一致で毎回送ると、語の統計にならない。1.5秒の静止を待ってから送る。同じ語はページ内で1回だけ。

2. 0件のときは別のイベント名で送る。 search_zero_result という名前にしておけば、イベント名だけで空振り語を絞れる。result_count = 0 でフィルタするより、レポートで扱いやすい。

3. 件数も一緒に送る。 0件だけでなく「出たが少ない」も改善の材料になる。

gtag が居るときだけ静かに送る。本番ホスト名でしか読み込まれないので、dev や E2E からは発火しない。

サイトごとに何を送るか

サイト計測する面送るもの
kaomoji検索ページsearch_term / result_count / category_hits / matched_by
emoji検索ページsearch_term / result_count
shiritori「相手の言葉」の入力search_term / result_count / outcome
mapsジャンルページのパネル検索search_term / result_count / genre

送るものはサイトごとに違う。読みどころも違う。

  • shiritori の outcome は words / no_words / no_reading / no_tail / ends_with_n。このうち no_reading(辞書に読みが無い)で空振りした語は、辞書に足す語そのものだ。空振りの内訳が、そのまま作業リストになる
  • maps の0件は「データが無い」ではなく「いま見ている範囲に無い」。genre と併せて読まないと意味が取れない
  • kaomoji の matched_by は word / synonym。synonym は意味辞書で架け替えて出したもので、辞書が効いているかがここで分かる

推測で作った辞書225件

ここが、この件で一番書き残したいところだ。

kaomoji の検索には、意味辞書がある。「うれしい」で検索したら「喜び」の顔文字も出るように、語を架け替える辞書だ。225エントリある。

これを書いたとき、実データは1件も無かった。利用者が何を検索しているか、何が空振りしているか、何も分からない状態で、「たぶんこういう語で探すだろう」と推測で225件書いた。

いま振り返ると、順序が逆だった。推測で辞書や索引を作る前に、まず溜まった空振り語を見る。 数週間ぶんの search_zero_result が出てから、それを見て辞書を書くのが正しい順序で、225件の中に本当に必要なものがどれだけあるかは、これから分かる。

計測が無いと、作ったものが効いているかも分からない。効いていないことにも気づけない。計測は改善の前に入れるもので、改善のあとに入れるものではなかった。

まとめ

  • GA4 の拡張計測「サイト内検索」は、ページ読み込み時の ?q= しか見ない。 クライアントサイドの検索では一度も発火しない。エラーも出ない
  • searchTerm を単独ディメンションで引くと、別イベントが「(空)」に合算される。eventName で絞ってから数える
  • 自分で送る。1.5秒の静止を待ち、同じ語は1回だけ、0件は別のイベント名で
  • 送るものはサイトごとに違う。空振りの内訳(outcome)が作業リストになる形が一番役に立つ
  • 推測で辞書を作る前に、空振り語を見る。 計測は改善の前に入れる

225件の辞書を書く前に、この記事の最初の1段落分の調査をしていれば、順序は違っていた。