Files
edgeever/apps/extension
..

EdgeEver Web Clipper

Chrome, Edge, and Firefox Manifest V3 extension for saving the current webpage, selected text, or a right-clicked image to a user's self-hosted EdgeEver instance.

Current MVP

  • Configure an EdgeEver instance URL and API Token.
  • Test the connection and select a default notebook.
  • Click the extension action to capture the selected content, or extract the article body with Mozilla Readability when there is no selection.
  • Convert the extracted article HTML into Markdown with Turndown before uploading it.
  • Copy the images in a saved page or selection into the note itself, so the note still shows them if the source page removes or changes them. The note is saved first; up to 30 images (20 MB each, 60 MB in total) are then uploaded as note attachments and the note is pointed at them. An image the extension cannot read, such as one blocked by its site or in an unsupported format, keeps its original address. If the note is edited before the images finish copying, the edit is kept and the images keep their original addresses. No extra site access is requested for this.
  • Right-click an image and choose Save image to EdgeEver. The image file is uploaded into a new note in the default notebook, with the source page linked underneath. An image saved from Google Search records “Google Search” and the search keyword instead of the results URL.
  • Select text on a page, right-click, and choose Save selection to EdgeEver. That passage is saved as a new note in the default notebook, with the source page linked underneath. The rest of the page is not included.
  • On X, right-click the post text and choose Save this post to EdgeEver. The post text, author, time, and photos already shown in that post are saved into one note. Text folded behind Show more is expanded first, so a long post is saved in full. Right-clicking a photo saves that image instead, so the command stays on the top-level menu. A single-post page can be saved immediately. On a timeline, the extension asks once for access to X so it can remember the post under the pointer.
  • On Xiaohongshu, right-click the note text and choose Save Xiaohongshu note to EdgeEver. The title, text, author, time, location, and photos go into one note. Comments are left out. Right-clicking a photo saves that image instead. An open note can be saved immediately. On the feed, the extension asks once for access to Xiaohongshu so it can remember the note under the pointer; open that note before saving if its full text is not on the page.
  • On Zhihu, right-click the answer or article text and choose Save Zhihu content to EdgeEver. The title, author, full text, and photos go into one note. Comments are left out. Right-clicking a photo saves that image instead. An open answer or article can be saved immediately. On the home feed or a question page, the extension remembers the item under the pointer; if that listener is not running yet, right-click the same text once more.
  • On Reddit, right-click a post or its title link and choose Save Reddit post to EdgeEver. The selected post becomes one note with its title, author, community, post text, source link, linked page, and available images. Comments are left out. The extension reads the selected post through Reddit's JSON response when available and falls back to its visible content. If the pointer listener is unavailable on a feed, right-click the same post once more.
  • On a GitHub repository page or code tree, right-click the page background, the description, or the README text and choose Save this repository to EdgeEver. The note keeps the repository address, the About text, and the homepage, language, license, and topics when the page shows them. An empty About falls back to the README's first paragraph. Issue, discussion, and single-file pages are left unsaved. The toolbar action uses the same card on those repository pages. Right-clicking a link or an image keeps the existing selection and image commands, so this one stays on the top-level menu.
  • On a Hacker News post detail page, right-click the page and choose Save Hacker News post to EdgeEver, or click Clip current page. The note keeps the title, author, original time, points at capture, external link and main-post text when available, without comments. Ask HN, Show HN and link-only posts are supported. Selecting text before the toolbar action saves only that selection.
  • On a YouTube or Bilibili watch page, right-click the page or the player and choose Save video note to EdgeEver. The note keeps the source and timestamped captions. A cover is uploaded only when the page provided the image bytes. A summary is added when the token includes ai:generate and the workspace has a default model. The command runs only after that click. Lives, premieres, bangumi, and other pages are left unsaved.
  • When the page cannot hand over the image bytes, the extension asks once for access to that image's site. After that, later images from the same site save directly.
  • Create a searchable EdgeEver memo with the source URL and a web-clip tag.

