ブラウザ拡張機能を開発していると、「リクエストの情報を取りたいのに取れない!」という場面に出くわすことがあります。そんなとき候補に上がるのが Performance API と chrome.webRequest API の2つです。
どちらもリクエストの情報を扱うAPIですが、動作する層がまったく異なるため、できることとできないことに大きな差があります。この記事では両者の違いを整理し、どちらをどんな場面で使うべきかを解説します。

「Performance APIで画像のリクエスト取ろうとしたら取れなかったんだけど…」

どっちのAPIを使うかより「なぜ取れないのか」を先に理解すると、スッと腑に落ちますよ
そもそも2つのAPIは何が違うの?
まずざっくりと整理しましょう。
Performance API はブラウザに標準搭載されたJavaScript APIで、ページ内で読み込まれたリソースのタイミング情報などを取得できます。拡張機能でなくても、通常のWebページのJavaScriptから呼び出せるのが特徴です。
// Performance APIの使用例
const entries = performance.getEntriesByType('resource');
entries.forEach(entry => {
console.log(entry.name); // リソースのURL
console.log(entry.duration); // 読み込みにかかった時間
});一方 chrome.webRequest API はChrome拡張機能専用のAPIで、ブラウザが行うすべてのHTTPリクエストをネットワーク層レベルで監視・操作できます。通常のWebページからは使えません。
// chrome.webRequest APIの使用例(manifest.jsonでの権限設定が必要)
chrome.webRequest.onCompleted.addListener(
(details) => {
console.log(details.url); // リクエストURL
console.log(details.requestHeaders); // リクエストヘッダー
},
{ urls: ["<all_urls>"] },
["requestHeaders"]
);
使える場所がそもそも違うんだね

そうなんです。Performance APIは「誰でも使える」、chrome.webRequestは「拡張機能専用」と覚えておきましょう
動作する「層」が違う
2つのAPIの最大の違いは どのレイヤーで動いているか です。下の図を見てください。
HTTPリクエストの送受信を直接監視。CSSやDOMの状態に関係なく、リクエストが発生した瞬間に検知できる。
HTMLの解析・CSSの適用・レンダリングツリーの構築を行う。display:noneの要素はここで「描画不要」と判断される。
レンダリングエンジンが「使った」と判断したリソースの情報をJavaScriptから参照できる。レンダリング結果に依存する。
▲ chrome.webRequestは上流、Performance APIは下流で動作する
chrome.webRequestはリクエストが発生した瞬間に 上流で 検知するため、後続の処理(CSSの適用など)の影響を受けません。一方Performance APIはレンダリングが終わった 下流で 情報を参照するため、レンダリングエンジンの判断に左右されます。川の上流と下流のようなイメージで捉えると分かりやすいかもしれません。
display:none問題 ― なぜ取得できないのか
Performance APIを使っていてハマりやすいのが display:noneで非表示にされた要素のリクエストが取得できない 問題です。
原因はレンダリングエンジンの仕組みにあります。display:none が指定された要素はレンダリングツリーから除外され「描画しなくていい要素」と判断されます。Performance APIは「描画に使われたリソース」を記録する仕組みのため、この判断に従って記録をスキップしてしまうのです。
一方chrome.webRequestはネットワーク層にいるため、レンダリングエンジンの判断とは無関係にリクエストを検知できます。
状況ごとの挙動の違いをまとめると下記のようになります。
🔍 display:none の状況別・リクエスト取得可否
| 状況 | リクエスト発生 | Performance API | chrome.webRequest |
|---|---|---|---|
display:none 静的 <img> タグ | ⚠️ 場合あり | ❌ 取得できない | ✅ 取得できる |
display:none JS 動的生成 | ✅ 発生する | ❌ 取得できない | ✅ 取得できる |
display:none CSS background-image | ❌ 発生しない | ❌ 取得できない | ❌ 取得できない |
なお、静的な <img> タグの場合はブラウザの プリロードスキャナー(HTMLを解析しながら別スレッドでリソースを先読みする仕組み)によってCSSが適用される前にリクエストが走ることがあります。そのためchrome.webRequestでは検知できるケースがあります。
> 悩見坂 楓
> じゃあchrome.webRequestを使えば全部解決じゃないの?
> 著者
> 惜しい!CORSという別の壁が待ち構えています
CORSの影響の違い
Performance APIにはもう1つの制約として CORS(Cross-Origin Resource Sharing) の影響があります。
異なるオリジン(ドメイン)からのリソースは、サーバー側で Timing-Allow-Origin ヘッダーが設定されていないと、Performance APIから詳細なタイミング情報が取得できません。取れるのはリソースの存在だけで、レスポンスタイムなどは 0 になってしまいます。
const entry = performance.getEntriesByName('https://other-domain.com/image.png')[0];
console.log(entry.duration); // → 0(CORSで詳細が隠される)
console.log(entry.responseEnd); // → 0
console.log(entry.name); // → URLは取れる実際にどちらを使うべきか
整理すると、2つのAPIの使い分けは下記のようになります。
- ページの表示速度計測
- 同一オリジンのリソース監視
- 拡張機能なしで使いたい
- 読み込み順序の分析
- display:none要素の監視
- クロスオリジンの詳細取得
- リクエストの改ざん・ブロック
- すべてのリクエストの監視
- クロスオリジンの情報取得
- リクエストのブロック・改ざん
- display:none要素の監視
- 拡張機能なしでは使えない
- manifest設定が必要
- Manifest V3では制限あり
なお chrome.webRequest は Manifest V3 への移行に伴い、リクエストをブロック・改ざんする用途には chrome.declarativeNetRequest の使用が推奨されるようになっています。新規で拡張機能を開発する場合は合わせて確認しておきましょう。

ページの速度計測ならPerformance API、拡張機能でがっつり監視するならchrome.webRequestって感じか

そのとおりです。目的に応じて使い分けるのがポイントです
まとめ
- Performance API はJavaScript実行層(下流)で動作し、レンダリングに使われたリソースの情報を参照する
- chrome.webRequest はネットワーク層(上流)で動作し、すべてのリクエストを検知できる
display:noneの要素はレンダリングツリーから除外されるため、Performance APIでは記録されない- CORSの影響を受けるのはPerformance APIのみ。chrome.webRequestは影響を受けない
- 拡張機能なしで使えるのはPerformance APIだけ。chrome.webRequestはmanifest設定が必要
- Manifest V3への移行でchrome.webRequestの一部機能に制限が入っている点も注意
どちらが優れているということはなく、用途に合わせた使い分けが重要です。「なんで取れないんだろう…」と悩む前に、まず「どの層で何が起きているか」を整理する癖をつけると、ハマりどころをぐっと減らせますよ。では、また!

