JinaClip scores page content locally before converting it to Markdown
Professional-grade, local-first browser extension that transforms any webpage into high-fidelity, LLM-friendly Markdown entirely within the browser's runtime. Zero-cloud, privacy-centric, and designed specifically for AI workflows.
At a glance
- What is it?
- JinaClip is a Manifest V3 browser extension that turns the page you are looking at into LLM-friendly Markdown without sending anything to a cloud reader, using a heuristic that scores candidate content roots by text density minus link density. It is aimed at people who paste web pages into models, and it still carries metadata from the service it replaced.
- Who is it for?
- JinaClip fits someone who pastes long articles into a language model and does not want the page text leaving the machine, since the whole extraction, scoring and conversion path runs in the tab with no cloud round trip.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 115 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Local extraction replaces a cloud reader call
JinaClip does the one job that a reader service does: it takes the page in front of you and produces a clean text payload you can paste into a model. The distinction is where the work happens. A cloud reader takes a URL, processes the document on a server and returns the result, which brings a rate limit, a token cost and a copy of your browsing going somewhere else. This project implements the same extraction and transformation pipeline inside the browser runtime instead, so nothing is uploaded and the cost stays at zero. The stated audience is people building AI workflows who need reliable page text repeatedly, and the design goal is stated in blunt terms: content remains local, speed is immediate and usage is unbounded. The feature matrix makes the comparison explicit, listing privacy as local against cloud processed, rate limits as infinite against strictly limited, cost as zero against token based, and full page screenshots as available locally and not applicable for the cloud path.
Text density minus link density finds the content root
The hard part of turning a web page into readable text is deciding which part of the DOM is the article. JinaClip calls this the Heuristic Scoring Engine and it refuses to guess. The engine traverses the DOM tree and collects candidate elements, the diagram names div, main and article, then hands them to a scoring module that computes text density minus link density for each. High scores belong to blocks of prose, low scores to navigation, dashboards and buttons, which the engine treats as interactive noise and penalises. The winning element becomes the content root, the DOM is cloned, and the clone is sanitised before conversion. Because the scoring is computed on the live page rather than on a fixed list of tags, the approach generalises past a hardcoded article selector, at the cost of a heuristic that can still be fooled by a page whose main body is mostly links, such as a search results listing or a documentation index.
Shadow DOM and iframes are flattened before conversion
Modern pages hide their content. Components render into shadow roots, advertisements and dashboards live in iframes, and single page applications rebuild the DOM after load. The engine handles this explicitly, flattening shadow DOM and iframes as part of its pass over the page before it hands anything to the converter. Once the structure is flat and the content root is known, the converter runs what the project calls a pro grade Markdown conversion and returns an LLM-friendly payload. The architectural shape around that is service oriented. A background orchestrator handles the user action, whether that is a click, a menu selection or a hotkey, and hands off to a config service that supplies the settings to a local reader service, which performs script injection into the target tab. The result travels back by message passing, then to the system clipboard through the Clipboard API and to the user through the Notification API, so the page text never has to be rendered into the page itself.
One click, a right click menu and a global shortcut
Three ways of triggering the capture are documented, and they map to three different output needs. A left click on the extension icon performs a standard Markdown copy. A right click opens a selection so you can choose a different format, with JSON, HTML and Text listed as the alternatives to Markdown. The third is a global shortcut, Alt+Shift+J, for immediate capture while the browser is in the foreground. In the repository layout the entry point for the background lifecycle is src/background/index.js, the core extraction and transformation engine lives in src/services/localReader.js, constants and default settings sit under src/config/, and utils/logger.js provides what the tree calls system-wide observability. The codebase is described as vanilla ES6+ with zero coupling, and the extension manifest is MV3 with no framework in the dependency list, which keeps the install small and the behaviour inspectable.
Pageshot stitches a full page into one canvas
Beyond text, the extension offers a full page capture that works in four stages, and the sequence is worth understanding because each stage is a place where a capture can go wrong. Dimension analysis calculates scrollHeight and viewHeight so the engine knows how tall the document is and how tall the viewport is. Synchronized scrolling then performs discrete jumps with paint settle delays, so each segment is captured after the browser has actually painted rather than at a scroll offset where the content has not rendered. Canvas orchestration assembles the visible segments inside an OffscreenCanvas. Data delivery is the last step, converting the final buffer into a high-quality Markdown-wrapped Base64 string. The trade-off is that a stitched image of a long article is large, and it is Base64, so it inflates roughly by a third on the way to a prompt. The stitching approach also means anything that changes while you scroll, such as a sticky header, can appear more than once in the final image.
Building from source with npm and a Node script
Contributor setup is a short three step sequence, and the packaging is done by a script rather than by a bundler framework. The build entry is a plain Node script, scripts/build.js, and the source is loaded with an unpacked extension from the dist/ folder after opening chrome://extensions/. The package configuration shows the shape of the project, with the module type set so the sources can use ES module syntax:
{
"name": "jina-reader-extension",
"version": "1.0.0",
"type": "module",
"main": "src/background/index.js",The scripts section wires the build to that Node file and prepares a pre-commit hook:
"build": "node scripts/build.js",
"prepare": "husky"
},The tooling around it is more disciplined than the rest of the project, with jest wired to the test script, eslint with a fix variant for linting, prettier for formatting, lint-staged for staged files, husky for hooks, and an .eslintrc.js and .prettierrc at the top level. The single runtime dependency is fs-extra, which the build script needs for file operations, so nothing from a framework ends up in the shipped extension.
The metadata still describes the cloud reader
The clearest sign of the project's history is in its own package file. The name field is jina-reader-extension, the description still says the extension converts a webpage to LLM-friendly text via r.jina.ai, and the repository and homepage URLs point at a path named JinaClip-_-Copy-Page-for-LLM. The README, by contrast, presents the project as a local edition whose whole point is removing the need for r.jina.ai calls, and the README title carries a version marker of v7 while package.json reads 1.0.0. None of that stops the extension from working, but it does make search results and store listings misleading, and it means a fork has to untangle which name the project actually has. Two further limits are worth stating plainly. There is no store listing in the documentation, so the only install path described is loading the built dist/ folder unpacked, which is a developer step rather than an end user step. The repository publishes no GitHub releases and the last push was on 2026-06-30, so there is no tagged build to point colleagues at.
Editorial conclusion
JinaClip fits someone who pastes long articles into a language model and does not want the page text leaving the machine, since the whole extraction, scoring and conversion path runs in the tab with no cloud round trip. It does not fit a team that needs a signed, auto-updated extension from a store, because the documented install path is loading the dist/ folder unpacked, and it does not fit anyone who needs the project metadata to describe the current architecture, since package.json still names the cloud reader in its description. Before adopting it, run npm run build and load dist/ unpacked to confirm the pipeline works in your browser, and check the repository URL and homepage fields in package.json, which still point at the JinaClip-_-Copy-Page-for-LLM path rather than the current one.
Frequently asked questions
Does JinaClip send the page to a server?
No. The project implements the whole extraction and transformation pipeline in the browser runtime instead of calling r.jina.ai, so the content stays in the tab and the Clipboard API and Notification API are the only outbound channels.
How does JinaClip decide which part of a page is the article?
The engine collects candidate elements such as div, main and article, and scores each with text density minus link density, penalising interactive elements like navigation and dashboards. The best scoring element becomes the content root.
What formats can JinaClip copy?
A left click copies standard Markdown, and a right click on the icon lets you choose JSON, HTML or Text instead. The global shortcut Alt+Shift+J triggers an immediate capture.
How do I install JinaClip for development?
Run npm install, then npm run build, and load the dist/ folder as an unpacked extension from chrome://extensions/. The build is handled by scripts/build.js and the extension uses an MV3 manifest.
Is there a released version of JinaClip?
The repository publishes no GitHub releases and the last push was on 2026-06-30, so you build from source rather than downloading a tagged package.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/ahmadhassan-bted-jinaclip)Was this useful?