A Chrome extension that summarizes, questions, translates, and analyses the page you are on, using an AI provider and API key you supply.
Page text goes from your browser directly to the provider you configured. There is no backend, no telemetry, and no third party in between.
| Feature | Where | How it works |
|---|---|---|
| Page summary | Popup → Summary | Four styles (key points, TL;DR, executive, technical) × four lengths |
| Ask about the page | Popup → Chat | Grounded in the extracted page text, with the last few turns as context |
| Translate | Popup → Translate | Whole page, or the first 2,000 characters |
| Sentiment | Popup → Analyze | A label plus a one-line reason |
| Key insights | Popup → Analyze | Up to seven bullet points |
| Smart tags | Popup → Analyze | 3–8 topic tags |
| Readability | Popup → Analyze | Flesch reading ease — computed locally, no API call |
| Page stats | Popup → Tools | Word/character/heading counts and read time, computed locally |
| Extract links | Popup → Tools | Read from the DOM, no API call |
| Export | Popup → Tools | Downloads saved summaries and chats as JSON |
| Right-click actions | Any page | Summarize / explain / translate / sentiment on a selection; summarize, insights, or tags on the page |
Ctrl+Shift+S |
Any page | Summarize the current page |
- No on-device AI. Chrome's built-in AI (
Summarizer,LanguageModel) is not available in extension service workers, which is where this extension's AI calls run. Supporting it would mean routing every request through an offscreen document — tracked as follow-up work, not shipped. - No page modification. The content script only reads.
- No agentic browsing. It does not click, type, or navigate for you.
- Nothing without a key. With no API key configured, AI actions report "no API key configured" rather than returning a fabricated answer.
git clone https://github.com/aaron-seq/GenAI-Browser-Tool.git
cd GenAI-Browser-Tool
npm ciLoad it in Chrome:
- Open
chrome://extensions - Enable Developer mode
- Click Load unpacked and select the repository root (not
dist/) - The options page opens on first install — pick a provider and paste an API key
The repository root is the loadable extension: manifest.json references the
source files directly, and Chrome loads ES modules natively in MV3 service
workers, so no build step is required for development.
npm run build writes bundled, minified copies to dist/ for packaging. There is
no dist/manifest.json, so dist/ is not loadable on its own.
Everything is configured on the extension's options page. There is no .env
file — the extension reads nothing from the filesystem at runtime.
| Provider | Default model | Get a key |
|---|---|---|
| Anthropic Claude | claude-opus-5 |
https://console.anthropic.com |
| OpenAI | gpt-4o-mini |
https://platform.openai.com/api-keys |
| Google Gemini | gemini-2.5-flash |
https://aistudio.google.com/app/apikey |
Model names are overridable per provider on the options page — useful when a provider ships a newer model than the default here.
| Command | What it does |
|---|---|
npm test |
Unit and integration tests (Vitest) |
npm run test:watch |
Tests in watch mode |
npm run test:coverage |
Coverage report |
npm run typecheck |
tsc --noEmit over the shipped source |
npm run lint |
ESLint |
npm run verify |
lint + typecheck + test |
npm run build |
Bundle to dist/ |
npm run test:e2e |
Loads the extension into real Chrome and drives it (see below) |
npm run test:e2e launches real Chrome with this repository loaded as an
unpacked extension and exercises it through its own APIs: manifest validity,
service-worker registration, options-page rendering and key persistence, content
script extraction, the popup → background → content-script message path, and the
missing-key, auth-error, and restricted-page failure paths.
No API key and no network access are required — provider calls and the fixture
page are both intercepted. First run needs npx playwright install chromium.
One path is not automatable: Chrome grants the activeTab permission only on a
real toolbar-icon click, which Playwright cannot perform because the icon lives
in browser chrome. The tests therefore pass the tab id explicitly, exactly as the
popup does. Clicking the icon and summarizing a page is still worth doing by hand
after changing the popup's tab handling.
popup.html ─┐
options.html├─► chrome.runtime.sendMessage ─► background.js (service worker)
│ │
content.js ─┘◄──── chrome.tabs.sendMessage ─────────┤
▼
core/configuration-manager.js
│ builds a client for the
▼ provider you selected
providers/ai-client.js ──► provider HTTPS API
▲
core/tasks.js (prompt construction)
| Path | Responsibility |
|---|---|
background.js |
Message router. Owns every AI call, context menu, and command. |
providers/ai-client.js |
One fetch client, shaped per provider. The only file that knows an API's wire format. |
core/tasks.js |
Prompt construction and response parsing for all seven tasks. |
core/configuration-manager.js |
Single source of truth for settings; builds the AI client. |
content.js |
Read-only DOM extraction. |
scripts/popup-main.js |
Popup UI. |
options.js |
Settings UI. |
services/storage-service.js |
Local history, bookmarks, export/import. |
src/utils/validation-service.js |
Message and input validation. |
One provider, chosen explicitly. An earlier version scored five providers on a health and latency heuristic and load-balanced between them. Four of those five returned hardcoded stub strings, so the "winner" was usually a fake. Provider choice is now the user's, and an unconfigured provider is an error rather than a silent substitution.
Prompts treat page content as data. Extracted text is fenced in
<<<PAGE_CONTENT>>> markers, and every system prompt states that the fenced
region is untrusted data whose instructions must not be followed. See
docs/SECURITY.md.
Failures are visible. Every error carries a code (MISSING_API_KEY,
AUTH_ERROR, CONTENT_SCRIPT_UNAVAILABLE, TIMEOUT, …) and reaches the UI as
text. Nothing degrades into a plausible-looking fake result.
| Permission | Why |
|---|---|
storage |
Save settings, API keys, and local history |
activeTab |
Read the page you explicitly act on |
contextMenus |
Right-click actions |
notifications |
Show the result of a right-click action |
alarms |
Daily cleanup of old local history |
host_permissions (3 API hosts) |
Send requests to the provider you chose |
The content script matches http://*/* and https://*/* because summarizing a
page requires reading it. It has no network access of its own.
| Symptom | Cause |
|---|---|
| "No API key configured" | Open the options page and add a key for the selected provider |
| "Cannot read this page" | Content scripts cannot run on chrome:// pages, the Chrome Web Store, or PDFs |
| "returned 401" | The key is wrong, revoked, or belongs to a different provider |
| "returned 429" | You hit the provider's rate limit |
| "Long page — summarized from the first section only" | Page exceeded 24,000 characters; only the first section was sent |
| Popup unchanged after an edit | Reload the extension at chrome://extensions, then reopen the popup |
Extension logs: chrome://extensions → service worker link under this
extension opens the background console.
- Long pages are truncated at 24,000 characters — no chunking or map-reduce summarization.
- Only the primary content container is extracted; heavily JavaScript-rendered or shadow-DOM pages may yield little text.
- Multi-tab comparison and cross-page reasoning are not implemented.
- Chat history lives in popup memory and is lost when the popup closes. Saved summaries and completed exchanges do persist to local storage.
- API keys are stored in
chrome.storage.sync, which is not an encrypted secret store. See docs/SECURITY.md. - Chrome only. There is no Firefox or Edge build.
- Not published to the Chrome Web Store; install unpacked.
See CONTRIBUTING.md. Run npm run verify before opening a PR.
Questions and bugs: https://github.com/aaron-seq/GenAI-Browser-Tool/issues
MIT — see LICENSE.