The development build also includes dedicated detail-page capture for Hacker News, V2EX and Xiaoyuzhou. It saves main-post text and links, topic supplements, or complete episode Show Notes, while keeping toolbar selection priority and reporting partially copied images. See usage and verification status (简体中文). Full cross-browser live-site acceptance and store publication are still pending.

The extension does not use a central relay service. The page content is sent directly to the EdgeEver instance configured by the user.

HN usage and verification limits are documented in English and 简体中文.

UI architecture

Extension pages use React, shared shadcn/ui-style Button and Input components, and Tailwind CSS 4 with a neutral theme. The webpage feedback UI uses the official shadcn/ui Sonner component structure, adapted for an explicit extension theme, inside a Shadow DOM. Extension pages and notifications share theme tokens. The feedback entry only mounts the component and maps clipping states, and is bundled as a standalone classic script. Its stylesheet stays inside the shadow root; image readers and content extractors do not load React. Permission requests remain in click handlers.

Localization

The extension uses the cross-browser chrome.i18n compatibility namespace. English is the fallback locale. Simplified Chinese, Japanese, and Polish are available for browsers whose UI language matches.

User-visible strings live in public/_locales/<locale>/messages.json. Add or update every supported locale when changing interface copy. Chrome Web Store listing translations are maintained separately in the developer dashboard; ready-to-paste English and Simplified Chinese copy is available in STORE_LISTING.md.

Development

Store delivery

The official repository's Submit Web Clipper workflow runs asynchronously after a stable vX.Y.Z GitHub Release is published. It builds from that release tag, runs the extension tests, and packages Chromium and Firefox before contacting the stores. Store delivery does not block or withdraw the GitHub Release. The extension keeps its independent version in apps/extension/package.json; increase it when preparing an extension update, rather than for every application release.

Each store is checked separately. A version already published (or superseded by a newer public version) is skipped, and the same version awaiting review is treated as already submitted. If another version is awaiting review, the workflow summary reports waiting-review without submitting a replacement. This is not an automatic retry: after review completes, manually run Submit Web Clipper, enter the original release_tag, and select the affected platform. Credential or submission failures remain visible as workflow failures, while the other store is still attempted. Store approval is separate from successful submission.

Manual runs retain platform selection and dry_run. Leave release_tag empty to build the selected workflow ref. Firefox notes default to a one-line extension version note; custom notes should describe only extension changes.

Chromium

From the repository root:

bun run build:extension

Then open apps/extension/dist from chrome://extensions or edge://extensions with Developer mode enabled and choose Load unpacked.

Firefox

Firefox uses the same application code with a Firefox-specific generated manifest:

bun run build:extension:firefox
bun run lint:extension:firefox

Open about:debugging#/runtime/this-firefox, choose Load Temporary Add-on, and select apps/extension/dist-firefox/manifest.json.

To create the unsigned AMO submission archive after building and linting:

bun run package:extension:firefox

The archive is written to apps/extension/web-ext-artifacts. Firefox requires AMO signing for normal installation. The manifest supports Firefox Desktop 140 or later and Firefox for Android 142 or later so Mozilla's built-in data-transmission consent UI is available.

Store submission

Chrome and Edge share one Chrome Web Store item. Firefox is submitted separately. From the repository root, the official workflow Submit Web Clipper builds and submits both. See Web Clipper store submission. Increase the version in package.json before submitting; an uploaded version cannot be replaced.

Firefox data disclosure

The Firefox package declares the data types required by its user-triggered clipping function:

  • authenticationInfo: the API token sent directly to the user's EdgeEver instance.
  • browsingActivity: the URL of the page the user chooses to clip.
  • websiteContent: the selected text, extracted article content, image, or video page the user chooses to clip. The extension sends that content only to the configured EdgeEver instance. When the token includes ai:generate and the workspace has a default model, the instance sends the caption text to that model provider. The extension does not send the page or its audio anywhere else.

No data is sent to an EdgeEver-operated relay, analytics service, or advertising service.

The next planned step is preserving a single-file HTML archive in R2 while keeping extracted text in the memo for search.