Google Gemini を Chrome 拡張のサイドバーに埋め込みたかった話:iframe ではじかれてから DNR にたどり着くまで
概要
Chrome 拡張のサイドバーに Google Gemini をそのまま表示したかった。最初は単純に iframe で読み込むつもりだったが、セキュリティヘッダーでブロックされていた。本記事では、その問題の構造と Declarative Net Request(DNR) による解決手順をまとめる。
1. 行き詰まった原因
根本的な問題は、Google Gemini 側が iframe 埋め込みを拒否していることだった。Gemini のレスポンスヘッダーには次のような項目が含まれている。
X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none'
Content-Security-Policy-Report-Only: (省略)
これらのヘッダーがあると、ブラウザが自動的に iframe 表示を拒否する。そのため、どんな JavaScript を書いても HTML レベルでは回避できなかった。
2. 試したアプローチと失敗
Chrome 拡張として一般的な3つの方法を試したが、いずれも HTTP レイヤーの制約には対抗できなかった。
| ステージ | アプローチ | 結果 |
|---|---|---|
| Stage 1 | 別ウィンドウで Gemini を開き、認証済み状態で iframe に埋め込み | ❌ サイドバー内で完結しない |
| Stage 2 |
offscreenDocument 経由で iframe を生成 |
❌ ヘッダーでブロック |
| Stage 3 |
content script で DOM 操作 |
❌ HTTP ヘッダーは操作不可 |
つまり、HTML や JavaScript では解決不能だった。
3. 解決の糸口:Declarative Net Request (DNR)
突破口となったのが、Chrome 拡張 API の Declarative Net Request (DNR) だった。これはブラウザが受け取る HTTP レスポンスを横取りし、ヘッダーを追加・削除できる仕組みである。
DNR を使い、Google Gemini からのレスポンスヘッダーのうち、ブロック要因を削除することで iframe 埋め込みが可能になった。
4. 実装手順
(1) rules.json を作成
Gemini からのレスポンスヘッダーを削除するルールを定義する。
[
{
"id": 1,
"priority": 1,
"action": {
"type": "modifyHeaders",
"responseHeaders": [
{ "header": "X-Frame-Options", "operation": "remove" },
{ "header": "Content-Security-Policy", "operation": "remove" },
{ "header": "Content-Security-Policy-Report-Only", "operation": "remove" }
]
},
"condition": {
"urlFilter": "https://gemini.google.com/*",
"resourceTypes": ["main_frame", "sub_frame"]
}
}
]
(2) manifest.json に DNR 関連設定を追加
{
"manifest_version": 3,
"name": "Gemini Sidebar",
"version": "1.0",
"permissions": [
"declarativeNetRequest",
"declarativeNetRequestWithHeadersModification"
],
"host_permissions": ["https://gemini.google.com/*"],
"declarative_net_request": {
"rule_resources": [
{
"id": "ruleset_1",
"enabled": true,
"path": "rules.json"
}
]
},
"side_panel": {
"default_path": "side_panel/panel.html"
}
}
(3) panel.html に iframe を配置
<iframe src="https://gemini.google.com/" width="100%" height="100%"></iframe>
これでサイドバー内に Gemini を直接表示できるようになる。
5. 動作確認
拡張を再読み込み後、Chrome のサイドパネルを開くと、Gemini がそのまま埋め込まれて表示される。JavaScript 側では特別な処理は不要で、iframe だけで完結する。
6. 学び
- 問題の原因はコードではなく HTTP レイヤーのセキュリティヘッダー にあった。
-
content scriptやoffscreenDocumentは DOM にしかアクセスできず、ヘッダー操作はできない。 - DNR によって、ブラウザレベルでレスポンスヘッダーを制御することが可能。
- 必要なのは複雑なコードではなく、「どの層の制約かを正確に見極めること」だった。
7. 補足:API を使わなかった理由
Gemini API を利用すれば同様のことは可能だが、API 経由では従量課金が発生する。サイドバーで軽く使いたいユースケースでは、公式 UI の iframe 埋め込みの方が実用的だった。
まとめ
- Google Gemini は
X-Frame-OptionsとCSPによって iframe 埋め込みを拒否している。 - その制約は JavaScript ではなくブラウザのレスポンス制御層で対処する必要がある。
- Declarative Net Request により、拡張レベルでブロックヘッダーを削除し、サイドバー埋め込みを実現できる。
Discussion