Skip to content

Repository files navigation

Article Saver — save, summarize, understand

Article Saver

A Chrome extension (Manifest V3, version 1.1.0) for saving articles to lists, generating AI summaries, chatting with a Gemini model about each article, taking rich notes, and exporting everything to Excel.

  • Local library — articles, notes, chats and settings are stored in browser IndexedDB. Optional AI sends article text and chat to Google using your API key; see Privacy.
  • Official repository: https://github.com/Barak-elisha/articles-extension.git (branch main).

Extension description and defaults

Name: Article Saver

Description: Save articles to lists, take notes, generate AI summaries, chat about your reading, and export to Excel.

The extension name, Chrome toolbar title and description are in English. On a fresh installation, the interface starts in English with a left-to-right layout, English AI responses and English Excel headers. Dates follow the selected interface language. Automatic AI summaries are off by default; saving articles and taking notes do not require an API key.

Hebrew is available as an optional language in Settings. An existing saved language choice is preserved. Article text remains in its original language.

The current release exports Excel workbooks; PDF export is not implemented.

Features

  • Side panel opens on the right, and opens automatically when the extension icon is clicked.
  • Soft blue and lavender background with flowing waves across the side panel, full-page view, and settings; the backdrop stays fixed while content scrolls.
  • List management — create, rename and delete lists (deleting a list also deletes its articles).
  • Filter by active list — select a list in the "Save to list" dropdown (or "All lists") to show only that list's articles and hide the rest.
  • Search your articles — a search box filters articles by title, summary, notes, URL and full article content, with a live result count and the last-opened article kept highlighted.
  • Save article from the active tab — extracts title, article body and URL, optionally with an automatic AI summary.
  • Chat with AI about each article — a built-in chat grounded in the article's body but also able to answer broader questions about the article (its topic, author, journal, concepts) with general knowledge. Chat messages render formatting (bold, italic, lists) inline, are persisted, and are exported to Excel.
  • Personal notes per article with a rich editor (bold, italic, lists, font size and color), saved automatically.
  • Edit the full article text directly in the panel, with automatic saving, automatic cleanup of 2+ blank lines, and a color highlight marker (a palette of preset colors or a custom one) whose highlights are persisted.
  • Auto-aligned full text — the article text automatically aligns right for Hebrew/Arabic and left for English/Latin.
  • Edit the article title inline with a small pencil next to it.
  • Full-window mode — a responsive workspace on a full screen: lists | summary+notes+chat | full text.
  • Excel export — an "All articles" sheet plus one sheet per list, with pale green headers, embedded green icons, rich text, clickable links, an APA citation and an AI-chat column.
  • AI settings — API key from Google AI Studio; when you click Refresh models the extension fetches compatible Gemini models from Google's API and lets you pick one from a dropdown (default: gemini-2.5-flash).
  • Interface language — switch between English and Hebrew in Settings (English is the default; the choice is persisted and also drives the AI output language and the Excel headers).

Saving an article from Chrome with an optional AI summary
Save an article to your library and optionally generate an AI summary

Prerequisites & Compatibility

  • Browser: Google Chrome 121+ (required for side panel support and tabs.Tab.lastAccessed used by full-window mode). Other Chromium browsers need separate compatibility checks.
  • Optional AI account: a Google account with access to Google AI Studio (free or paid tier API key).

Installation

  1. Open chrome://extensions in Chrome.
  2. Enable Developer mode.
  3. Click "Load unpacked" and choose this folder.
  4. Click the extension icon in the toolbar to open the panel.

Usage

  1. Create a list in the "Create a list" section.
  2. Choose an active list and click "Save current article".
  3. (Optional) In Settings → "AI settings", paste an API key from Google AI Studio and click Save key. Click Refresh models to query Google for compatible generation models; choose a model and save. Saving a key or opening the panel does not make a network request.
  4. (Optional) In Settings → "Interface language", choose English or Hebrew (default: English).
  5. Click "Export to Excel" to export only the selected list, using its name as the filename (List name.xlsx; characters unsupported in filenames are replaced with underscores). Choose "All lists" to export the entire library (articles.xlsx by default; the filename is localized when Hebrew is selected).

