【AI × 個人開発】 Chrome拡張の申請でつまずく落とし穴と対策

1. はじめに

Chrome ウェブストアに拡張機能を申請する際、意外と多いのが「思わぬリジェクト」です。

私が開発した ChatGPT Question Redactor というアドオンも、最初の申請で不承認になりました。

理由はシンプル――不要な権限(tabs)をリクエストしていたからです。

拡張機能を作っていると、「とりあえず入れておけば動くだろう」と思い manifest.json に権限を追加してしまうことがあります。特に古い情報を参考にすると、"tabs" を指定するのが当然のように見えてしまう。

結果としてリジェクト通知を受け取ることになりました。

この経験を通じて、「Chrome 拡張の申請では必要最小限の権限をリクエストしなければならない」というポリシーの厳しさを実感しました。

開発者にとっては一見小さなミスでも、審査では見逃されません。

この記事では、この体験を出発点にして、Chrome 拡張申請でよくある落とし穴とその対策 をまとめていきます。

2. 事例1:不要な権限(tabs)

最初にリジェクトされた理由は、tabs 権限のリクエスト でした。

審査チームから届いた通知メールには、こう書かれていました(意訳):

この拡張は tabs 権限を要求していますが、実際のコードには使用されていないようです。
Chrome ウェブストアでは、必要のない権限を含めることは認められていません。

つまり「動作していないからダメ」ではなく、“不要な権限を入れること自体がアウト” というポリシーです。

セキュリティ上、ユーザーにとって不要なアクセス権を持つ拡張はリスクになるため、例外なくチェックされます。

解決策

今回のケースでは単純で、manifest.json から "tabs" を削除するだけで済みました。 ChatGPT のページ上で DOM を操作する処理は、以下の権限だけで問題なく動きます。

{
  "manifest_version": 3,
  "name": "ChatGPT Question Redactor",
  "version": "1.0.1",
  "permissions": [
    "scripting"
  ],
  "host_permissions": [
    "https://chat.openai.com/*"
  ]
}
  • scripting → ページにスクリプトを注入するために必要。
  • host_permissions → 実際に対象とするサイト(今回は ChatGPT のドメイン)のみを指定。

3. 事例2:host_permissions の広域指定

もうひとつ審査でよく引っかかるのが、ホスト権限を広域に指定してしまうこと です。

例えば、以下のように書いてしまうケースは非常に多いです。

"host_permissions": [
  "<all_urls>"
]

あるいは、

"host_permissions": [
  "*://*/*"
]

一見「どのサイトでも動くから便利」と思えますが、これこそがリジェクトされやすい典型パターンです。

理由は単純で、“ユーザーのすべての閲覧ページにアクセスできる” という強力すぎる権限になってしまうから。

セキュリティ・プライバシーの観点で、審査チームは非常に厳しくチェックします。

必要なドメインだけを指定する方法

解決策はシンプルです。
拡張が本当にアクセスする必要のあるドメインだけを記載すること。

たとえば ChatGPT のページでしか動かない拡張なら、以下のように書けば十分です。

"host_permissions": [
  "https://chat.openai.com/*"
]

また、複数サービスに対応する場合も、

"host_permissions": [
  "https://example.com/*",
  "https://another-service.org/*"
]

と、対象サイトを明示的に列挙するのがベストプラクティスです。

レビューに与える影響

Google の公式ドキュメントでも、広域指定をしている拡張はレビューに時間がかかるか、場合によってはリジェクトされると明記されています。

安全・明確・最小限――この原則を守ることで審査はぐっと通りやすくなります。

4. 事例3:外部スクリプトの読み込み禁止

Manifest V3 では、リモートコードの読み込みが禁止されています。

これは「セキュリティリスクを排除するため」に導入された厳しいルールで、CDN などから直接スクリプトを読み込む方式は申請時に即リジェクトの対象となります。

例えば、以下のような書き方は NG です。

<script src="https://cdn.example.com/library.js"></script>

あるいは JavaScript 内で evalnew Function() を使って動的にコードを実行する方法も禁止されています。

// NG 例
eval(remoteCode);

こうした仕組みは「審査後に外部コードを差し替えれば、ストア審査をすり抜けて悪意ある動作ができてしまう」ため、セキュリティ上の大きな脆弱性となるのです。

解決策:すべて拡張に同梱する

必要なライブラリは 必ず拡張パッケージに同梱 しましょう。 つまり、CDN を参照するのではなく、/libs フォルダなどに置いて manifest.json から読み込む形にします。

"web_accessible_resources": [{
  "resources": ["libs/library.js"],
  "matches": ["https://chat.openai.com/*"]
}]

これで外部依存をなくし、審査に通りやすくなります。

eval や動的 import の回避策

  • eval → JSON.parse や明示的な関数呼び出しに書き換える
  • 動的 import → 事前にモジュールを同梱し、必要な部分だけを呼び出す

こうした「静的で透明性のあるコード」にすることで、Chrome チームに「後から挙動を変える可能性がない」ことを示すのが重要です。

5. 事例4:リスティング不備(説明文・アイコン・スクショ)

拡張機能のコードに問題がなくても、ストアのリスティング情報が不備だとリジェクトされることがあります。
意外と見落とされがちなポイントです。

よくある不承認パターン

  • 説明文が不十分
    → 「何をする拡張なのか」が曖昧、または数行しか書かれていない。

  • 誤解を招く説明
    → 実際には提供しない機能を匂わせたり、誇張した表現。

  • アイコンやスクリーンショット不足
    → 規定のサイズに満たない、あるいは空のまま。

  • 機能と無関係な画像を使用
    → ユーザー体験と乖離しているビジュアルはリジェクト対象。

