One click, one full page screenshot. Capture, annotate, export.
Free, open source, and private by design.
Website · Download · FAQ · Privacy · Report a bug
screencappy is a free, Apache-2.0 licensed Chrome extension that captures full page screenshots in one click, annotates them, and exports them as PNG, JPEG, WebP or PDF. Everything that sits behind a paywall elsewhere, annotation, blur and redaction, emoji stamps, PDF export, is free here. Nothing ever leaves your machine: no account, no cloud, no analytics, and no host permissions, so the extension cannot read a page until you ask it to.
Store listings are not live yet, so the release build is the distribution channel today.
From a release:
- Download
screencappy.zipfrom the latest release and unzip it. - Open
chrome://extensionsand turn on Developer mode. - Click Load unpacked and pick the unzipped folder.
From source:
bun install
bun run build # writes the unpacked extension to dist/Then load dist/ as an unpacked extension. bun run watch rebuilds on save.
Requires Chrome 116 or newer, or any Chromium browser of the same vintage.
- One click, whole page. Click the toolbar icon or press
Alt+Shift+P, and everything below the fold and off to the right is captured. Sticky headers appear exactly once. - Four capture modes. Full page, visible area, drag select a region (you can scroll mid selection to grab a region taller than the viewport), or pick an element DevTools style: hover highlights the node under the cursor, and a click captures exactly it.
- A real editor, free. Crop, arrows, lines, rectangles, ellipses, freehand pen, highlighter, text, emoji stamps, and blur or pixelate redaction. Every annotation is vector based and non destructive, moves, scales and rotates, and has full undo and redo, zoom, and pan.
- Export anywhere. PNG, JPEG, WebP, PDF (one tall page, or paginated to A4 or Letter), or straight to the clipboard. Filename templates like
{domain} {date} {time}. - Searchable PDF. Right click and choose "Save as searchable PDF" to print the live page through the DevTools Protocol (
Page.printToPDF) into a real PDF with selectable, searchable text rather than an image of the page. - Delayed capture. Set a start delay in Settings, or right click and pick a delayed capture, and the toolbar badge counts down before the shot. Use it when the thing you want only exists while a menu is open or an element is hovered.
- Mobile width capture. Reflow the page to a phone width layout through DevTools device emulation and capture the full mobile page at 2x, without resizing your real window. The emulated width is configurable.
- Infinite scroll, handled. Turn on "Auto-load more content" and screencappy keeps scrolling to the bottom until the page stops growing, bounded by the maximum capture height and a time budget, then captures the loaded page.
- SPA scroll containers. When the window itself barely scrolls, as in Gmail, Slack and Notion style apps, screencappy finds the inner container holding the real content and captures all of it instead of a single viewport.
- Iframes, in depth. Pick an iframe with the element picker and you get its entire content, not just the part visible in its box. Same origin frames are scrolled and stitched internally, cross origin frames are deep captured through the DevTools Protocol when the Turbo permission is granted, and anything else falls back to the frame's visible box.
- Huge pages just work. The composed image is stored as strips, so pages taller than the browser's canvas limits still render, and exports auto split into numbered files or extra PDF pages instead of failing.
- Local capture history. Recent captures keep their annotations in IndexedDB with thumbnails. Prune limits are configurable. Nothing syncs anywhere.
- Graceful on restricted pages.
chrome://pages and the Web Store cannot be scripted, so screencappy falls back to a visible area capture rather than erroring.
| Engine | How it works | Permissions | Best for |
|---|---|---|---|
| Scroll and stitch (default) | Scrolls the page tile by tile and stitches the frames. Handles sticky headers and fixed overlays (including inside open shadow DOM), parallax background-attachment: fixed backgrounds, lazy loaded images, scrollbar removal, CSS animations, high DPI screens, and browser zoom. |
activeTab only, zero host permissions |
Everyday use, and anyone who wants the extension to hold no standing access |
| Turbo (opt in) | One shot through the DevTools Protocol (Page.captureScreenshot with captureBeyondViewport). No scrolling, no stitching seams, immune to sticky headers. Also powers mobile width capture and searchable PDF export. |
Uses the debugger permission; Chrome shows a banner whenever it is attached |
Very long pages, and pages that fight the scroll loop |
Every push and pull request runs a real capture in four real browsers:
| Browser | Build | Status |
|---|---|---|
| Chrome (116+) | dist/ |
Continuously tested in CI |
| Edge | dist/ |
Continuously tested in CI |
| Brave | dist/ |
Continuously tested in CI |
| Firefox (128+) | dist-firefox/ |
Continuously tested in CI |
| Opera, Vivaldi and other Chromium browsers | dist/ |
Engine compatible, not tested in CI |
- Chromium browsers load the regular build in
dist/unchanged and every feature works. Chrome, Edge and Brave each run the full capture suite on every commit; the rest of the family shares the same engine and the same build, so they are expected to work but nothing watches them for us. Opera is the one we checked by hand: it captures correctly, but it composes at 95% scale, so it needs its own expectations rather than the shared ones. - Firefox (128+): build the Firefox variant with
bun run build:firefox, which outputsdist-firefox/from the same code with a Firefox flavoured manifest (background scripts instead of a service worker, and a gecko add-on id). Load it throughabout:debugging, then This Firefox, then Load Temporary Add-on. Scroll and stitch works fully, and CI proves it by stitching the same fixtures Chromium does. Turbo, mobile width capture, and searchable PDF export are unavailable, because Firefox has nochrome.debuggerAPI, and the options page marks Turbo accordingly. CI also runsweb-ext lint, the validator addons.mozilla.org uses at submission. - Safari is not supported: it needs a native app wrapper and a different extension format.
- Store listings for the Chrome Web Store and Firefox Add-ons are not live yet.
bun run zippacksscreencappy.zipandbun run zip:firefoxpacksscreencappy-firefox.zipfor submission.
Capture, from any tab:
| Action | Shortcut |
|---|---|
| Capture full page | Alt+Shift+P |
| Capture visible area | Alt+Shift+V |
| Capture a selected region | Alt+Shift+S |
Rebind any of these at chrome://extensions/shortcuts.
In the editor, tools are single keys and the rest follow platform convention (Ctrl on Windows and Linux, Cmd on macOS):
| Key | Tool | Key | Tool |
|---|---|---|---|
V |
Select | H |
Highlighter |
C |
Crop | T |
Text |
A |
Arrow | B |
Blur or pixelate |
L |
Line | E |
Emoji |
R |
Rectangle | P |
Pen |
O |
Ellipse |
| Shortcut | Action |
|---|---|
Ctrl/Cmd + Z |
Undo |
Ctrl/Cmd + Shift + Z |
Redo |
Ctrl/Cmd + S |
Download in the current export format |
Ctrl/Cmd + C |
Copy to clipboard |
Ctrl/Cmd + D |
Duplicate the selection |
Ctrl/Cmd + + or - |
Zoom in or out |
Ctrl/Cmd + 0 |
Actual size |
Ctrl/Cmd + 9 |
Fit width |
Ctrl/Cmd and scroll |
Zoom about the pointer (or pinch a trackpad) |
Delete or Backspace |
Delete the selected annotation |
Esc |
Deselect, cancel a crop |
Hold Space and drag |
Pan the canvas |
| Drag the handle above a selection | Rotate it, with Shift for 15 degree steps |
Zero runtime dependencies. TypeScript, bundled by esbuild, Manifest V3.
src/
manifest.json MV3 manifest (version stamped from package.json at build time)
background.ts Service worker: gestures, capture orchestration, editor tab
cdp.ts Turbo engine (chrome.debugger and CDP)
content/capture.ts Injected on demand: measures, neutralizes sticky, fixed and
animated elements, drives the scroll loop, restores the page
content/select.ts Region selection overlay (shadow DOM, scroll through)
content/element.ts Element picker overlay (DevTools style hover highlight)
editor/ The capture tab: stitching, annotation tools, export, history
stitch.ts Tiles into a strip backed BigImage (no canvas size ceilings)
annotations.ts Vector annotation model: draw, hit test, handles
export.ts PNG, JPEG, WebP, PDF and clipboard, with automatic splitting
lib/ IndexedDB, settings (chrome.storage.sync), filename templates,
and a minimal dependency free PDF writer
How a stitch capture flows. A user gesture grants activeTab. The content script measures the page and preps it: position: sticky elements are pinned back into flow, position: fixed elements are hidden after the first frame, scrollbars are hidden, and the page is optionally pre scrolled to trigger lazy loading. The service worker then scrolls tile by tile calling captureVisibleTab, throttled under Chrome's quota of two calls per second. Tiles land in IndexedDB. The editor tab composes them into strips, derives the true device pixel scale from the bitmaps themselves, and everything after that, annotating and exporting, is pure local canvas work.
screencappy requests activeTab, scripting, storage, downloads, contextMenus, and unlimitedStorage. There are no host permissions, so the extension cannot read any page until you invoke it. The full build on GitHub also declares debugger for Turbo capture, mobile width capture and searchable PDF export; the store build omits that permission and those features entirely.
There is no network code in this extension at all. No account, no telemetry, no remote config. Captures, annotations, and settings live in your browser and nowhere else.
Full policy: screencappy.smollet.app/privacy
bun install
bun run typecheck # tsc --noEmit
bun run test # unit tests
bun run e2e # end to end capture test against a real Chromium browser
bun run e2e:firefox # the same capture test against a real Firefox
bun run lint:firefox # Mozilla's add-on linter over dist-firefox/
bun run build # unpacked extension into dist/
bun run zip # build, then pack dist/ into screencappy.zipbun run e2e picks up whatever Chrome it can find; point it at another Chromium browser with CHROME=/path/to/binary, and label the run with BROWSER=brave so the output says which one it was. bun run e2e:firefox needs bun run build:firefox first and takes FIREFOX=/path/to/binary.
Every push and pull request runs typecheck, unit tests, a build, and the end to end capture in Chrome, Edge, Brave and Firefox. Releases are cut by release-please: merging the release PR tags a semver version, generates the changelog from Conventional Commits, and attaches the packed extension zip. Conventional Commits are enforced on PR titles in CI, and locally via git config core.hooksPath .githooks.
See CONTRIBUTING.md for the full loop, commit conventions, and how to add a capture regression test.
Issues and pull requests are welcome. Start with CONTRIBUTING.md.
Found a page screencappy captures badly? That is the most useful bug report you can file, and there is a dedicated form for it. Include the URL.
Security reports go through GitHub's private advisory flow, not the public issue tracker. See SECURITY.md.
Apache-2.0 © screencappy contributors