Viewing and handling an article

  • Clicking an article title opens its details: AI summary (+ "Regenerate" button), My notes, Chat with AI, and the full text.
  • Article rows include Open source and Delete article icon buttons.
  • The active article is highlighted in blue.
  • Summaries and chat messages render Markdown (headings, lists, bold, italic, code and links). Notes use the rich-text editor and its formatting toolbar.
  • Select text in AI summary or Notes, click the small marker button and choose a preset or custom color. The eraser removes highlighting from the selection. Highlights save automatically and reappear when the article is reopened. Generating a new summary clears the previous summary's highlights.
  • Search within the full text — a search bar above the article text highlights every match, shows a running count, and lets you jump between matches with ▲/▼.
  • Edit the title — click the small pencil (✎) next to the title, type, then press Enter (or click away) to save; Esc cancels.
  • The full text is cleaned automatically on save: 2+ consecutive blank lines collapse to one, and trailing spaces/newlines are removed.
  • Highlight important text — select text and pick a color from the marker bar above the text (preset palette or custom color); highlights are saved with the article.
  • Auto direction — Hebrew/Arabic articles align right, English/Latin articles align left, automatically.

Full-window mode

Full-window reading workspace with lists, summary, notes, and article text
Full-window reading workspace — feature illustration

  • The Open in full size button opens sidepanel.html?mode=full in a new tab of the same window.
  • On wide screens: My lists | AI summary + notes + chat | Full text. On narrower screens, article details stack vertically.
  • The page height follows the lists column (the page ends where the lists end); panels size to their content and scroll internally only when space is tight. The chat box stretches to the end of the page.

AI

The extension talks to Google Gemini (v1beta generateContent) in two modes:

Mode background message Description
Summary GENERATE_SUMMARY A comprehensive summary of the article body in the interface language (up to 12,000 characters sent, up to 2,048 output tokens).
Chat CHAT_ARTICLE Q&A about the article in the interface language; systemInstruction anchors factual answers to the article's content (noting when an answer goes beyond it) while allowing relevant general knowledge, and the last 20 messages are sent.

An API key is required only for AI. The "Include an AI summary" checkbox is off by default and its choice is persisted. Enabling it sends saved article content to Google on subsequent saves. Regenerate and chat are explicit AI actions. Requests time out after 60 seconds.

Model dropdownRefresh models explicitly calls Google's models endpoint using the key in a request header, follows pagination, and lists unique gemini-* models supporting generateContent. The default is gemini-2.5-flash; previously saved retired Gemini 2.0 selections resolve to that default. The selected model is stored as geminiModel.

Article Saver chat with a saved article and AI responses
Ask questions about your saved articles

Interface language (i18n)

English is the default for every new installation and whenever a stored language setting is missing or unsupported. The extension does not automatically switch to the browser or operating-system language.

To change the language, open Settings → Interface language and select English or Hebrew. This preference is saved and controls interface labels, dates, AI response language and Excel headers. Hebrew enables right-to-left layout. Switching the interface language does not translate previously saved articles, notes or AI responses.

After updating an unpacked extension, click Reload on its card in chrome://extensions and reopen the panel to refresh its name, description and interface. If an existing installation opens in Hebrew, select English in Settings; reloading preserves saved preferences.

Security & API key

  • Bring your own key — the extension does not ship or bundle any API key. You must provide your own key from Google AI Studio, under Settings → "AI settings".
  • Stored locally only — the key is saved exclusively in the browser's own storage (IndexedDB via the settings store), never transmitted to or stored on any server owned by this extension, and never written to Excel or the article records.
  • Sent only to Google — the key and your article content are sent directly from your browser to Google's Gemini API only when you generate a summary or chat (model refresh sends the key without article content); nothing is routed through a third-party backend.

Treat your key like a password: anyone who can access your browser's profile can read saved keys. If a key is ever leaked, revoke and regenerate it in Google AI Studio.

Untrusted content hardening (XSS)

