署名付きエクスチェンジを測定して最適化し、最大限に改善する方法
Signed Exchange(SXG)は、ページの読み込み速度を改善する手段であり、主に Largest Contentful Paint(LCP)です。参照元サイト(現在は Google 検索)がページにリンクを設定する場合、ユーザーがリンクをクリックする前に、そのページをブラウザ キャッシュにプリフェッチできます。
プリフェッチ時に、ページのレンダリングに必要なクリティカル パスでネットワークを必要としないウェブページを作成できます。4G 接続では、このページの読み込み時間が2.8 秒から 0.9 秒に短縮されます(残りの 0.9 秒は主に CPU 使用量によるものです)。
現在 SXG を公開しているほとんどのユーザーは、Cloudflare の使いやすい自動 Signed Exchange(ASX)機能を使用しています(ただし、オープンソースのオプションもあります)。
多くの場合、チェックボックスをオンにすれば、上記のような大幅な改善が可能です。パイプラインの各ステージでこれらの SXG が意図したとおりに動作するようにし、プリフェッチを最大限に活用できるようにページを最適化するには、さらにいくつかの手順が必要になることがあります。
Cloudflare のリリースから数か月間、私はさまざまな フォーラムで質問を読み、回答してきました。また、SXG デプロイメントを最大限に活用できるようにサイトにアドバイスする方法を学びました。この投稿では、私がこれまでに提供してきたアドバイスをまとめています。以下を行うための手順を説明します。
- WebPageTest を使用して SXG のパフォーマンスを分析します。
- 分析ステップで機能していないことが示された場合は、SXG パイプラインをデバッグします。
- 最適な
max-age
の設定や、レンダリング ブロック サブリソースのプリロードなど、SXG プリフェッチ用にページを最適化します。 - 適切なテストグループとコントロール グループを選択して、Google アナリティクスを使用して SXG の改善を測定します。
はじめに
SXG は、URL、一連の HTTP レスポンス ヘッダー、レスポンスの本文を含むファイルで、これらはすべて Web PKI 証明書によって暗号署名されています。ブラウザが SXG を読み込むと、次のすべてが検証されます。
- SXG の有効期限が切れていない。
- 署名は、URL、ヘッダー、本文、証明書と照合されます。
- 証明書が有効で、URL と一致している。
検証に失敗すると、ブラウザは SXG を破棄し、代わりに署名付き URL を取得します。検証に成功すると、ブラウザは署名付きのレスポンスを読み込み、署名付き URL から直接返されたものとして扱います。これにより、署名後に期限切れになったり変更されたりしていない限り、任意のサーバーに SXG を再ホストできます。
Google 検索の場合、SXG により検索結果のページのプリフェッチが可能になります。SXG をサポートするページの場合、Google 検索は webpkgcache.com でホストされているページのキャッシュ コピーをプリフェッチできます。ブラウザは元の署名付き URL を尊重するため、これらの webpkgcache.com の URL はページの表示や動作には影響しません。プリフェッチを使用すると、ページの読み込みが大幅に速くなります。
分析
SXG のメリットを確認するには、まずラボツールを使用して、再現可能な条件で SXG のパフォーマンスを分析します。WebPageTest を使用して、SXG プリフェッチありとなしでのウォーターフォール(および LCP)を比較できます。
次のように、SXG のないテストを生成します。
- WebPageTest にアクセスしてログインします。ログインすると、テスト履歴が保存され、後で簡単に比較できます。
- テストする URL を入力します。
- [詳細設定] に移動します。(SXG テストには高度な構成が必要になるため、ここで使用するとテスト オプションが同じになります)。
- [Test Settings] タブで、[Connection] を [4G] に設定して、[Number of Tests to Run] を 7 にすると便利です。
- [テストを開始] をクリックします。
上記と同じ手順で SXG を使用してテストを生成します。ただし、[テストを開始] をクリックする前に、[スクリプト] タブに移動し、次の WebPageTest スクリプトを貼り付け、指示に沿って 2 つの navigate
URL を変更します。
// Disable log collection for the first step. We only want the waterfall for the target navigation.
logData 0
// Visit a search result page that includes your page.
navigate https://google.com/search?q=site%3Asigned-exchange-testing.dev+image
// Wait for the prefetch to succeed.
sleep 10
// Re-enable log collection.
logData 1
// Navigate to the prefetched SXG on the Google SXG Cache.
navigate https://signed--exchange--testing-dev.webpkgcache.com/doc/-/s/signed-exchange-testing.dev/sxgs/valid-image-subresource.html
最初の navigate
URL で、ページがまだ Google 検索の検索結果に表示されていない場合は、このプリフェッチ ページを使用して、この目的の疑似検索結果ページを生成できます。
2 番目の navigate
URL を特定するには、Chrome 拡張機能の SXG Validator を使用してページにアクセスし、拡張機能アイコンをクリックしてキャッシュ URL を確認します。
テストが完了したら、[テスト履歴] に移動し、2 つのテストを選択して [比較] をクリックします。
比較 URL に &medianMetric=LCP
を追加して、WebPageTest が比較の両側で LCP の中央値が最も高い実行を選択するようにします。(デフォルトは、速度インデックスによる中央値です)。
ウォーターフォールを比較するには、[ウォーターフォールの不透明度] セクションを開き、スライダーをドラッグします。動画を表示するには、[フィルムストリップの設定を調整] をクリックし、ダイアログ内で下にスクロールして [動画を表示] をクリックします。
SXG プリフェッチが成功すると、「with SXG」ウォーターフォールに HTML の行が含まれず、サブリソースの取得がより早く開始されます。たとえば、ここで「変更前」と「変更後」を比較します。
デバッグ
WebPageTest の表示で、SXG がプリフェッチされていることが示されている場合は、パイプラインのすべてのステップで成功しています。最適化のセクションに進んで、LCP をさらに改善する方法を確認できます。エラーがパイプラインのどの部分で発生し、なぜ発生したのかを特定する必要があります。方法については、以下をご覧ください。
公開
ページが SXG として生成されていることを確認します。そのためには、クローラーのふりをする必要があるのです。最も簡単な方法は、SXG Validator Chrome 拡張機能を使用することです。
この拡張機能は、SXG バージョンを優先することを示す Accept
リクエスト ヘッダーを使用して、現在の URL を取得します。[送信元] の横にチェックマーク(✅)が表示されている場合は、SXG が返されたことを意味します。インデックス処理のセクションに進むことができます。
バツ印(❌)が表示される場合は、SXG が返されなかったことを意味します。
Cloudflare ASX が有効になっている場合、クロスマーク(❌)が表示される最も一般的な理由は、キャッシュ制御レスポンス ヘッダーが原因でキャッシュに保存できないためです。ASX は、次の名前のヘッダーを参照します。
Cache-Control
CDN-Cache-Control
Surrogate-Control
Cloudflare-CDN-Cache-Control
これらのヘッダーのいずれかに次のヘッダー値が含まれている場合、SXG は生成されません。
private
no-store
no-cache
max-age
は 120 未満(120 以上のs-maxage
でオーバーライドしない限り)
このような場合、ASX は SXG を作成しません。SXG は複数回のアクセスや複数のユーザーに対してキャッシュに保存され、再利用される可能性があるためです。
クロスマーク(❌)が表示されるもう 1 つの理由として、Set-Cookie
を除くこれらのステートフル レスポンス ヘッダーのいずれかが存在することも考えられます。ASX は、SXG 仕様に準拠するために Set-Cookie
ヘッダーを削除します。
Vary: Cookie
レスポンス ヘッダーが存在することも原因として考えられます。Googlebot はユーザーの認証情報なしで SXG を取得し、複数の訪問者に提供する可能性があります。Cookie に基づいて異なるユーザーに異なる HTML を配信すると、ログアウトしたビューなど、正しくないエクスペリエンスが表示される可能性があります。
Chrome 拡張機能の代わりに、curl
などのツールを使用することもできます。
curl -siH "Accept: application/signed-exchange;v=b3" $URL | less
または dump-signedexchange
:
dump-signedexchange -verify -uri $URL
SXG が存在し、有効な場合は、SXG の判読可能な出力が表示されます。そうしないと、エラー メッセージが表示されます。
インデックス登録
SXG が Google 検索に正しくインデックスに登録されていることを確認します。Chrome DevTools を開き、ページを Google 検索します。ページが SXG としてインデックスに登録されている場合は、ウェブページへの Google のリンクに、webpkgcache.com のコピーを指す data-sxg-url
が追加されます。
ユーザーが検索結果をクリックする可能性が高いと Google 検索が判断した場合は、その検索結果もプリフェッチされます。
<link>
要素は、SXG をプリフェッチ キャッシュにダウンロードするようブラウザに指示します。ユーザーが <a>
要素をクリックすると、ブラウザはそのキャッシュされた SXG を使用してページをレンダリングします。
DevTools の [ネットワーク] タブに移動し、webpkgcache
を含む URL を検索すると、プリフェッチの証拠を確認することもできます。
<a>
が webpkgcache.com を参照している場合、署名付きエクスチェンジの Google 検索インデックス登録が機能しています。取り込みセクションに進んでください。
そうでない場合は、SXG を有効にした後、Google がまだページを再クロールしていない可能性があります。Google Search Console の URL 検査ツールをお試しください。
digest: mi-sha256-03=...
ヘッダーが存在する場合は、Google が SXG バージョンを正常にクロールしたことを示します。
digest
ヘッダーが存在しない場合、SXG が Googlebot に配信されていないか、SXG を有効にした後でインデックスが更新されていないことを示している可能性があります。
SXG が正常にクロールされてもリンクされていない場合は、SXG キャッシュ要件を満たしていない可能性があります。これらについては、次のセクションで説明します。
取り込み
Google 検索が SXG をインデックス登録すると、そのコピーが Google SXG キャッシュに送信され、キャッシュ要件に基づいて検証されます。Chrome 拡張機能に結果が表示されます。
チェックマーク(✅)が表示されている場合は、[最適化] に進んでください。
要件を満たしていない場合は、× マーク(❌)と、その理由を示す警告メッセージが表示されます。
この場合、ページは SXG を有効にする前と同じように動作します。Google は SXG プリフェッチなしで元のホストのページにリンクします。
キャッシュに保存されたコピーの有効期限が切れてバックグラウンドで再取得されている場合は、砂時計(⌛)が表示されます。
SXG に関する Google デベロッパー向けドキュメントには、キャッシュを手動でクエリする手順も記載されています。
最適化
Chrome 拡張機能の SXG Validator にすべてのチェックマーク(✅)が表示されている場合は、ユーザーに配信できる SXG が作成されています。SXG で LCP を最大限改善できるようにウェブページを最適化する方法については、以下をご覧ください。
max-age
SXG が期限切れになると、Google SXG キャッシュはバックグラウンドで新しいコピーを取得します。フェッチを待っている間、ユーザーは元のホストのページにリダイレクトされますが、このページはプリフェッチされません。Cache-Control: max-age
を長く設定するほど、このバックグラウンド フェッチが発生する頻度が低くなるため、プリフェッチによって LCP が低減される頻度が高くなります。
これはパフォーマンスと更新頻度のトレードオフです。キャッシュを使用すると、サイト所有者は各ページの特定のニーズに合わせて、2 分~7 日の範囲で SXG の有効期限を指定できます。経験則では、次のようなことがわかります。
max-age=86400
(1 日)以上はパフォーマンスに適していますmax-age=120
(2 分)は
今後、データをさらに調査し、この 2 つの値の間にある値について詳しく把握したいと考えています。
user-agent
プリフェッチされた SXG の使用時に、LCP が増加しました。WebPageTest を実行して、SXG プリフェッチを有効にした場合と無効にした場合の結果の中央値を比較しました。下記の [After] をクリックします。
プリフェッチが機能していることを確認しました。HTML がクリティカル パスから削除されるため、すべてのサブリソースをより早く読み込むことができます。しかし、緑色の破線の LCP は 2 秒から 2.1 秒に増加しました。
これを調べるために、フィルム ストリップを調べました。SXG ではページの表示が異なることがわかりました。プレーン HTML では、Chrome は LCP の「最大の要素」を見出しと判断しました。しかし、SXG バージョンでは、ページに遅延読み込みバナーが追加され、ヘッドラインが折り返しの下に押しやられ、遅延読み込みの Cookie 同意ダイアログが新しい最大要素になりました。すべてのレンダリングが以前よりも速くなったが、レイアウトが変更されたため、指標では遅くなったと報告されている。
さらに詳しく調査したところ、レイアウトが異なる理由は、ページが User-Agent
によって異なり、ロジックにエラーがあったことであることがわかりました。SXG クロール ヘッダーがモバイルを示しているにもかかわらず、パソコン向けのページが配信されていました。この修正後、ブラウザはページの見出しを最大の要素として再び正しく識別しました。
[After] をクリックすると、プリフェッチされた LCP が1.3 秒に短縮されました。
SXG はすべてのフォーム ファクタで有効になっています。そのためには、次のいずれかを確認してください。
- ページが
User-Agent
によってVary
されていない(レスポンシブ デザインやモバイルとパソコンの URL が別々になっているなど)。 - ページで動的配信を使用している場合は、
<meta name=supported-media content=...>
を使用して、モバイル専用またはパソコン専用としてアノテーションが付けられます。
サブリソース
SXG を使用すると、HTML とともにサブリソース(画像を含む)をプリフェッチできます。Cloudflare ASX は、HTML をスキャンして同じオリジン(ファーストパーティ)の <link rel=preload>
要素を検出し、SXG 互換のリンク ヘッダーに変換します。詳細については、こちらとこちらのソースコードをご覧ください。
正常に動作している場合は、Google 検索からの追加のプリフェッチが表示されます。
LCP を最適化するには、ウォーターフォールを詳しく調べ、最大要素のレンダリングに必要なクリティカル パス上にあるリソースを特定します。プリフェッチできない場合は、クリティカル パスから除外できるかどうかを検討します。読み込みが完了するまでページを非表示にするスクリプトに注意してください。
Google SXG キャッシュでは、最大 20 個のサブリソースのプリロードが許可され、ASX は、この上限が超過しないように保証します。ただし、サブリソースのプリロードを追加しすぎると、ブラウザは、クロスサイト トラッキングを防止するために、プリロードされたサブリソースをすべて取得が完了した場合のみ使用します。サブリソースが多いほど、ユーザーがページに移動する前にすべてのサブリソースのプリフェッチが完了する可能性は低くなります。
現在、SXG Validator はサブリソースをチェックしません。デバッグするには、curl
または dump-signedexchange
を使用してください。
測定
WebPageTest で LCP の改善を最適化したら、SXG プリフェッチがサイトの全体的なパフォーマンスに与える影響を測定することをおすすめします。
サーバーサイドの指標
最初の 1 バイトまでの時間(TTFB)などのサーバーサイド指標を測定する際は、サイトが SXG を提供するクロールツールは、その形式をサポートしているものだけであることを覚えておくことが重要です。TTFB の測定は、ボットではなく実際のユーザーからのリクエストに限定します。SXG を生成すると、クロールのリクエストの TTFB が増加する場合があります。これは、訪問者のエクスペリエンスには影響しません。
クライアントサイドの指標
SXG は、クライアントサイドの指標(特に LCP)の速度向上に最も効果的です。影響を測定する場合は、Cloudflare ASX を有効にして、Googlebot によって再クロールされるのを待ってから、Core Web Vitals(CWV)の集計までさらに 28 日間待ってから、新しい CWV 数を確認するだけです。ただし、この期間中に他のすべての変更が混在している場合、変化を見つけるのが難しい場合があります。
代わりに、影響を受ける可能性のあるページ読み込みに「ズームイン」し、「SXG はページビューの X% に影響し、75 パーセンタイルにおいて LCP を Y ミリ秒改善しました」というように表現することをおすすめします。
現在、SXG プリフェッチは特定の条件下でのみ行われます。
- Chromium ブラウザ(iOS を除く Chrome または Edge)、バージョン M98 以降
Referer: google.com
またはその他の Google 検索ドメイン。(Google アナリティクスでは、参照元タグはセッション内のすべてのページビューに適用されますが、SXG プリフェッチは Google 検索から直接リンクされた最初のページビューにのみ適用されます)。
「ページビューの X%」と「LCP を Y ミリ秒改善」の測定方法については、現代の調査のセクションをご覧ください。
現代研究
リアルユーザー モニタリング(RUM)データを確認する際は、ページ読み込みを SXG と SXG 以外に分割する必要があります。選択バイアスを回避するには、SXG 以外の側が SXG の資格要件を満たすように、対象とするページ読み込みのセットを制限することが重要です。そうでない場合、次のすべてが SXG 以外のページ読み込みのセットにのみ存在し、LCP が本質的に異なる可能性があります。
- iOS デバイス: これらのデバイスを使用しているユーザーのハードウェアやネットワーク速度が異なるためです。
- 古い Chromium ブラウザ: 同じ理由があります。
- パソコン: 上記と同じ理由、またはページ レイアウトによって別の「最大要素」が選択されるため。
- 同一サイト ナビゲーション(サイト内のリンクをたどる訪問者): 前のページ読み込みでキャッシュに保存されたサブリソースを再利用できるため。
Google アナリティクス(UA)で、スコープが「ヒット」の2 つのカスタム ディメンションを作成します。1 つは「isSXG」、もう 1 つは「referrer」という名前にします。(組み込みの「参照元」ディメンションはセッション スコープであるため、同一サイト内のナビゲーションを除外しません)。
次のフィルタを AND 演算で結合して、「SXG 対照実験」という名前のカスタム セグメントを作成します。
- 「
referrer
」の先頭が「https://www.google.
」と一致 Browser
はChrome
と完全に一致するBrowser
バージョンが正規表現^(9[8-9]|[0-9]{3})
と一致するisSXG
はfalse
と完全に一致する
このセグメントのコピーを作成して「SXG」という名前を付けます。ただし、isSXG
は true
と完全に一致するようにします。
サイト テンプレートで、Google アナリティクスのスニペットの上に次のスニペットを追加します。これは、ASX が SXG の生成時に false
を true
に変更する特別な構文です。
<script data-issxg-var>window.isSXG=false</script>
Google アナリティクスのレポート スクリプトを推奨どおりカスタマイズして、LCP を記録します。gtag.js を使用している場合は、'config'
コマンドを変更してカスタム ディメンションを設定します('dimension1'
と 'dimension2'
は、Google アナリティクスで使用するよう指定されている名前に置き換えてください)。
gtag('config', 'YOUR_TRACKING_ID', {
'dimension1': String(isSXG),
'dimension2': document.referrer,
});
analytics.js を使用している場合は、こちらに記載されているように 'create'
コマンドを変更します。
データが収集されるまで数日待ってから、Google アナリティクスのイベント レポートに移動し、SXG セグメントのドリルダウンを追加します。これにより、「SXG が X% のページビューに影響している」の X が入力されます。
最後に、Web Vitals レポートにアクセスして [セグメントを選択] を選択し、[SXG 反事実的条件] と [SXG] を選択します。
[送信] をクリックすると、2 つのセグメントの LCP 分布が表示されます。これにより、「75 パーセンタイルにおいて LCP を Y ミリ秒改善」の Y が入力されます。
注意点
上記のフィルタをすべて適用すると、SXG の反実仮想ページ読み込みは次のような内容になります。
- キャッシュに一致するデータがない: 特定の URL の SXG の最新のコピーが Google SXG キャッシュにない場合、サイトの元の URL にリダイレクトされます。
- その他の検索結果タイプ: 現在、Google 検索でサポートされているのは、標準のウェブ検索結果とその他のいくつかのタイプの SXG のみです。一方、強調スニペットやトップニュース カルーセルなどでは、サイトの元の URL にリンクされます。
- 対象外の URL: サイト上の一部のページが SXG の対象外(キャッシュに保存できないなど)である場合、このセットに表示されることがあります。
SXG ページの読み込みと上記の SXG 以外のページ読み込みの間にバイアスが残っている可能性がありますが、その程度は「現代調査」セクションの冒頭で説明したバイアスよりも小さくする必要があります。たとえば、キャッシュに保存できないページがキャッシュに保存できるページよりも遅い場合や、速い場合があります。これが問題であると思われる場合は、特定の SXG 対象 URL に限定したデータを調べて、その結果が全体的な調査と一致するかどうかを確認することをおすすめします。
サイトに AMP ページがある場合、Google 検索からすでにプリフェッチされているため、SXG を有効にしてもパフォーマンスが向上する可能性は低くなります。関連する変更をさらに「拡大」するには、そのようなページを除外するフィルタを追加することを検討してください。
最後に、選択バイアスをすべて解消しても、生存バイアスによって LCP の改善が RUM 統計情報の低下のように見えるリスクがあります。こちらの記事では、そのリスクについて詳しく説明しています。また、放棄が発生しているかどうかを検出するために、なんらかの放棄指標を確認することをおすすめしています。
前後比較調査
最新の調査結果を裏付けるために、SXG を有効にする前と後で LCP を比較すると役立つ場合があります。上記の潜在的なバイアスを排除するため、SXG ページビューに限定しないでください。代わりに、SXG の対象となる結果(上記のセグメント定義に isSXG
制約がない結果)を確認します。
なお、Google 検索がサイト上のすべてのページを再クロールして SXG が有効になっていることを確認するまでに、数週間かかることがあります。この数週間の間に、他にもバイアスが発生する可能性があります。
- 新しいブラウザのリリースやユーザーのハードウェアの改善により、ページの読み込み時間が短縮される場合があります。
- 祝日などの重要なイベントによって、トラフィックが通常から偏ることがあります。
また、上記の調査を確認するために、全体的な 75 パーセンタイル LCP の前後を確認することも有用です。母集団のサブセットについて学んだとしても、それが母集団全体についての情報になるとは限りません。たとえば、SXG によってページ読み込みの 10% が 800 ミリ秒短縮されたとします。
- これらのページの読み込みがすでに上位 10% に含まれている場合、75 パーセンタイルにはまったく影響しません。
- 最も遅いページ読み込みの 10% でも、そもそも 75 パーセンタイルの LCP よりも 800 ミリ秒以上遅かった場合、75 パーセンタイルにはまったく影響しません。
これらは極端な例であり、現実を反映していない可能性がありますが、問題を説明するうえで役立つと思います。実際には、SXG はほとんどのサイトで 75 パーセンタイルに影響する可能性があります。クロスサイト ナビゲーションは最も遅い傾向があり、プリフェッチによる改善は大幅に改善する傾向があります。
一部の URL をオプトアウトする
最後に、SXG のパフォーマンスを比較する方法として、サイト上の一部の URL で SXG を無効にするという方法があります。たとえば、CDN-Cache-Control: no-store
ヘッダーを設定して、Cloudflare ASX が SXG を生成しないようにできます。このようなケースはおすすめしません。
他の調査方法よりも選択バイアスが生じるリスクが高いと考えられます。たとえば、サイトのホームページとそれと似た URL のどちらをコントロール グループとテスト グループに選択したかによって、結果に大きな違いがみられる可能性があります。
ホールドバック スタディ
影響の測定に最適な方法は、ホールドバック テストを実施することです。残念ながら、現在のところこのようなテストは行えません。今後、このようなテストのサポートを追加する予定です。
ホールドバック スタディには次の特性があります。
- テストグループでは、SXG になるはずのページビューがランダムに切り替わり、「保留」となり、SXG 以外として配信されます。これにより、同等のユーザー、デバイス、シナリオ、ページを同じ条件で比較できます。
- 保留された(反事実的)ページビューは、アナリティクスではそのようにラベル付けされます。これにより、データを「拡大」して、コントロールの SXG のページ読み込みとテストの SXG の反事実的データを比較できます。これにより、SXG プリフェッチの影響を受けない他のページ読み込みによるノイズが軽減されます。
これにより、前述の選択バイアスの原因を排除できますが、LCP の存続バイアスのリスクを排除することはできません。どちらのプロパティも、ブラウザまたは参照元のいずれかを有効にする必要があります。
まとめ
ぜひここまでお読みいただき、ありがとうございました。ラボテストで SXG のパフォーマンスをテストする方法、ラボテストと緊密なフィードバック ループでパフォーマンスを最適化する方法、そして最終的に実環境でパフォーマンスを測定する方法について、より包括的な理解を深めてもらえれば幸いです。これらすべてを総合すると、SXG を最大限に活用し、サイトとユーザーに利益をもたらすことができます。
SXG のパフォーマンスを高める方法について、他にご提案がございましたら、お気軽にお問い合わせください。改善案とともに developer.chrome.com にバグを報告します。
Signed Exchange について詳しくは、web.dev のドキュメントと Google 検索のドキュメントをご覧ください。