ストアページはユーザーにとっての「顔」でもあるため、Google の審査も厳しくチェックします。

提出前のチェックリスト

申請前に以下を確認すると安心です。

  • 拡張の説明文
    → 機能概要、利用シーン、制約を簡潔に書く。

  • バージョン履歴(更新情報)
    → リリースごとに「何を修正/追加したか」を明記。

  • アイコン画像
    → 16px / 48px / 128px の PNG を用意。透過背景推奨。

  • スクリーンショット
    → 実際の利用シーンを複数枚。推奨サイズ 1280×800 以上。

  • 不使用ファイルを削除
    background.html や不要なリソースが残っていると指摘されることもある。

このチェックを通してから申請すれば、コード面以外でのリジェクトを大幅に防ぐことができます。

6. 事例5:スパム・重複コンテンツ判定

Chrome ウェブストアでは、スパム的な拡張重複コンテンツに対しても厳しく審査が行われます。
単に動作するだけではなく、「ユーザーにとって実際に価値がある拡張か」が重視されます。

「ラッパー拡張」と見なされるケース

もっとも多いのは、単に既存のウェブサイトを開くだけの拡張です。

例えば「YouTube ランチャー」や「Gmail オープナー」といった、ブラウザでブックマークすれば済むような機能は「ラッパー拡張」と判定され、リジェクト対象になります。

また、既存拡張のコードを少し変えただけで公開した場合も「重複」と判断されやすいです。ストアに似たような機能の拡張が大量に並ぶのを防ぐためのポリシーです。

他拡張や外部サービス誘導の注意点

  • 拡張の説明文や UI に「他の拡張をインストールしてください」と書くのはアウト。

  • 特定の外部サービスへの過剰な誘導(アフィリエイトリンクや会員登録必須のサービスなど)も拒否されます。

  • 「拡張の利用に必須のサービス」であっても、説明文に明記しないとリジェクトされるケースがあります。

Chrome ウェブストアは「ユーザーが安心して使えること」を最優先にしているため、「実際の付加価値を示す」ことが不可欠です。

7. 事例6:依存ライブラリと脆弱性

拡張機能のコードそのものに問題がなくても、依存しているライブラリに脆弱性がある場合はリジェクトや警告の対象になります。

古いライブラリ使用のリスク

開発の効率化のために jQuery や Lodash などのライブラリを導入するケースは多いですが、

古いバージョンをそのまま同梱している
脆弱性が報告されているにも関わらず更新されていない

といった場合、セキュリティ上のリスクとして指摘されます。

特に研究調査では、数万件の拡張の中に古いライブラリを含んだまま公開されている例が多数あることが報告されています。
審査チームも「既知の脆弱性を抱えたコード」が含まれていないかを自動チェックしており、該当するとリジェクトにつながります。

提出前に確認する方法

  • npm audit
    パッケージの既知脆弱性を一覧表示してくれる。

  • npm outdated
    依存パッケージの更新状況を確認。

  • GitHub Dependabot
    リポジトリに自動アラートを出してくれる。

例えば開発時に以下を実行しておけば安心です。

npm install
npm audit fix
npm outdated

問題が見つかれば、可能な限り最新版に更新してから再ビルド・申請するのが安全です。

拡張は「ユーザー環境に常駐するソフトウェア」なので、外部依存の健全性はコード本体以上に重視されます。

8. 事例7:パフォーマンス・バッテリー問題

Chrome 拡張はコードが軽量であることも求められます。
無駄な処理が常時走っていると、ユーザーの体験を損ねるだけでなく、審査にもマイナス評価を与える可能性があります。

無駄なバックグラウンド処理

  • 常にループで動作しているポーリング処理
  • 実際には使っていないイベントリスナーを登録しっぱなしにしている
  • 不要なログ出力を延々と書き出している

こうした設計は、CPU 使用率やメモリ消費を増やし、バッテリー駆動のノートPCやモバイル端末では顕著に悪影響を及ぼします。

審査にも影響する可能性

研究では、拡張の複雑度や無駄なコードがブラウザ起動時間や消費電力に悪影響を与えることが確認されています。
そのため審査チームも「不要にリソースを消費していないか」を注視していると考えられます。

改善のヒント

  • イベント駆動型に書き換える
    → 常駐ループを廃止し、必要なタイミングでだけ処理を実行する。

  • 不要な処理は削除
    → デバッグ用ログやテストコードをそのまま残さない。

  • バックグラウンド処理の最適化
    → chrome.alarms を活用して定期的に動かすなど、省リソース設計にする。

パフォーマンス改善はユーザー満足度の向上だけでなく、審査での印象を良くする効果も期待できます。

9. まとめ

Chrome ウェブストアの申請は、一見すると単純なチェックリストのように見えます。
しかし実際には、「安全・明確・最小限」 というポリシーが徹底されており、ほんの小さな油断でもリジェクトにつながります。

  • 不要な権限を削ぎ落とす
  • ホスト権限は必要なドメインだけに絞る
  • 外部スクリプトは禁止、コードは透明性を持たせる
  • リスティング情報を正しく整える
  • スパムや重複と見なされない付加価値を示す
  • 依存ライブラリやセキュリティリスクを放置しない
  • ユーザー環境に負荷を与えない軽量な設計を心がける

開発者にとって申請のやり取りは負担にもなりますが、裏を返せば 「ユーザーにとって安全で快適な拡張を作るためのフィルター」 でもあります。
この記事が、これから申請する人にとってリスクを減らし、スムーズに承認を得る一助になれば幸いです。