The extension renders and stores content that originates outside your control — article bodies, titles, AI output — so it never inserts that data as raw HTML:

  • Article body & title — the title is always rendered with textContent. The full-text editor renders through sanitizeHtml and is always sanitized on save (sanitizeHtml(content.innerHTML)), so HTML from the source page or pasted in is neutralized before it is stored; color highlights survive because background-color (a non-URL, text-affecting property) is allowlisted. On extraction the body is stored as plain text.
  • AI summaries are rendered through renderMarkdown, which HTML-escapes the entire input (&<>") before building any markup.
  • Notes (the only HTML the user can author) are passed through a self-contained sanitizer — sanitizeHtml in sanitize.js — before rendering, on paste, before saving, and before the Excel rich-text export. It is an allowlist (no external library, works fully offline): it drops <script>, <style>, <iframe>, <object>, <embed>, <form>, interactive elements and every on* handler, strips javascript:/vbscript:/data:/file: URLs and expression()/url() CSS, while keeping the safe formatting tags (b, i, u, font, lists, …). A malicious <img onerror=…> or <a href="javascript:…"> inside a note is neutralized before it ever reaches the live DOM.
  • Anchor links produced by the sanitizer always get rel="noopener noreferrer".

Prompt-injection hardening

Because article content sent to Gemini is untrusted and could contain hidden instructions, the prompts isolate it:

  • The article body is wrapped in explicit, unusual delimiters ([START_OF_ARTICLE] … [END_OF_ARTICLE]).
  • The system instruction tells the model to treat everything between the markers strictly as reference data, never as instructions — to ignore any request, injection attempt, or "ignore previous instructions" text found inside the article.

Excel

Excel export with List, Title, AI summary, Notes, APA citation, URL, Saved on, and Chat with AI columns
Export your selected list, or choose All lists to export the library

Columns in the "All articles" sheet (and in the per-list sheets):

Column Source
List List name
Title Article title
AI summary Current a.summaryHtml when available; otherwise a.summary (Markdown → rich text)
Notes a.notes (HTML → runs with bold/italic/underline/color/size)
APA citation buildApaCitation — APA 7th edition webpage format: Title. (n.d.). Site Name. Retrieved Month D, YYYY, from URL (retrieval date uses the saved date; (n.d.) when no publication date)
URL active hyperlink
Saved on a.savedAt → numeric Excel date/time, displayed as dd/mm/yyyy hh:mm
Chat with AI a.chat formatted as Me: … / AI: … (with localized speaker labels when Hebrew is selected), with rich-text bold/italic, real bullets, paragraph breaks, and bold colored speaker labels (no raw Markdown markers)

Excel exports store Saved on as a numeric date/time (dd/mm/yyyy hh:mm), suitable for sorting and date formulas. Highlights from current AI summaries and Notes are underlined in the main sheets. Because Excel rich text does not support a background fill for part of a cell, an additional Highlights sheet stores each marked passage in a separate editable cell with its original background color. The sheet is omitted when nothing is highlighted. Regenerated summaries do not reuse stale highlights.

The export pipeline:

  • buildExcelBlob — builds the workbook with xlsx-js-style (styles, text wrapping, column widths, one sheet per list).
  • enhanceWorkbook — a post-processing pass with JSZip: converts the summary into rich-text runs (inlineStr), turns every URL column into hyperlinks (with _rels/sheet*.xml.rels), and enforces OOXML element ordering.
  • isWellFormedWorkbook — re-opens the package and verifies well-formed XML and <rPr> tag order; if anything breaks, it falls back to the safe raw SheetJS output.

Architecture

File layout

File Role
manifest.json Extension configuration and permissions
background.js Service worker — article extraction from the active tab and Gemini calls
storage.js IndexedDB layer (lists, articles, settings)
i18n.js Hebrew/English dictionaries and translation helpers
sanitize.js Self-contained HTML sanitizer (allowlist) for untrusted content
sidepanel.html/css/js The panel UI and the full-window mode
excel-export.js Excel export including rich-text styling, links and validation
lib/ Local libraries: jszip.min.js, xlsx-js-style.min.js, cpexcel.js
lib/THIRD_PARTY_LICENSES.md Preserved license notices for the bundled libraries
icons/ Extension icons (16/32/48/128)
LICENSE The project's MIT license
SECURITY.md How to report security vulnerabilities privately
CONTRIBUTING.md Contribution guidelines (local-first, no unneeded deps)

Scripts are loaded in sidepanel.html in this order (it matters): jszipcpexcelxlsx-js-stylestoragei18nsanitizehighlighterexcel-exportsidepanel.

Messaging between the panel and the background

type input output
EXTRACT_ARTICLE { lang } { ok, data: { title, content, url } }
GENERATE_SUMMARY { apiKey, content, title, model, lang } { ok, summary }
CHAT_ARTICLE { apiKey, model, title, content, messages, lang } { ok, text }

extractFromPage runs inside the tab (via chrome.scripting.executeScript): title from og:titleh1document.title, body from articlemain#contentbody, stripping script/style/nav/header/footer/form/....

The extension requests HTTP/HTTPS host access for user-triggered article extraction. tabs supports selecting the last web tab while full-window mode is focused. It does not automatically scan browsing history; storage permission is unnecessary because data uses IndexedDB. When the focused tab is the extension's own side panel, extractActiveTab falls back to the most recently used HTTP tab, so saving an article works while the panel is focused.

IndexedDB schema (article-saver-db, version 1)

  • lists{ id, name, createdAt } (index name)
  • articles{ id, listId, title, content, url, savedAt, summary?, notes?, chat? } (indexes listId, savedAt)
    • content — extracted plain text or sanitized edited HTML; contentFormat distinguishes text from html. Legacy records are sanitized on display.
    • summary — Markdown string
    • notes — HTML string
    • chat — array of [{ role: "user"|"assistant", text }]
  • settings{ key, value }; keys: activeListId, geminiApiKey, geminiModel, autoSummary, uiLang

Panel logic (JS — sidepanel.js, IIFE)

  • loadAll() — loads lists + articles + settings, picks the active list, persists activeListId, applies the interface language, re-renders.
  • window.I18N (i18n.js) — load()/set() read and write the uiLang setting (default en), and apply() swaps data-i18n* strings and sets <html lang>/dir.
  • renderLists() / renderArticleRow() — built in the DOM (no templates). renderLists filters to the active list (or shows all when "All lists"), applies the search query via articleMatches, and shows a filtered/total count.
  • articleMatches(a, query) — case-insensitive search across title, content, summary, notes and url.
  • normalizeBody(s) — collapses 2+ consecutive blank lines into one and strips trailing whitespace/CRLF, applied on extraction and on save of the full text.
  • detectDirection(s) — returns rtl for Hebrew/Arabic text, ltr otherwise; applied to the full-text editor for auto-alignment.
  • contentToHtml(s) — converts plain text (with <br> for newlines) or existing HTML into sanitized HTML for the full-text contentEditable editor.
  • showDetail(a) — builds dynamically (per article): editable title row (pencil ✎), URL, meta (meta.dataset.base), .detail-mid with AI summary (+ "Regenerate"), Notes (contentEditable editor with a toolbar wired to document.execCommand), Chat (renderChat/sendChat rendering messages through renderMarkdown), and the full text (contentEditable, saved on blur) with an in-panel search + highlight bar (applySearch) and a color-marker toolbar (execCommand("hiliteColor", …)).
  • renderMarkdown / mdInline — convert Markdown (headings, bold, italic, lists, code, links) to styled, HTML-escaped output; used by summaries, and reused for chat bubbles.
  • applyActiveRow() — highlights .article-item.active based on activeArticleId.
  • fitDetailToLists() — in full mode binds .detailBody height to the lists column height; also runs on resize.
  • Re-renders on visibilitychange (when the panel comes to the foreground).

CSS layout

  • Base (RTL): cards, buttons, .rich-text, .chat-*, .detail-*; active article state; placeholders for empty values.
  • Full mode (@media (min-width:760px) + body.full): a grid with 3 1fr columns; #detailBody is a 1fr 1fr grid with grid-template-rows: auto auto auto 1fr; .detail-mid is a flexible column (flex), the chat is flex: 1 1 auto (extends to the end of the page), and the text panel is sticky with internal scrolling.

Development

See regression test instructions and pre-store review.

  • No build step — load the folder as "load unpacked" and refresh.
  • Libraries live locally under lib/ (no CDN; everything stays fully local).
  • Manual Excel checks are done by opening the file in LibreOffice/Excel; the internal validation pipeline in excel-export.js guarantees a well-formed file even with fragile XML tweaks.

Chrome Web Store package

Run python3 scripts/package-extension.py from the repository root to create dist/article-saver-1.1.0.zip and its SHA-256 checksum. The archive contains the manifest at its root, runtime code, local libraries, icons and required license notices. Tests, screenshots, development scripts, Git metadata and machine-specific files are excluded. Generated archives are ignored by Git.

Upload this ZIP to the existing extension's Package page in the Chrome Developer Dashboard. Uploading a draft is separate from submitting it for review. Check the pre-release review and complete the remaining verification and listing requirements before submission.

Security Policy

If you discover a security vulnerability or sensitive data issue, please do not open a public issue. Contact the maintainer directly via GitHub instead, so the problem can be handled privately before it is fixed and disclosed. See the full Security Policy for details.

Contributing

Contributions are welcome. Before opening a pull request, please review the Contributing guidelines — including keeping the project local-first (no new server dependencies) and avoiding unnecessary third-party libraries.

License

This project's own code is released under the MIT License — see the root LICENSE file. Copyright (c) 2026 Barak Elisha.

The extension bundles third-party libraries locally under lib/ (JSZip, xlsx-js-style, cpexcel). Their respective license terms and copyright notices are preserved and reproduced in lib/THIRD_PARTY_LICENSES.md; redistribution of this software must retain those notices.

Limitation of Liability & General Disclaimer

This software is provided by the copyright holders and contributors "AS IS", and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed.

In no event shall the author(s) or copyright holders be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; business interruption; API billing overages; or system malfunctions) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage.

Disclaimer

This extension is provided "AS IS", without warranty of any kind, express or implied. To the maximum extent permitted by applicable law, the author(s) disclaim all warranties, including fitness for a particular purpose and non-infringement.

By using this extension you acknowledge that:

  • No Medical or Clinical Advice — This extension is designed for academic, study, and research workflows. AI-generated summaries and responses do not constitute medical, legal, or professional advice.
  • API costs & Quotas are yours — The extension connects directly to Google's Gemini API using your personal API key. You are solely responsible for managing your API quotas, billing, and any incurred costs.
  • Content ownership & Copyright — You are solely responsible for the content you extract, store, or export, and must comply with the terms of service and copyright terms of each source site.
  • Local Credential Security — API keys reside in the browser's local IndexedDB. You are responsible for maintaining the physical and digital security of your browser profile and machine.
  • Non-Affiliation: This project is an independent open-source tool and is not affiliated, endorsed, or associated with Google LLC or Google Chrome.

Author & Feedback

Changelog

v1.1.0

  • Refreshed interface and icons, with English metadata and defaults.
  • Hardened article/notes rendering and fixed Excel names, duplicate saves and list deletion.
  • Optional AI disclosure, updated Gemini default and bounded network requests.
  • Dynamic Gemini model selection dropdown via Google AI Studio API.
  • Full-text interactive highlight marker toolbar with persistent sanitized styling.
  • In-article text search with match counter and navigation controls (▲/▼).
  • Multi-field article search across titles, content, notes, and summaries.
  • APA 7th Edition compliant citation export for webpages.
  • Markdown rendering support inside chat dialogue bubbles.
  • Contextual right-click deletion for chat messages.
  • Side-panel fallback extraction handling for non-HTTP tabs.

v1.0.0

  • Initial release: Side panel UI, local IndexedDB storage, Gemini AI summaries, rich notes, full-window mode, and styled OOXML Excel export.

Releases

Packages

Contributors

Languages