Skip to content

Screenie

Screenie is a Chrome extension that captures a whole web page as a single PDF or PNG, including everything below the fold, and carries review notes that page authors write into the CMS alongside the content. The PDF is a real PDF with selectable text, produced with the screen stylesheet forced on, so what the reviewer reads matches what the visitor sees.

It was written for one job in particular: getting a website in front of a promotional review committee in a form the committee can actually work with.

Submitting a website for regulatory review

Promotional review in pharma — the PRC or MLR committee, depending on the company — grew up around documents, and its working assumptions still reflect that. A reviewer expects a fixed artifact that can be marked up, versioned, approved, and produced years later if a regulator asks what was in market on a particular date. A website meets almost none of those assumptions: it reflows to whatever viewport it lands in, it loads content as the reader scrolls, some of its copy is assembled at render time by services that were never part of the review, and its meaning depends in part on pages one click away that the reviewer may never open.

The common workarounds each give something up. Browser print-to-PDF applies the print stylesheet, which strips backgrounds and reformats the layout, so the committee approves a rendering no patient will ever be shown. A capture of the visible window pushes the rest of the page into a second and third image with no assurance the seams line up. Neither approach records which text is fixed approved copy and which is generated per visitor, so that distinction gets reconstructed in email during the review cycle and is gone by the time anyone looks at the file again.

Screenie produces one file that holds the page and its context together: the full rendered page at a fixed width, an appended index of every link with its destination URL, and a table of the notes the page's own authors attached to specific elements. Because the notes live in the markup rather than in a reviewer's separate document, they travel with the page — anyone who captures it gets the same annotations, and the annotations stay attached to the content as it changes.

Two caveats are worth stating plainly. A capture records one rendering, so for content that varies by visitor, geography, or plan, it shows the variant that the capturing browser received; that is precisely why the dynamic-content annotations exist, since an author can describe the range of what is generated even though a single capture cannot show it. And the artifact is not an approval — Screenie improves the material a reviewer works from, while the judgment about whether the page may run stays entirely with the committee.

What a capture looks like

The page itself, captured at a fixed width with annotated elements outlined and badged. Reviewer notes get a dashed red box and an A badge; content generated at render time gets a solid pink box and a D badge. Links are outlined and numbered.

A demo product page captured by Screenie, with annotated elements outlined and numbered

Appended to the end of the same document: the capture metadata, a table for each kind of annotation, and the index of every link on the page with its destination.

The annotation section appended to the capture, showing annotation tables and the link index

Both images are captures of a demonstration page. The product, the safety information, and the annotations are fictional.

Annotating content in the CMS

Page authors add a data attribute to any container element. The attribute value is the note.

<!-- A reviewer note about approved copy -->
<div data-prcAnnotation="ISI must appear verbatim from the approved PI, revision 04/2026">
  ...
</div>

<!-- A hint that this content is generated at render time -->
<div data-prcDynamic="Copay figure is pulled live from the savings-program service; not fixed copy">
  $5 per month
</div>
Attribute Box Badge Table
data-prcAnnotation Dashed red A1, A2, A3… Annotated elements
data-prcDynamic Solid pink D1, D2, D3… Dynamic content

Badges are numbered in document order, and the numbering in the tables matches the numbering on the page, so a reviewer reading the table can find the element it refers to. Each row also records the element's tag, id, and classes along with a short preview of its text, which is enough to locate the content again in a later revision.

The two attribute names are configurable in Settings. HTML lowercases attribute names, so data-prcDynamic and data-prcdynamic are the same attribute and either spelling works in a template. An element may carry both attributes, in which case it gets both boxes and both badges and appears in both tables. Elements whose attribute is empty or whitespace are skipped, and note text is always rendered as text, never as markup.

Installation

Screenie is not on the Chrome Web Store; load it as an unpacked extension.

  1. Clone or download this repository.
  2. Open chrome://extensions in Chrome.
  3. Enable Developer mode (toggle in the top-right corner).
  4. Click Load unpacked and select the screenie/ directory.

The extension icon appears in the toolbar. Pin it for quick access.

Usage

  1. Navigate to the page you want to capture.
  2. Click the Screenie icon in the toolbar.
  3. Set the capture Width if the page should be reflowed to a specific width; the default is 1200 px.
  4. Select PDF or PNG using the format toggle. Your choice is remembered.
  5. For PDF, tick any of Highlight links, Append link annotations, and Element annotations.
  6. Click Capture Full Page.

The file is saved to your Downloads folder under a Screenie/ subdirectory, named from the page title with a timestamp appended. The popup closes on its own after a successful capture.

The three PDF options are independent. Highlight links outlines and numbers every link in the page image; Append link annotations adds the link index table at the end; Element annotations handles both the boxes and the tables for data-prcAnnotation and data-prcDynamic content. None of them alter the live page for more than the duration of the capture — the injected markup is removed afterwards, including when the capture fails partway through.

Settings

Right-click the extension icon and select Options, or click Settings in the popup footer.

Setting Default Description
Save directory Screenie Subdirectory within Downloads for saved files
Default format PDF PDF or PNG
Max page height 15,000 px Height cap for capture, which keeps infinite-scroll pages from running away
Scroll delay 300 ms Pause between scroll steps during the lazy-load pass; increase it for slow-loading pages
Annotation attribute data-prcAnnotation Attribute for reviewer notes (dashed red box, A badges)
Dynamic content attribute data-prcDynamic Attribute for render-time content hints (pink box, D badges)

How it works

Screenie drives the page through the Chrome DevTools Protocol using the chrome.debugger API rather than chrome.tabs.captureVisibleTab, which is what allows it to reach content beyond the visible viewport.

  1. Width override — when a capture width is set, Emulation.setDeviceMetricsOverride reflows the page to that width first, so the output does not depend on the size of the window that happened to be open.

  2. Scroll-to-load — the page is scrolled from top to bottom in steps of 800 px with a configurable delay between them, which triggers lazy-loaded images, infinite scroll, and intersection observer callbacks. The page is then returned to the top.

  3. Measure — content dimensions are re-measured to account for anything that loaded during the scroll pass, and the height is capped at the configured maximum.

  4. Inject (PDF only) — link highlights, element badges, and the annotation section are added, and the page is measured again.

  5. Capture — for PDF, Emulation.setEmulatedMedia({media:'screen'}) forces the screen stylesheet and Page.printToPDF renders a single page with zero margins on paper sized to the full content. For PNG, the viewport is overridden to the full page size and Page.captureScreenshot runs with captureBeyondViewport: true.

  6. Restore — injected markup is removed and every emulation override is cleared, including on failure.

  7. Save — the file is written through chrome.downloads to Downloads/<saveDir>/<title>_<timestamp>.<ext>.

Limitations

  • Chrome does not allow any extension to capture chrome:// or chrome-extension:// pages.
  • Capture fails while DevTools is open on the same tab, because only one debugger client can attach to a tab at a time.
  • Chrome shows a "Screenie started debugging this tab" banner for the duration of the capture. There is no way to suppress it, and it is not part of the captured output.
  • Very tall pages are cut off at the max height setting. PDF output is capped further at roughly 19,000 px, because Page.printToPDF rejects paper larger than 200 inches.
  • A capture reflects one moment and one rendering. Content that varies by visitor will show the variant this browser received.

Permissions

Permission Reason
activeTab Access the current tab for capture
debugger Chrome DevTools Protocol for full-page screenshots
downloads Save captured files
storage Persist settings and format preference

Screenie sends nothing anywhere. Captures are written straight to your Downloads folder, settings live in chrome.storage.sync and travel through your own Chrome profile, and the extension makes no network requests of any kind. Given that it can read every page you capture, that claim is worth checking rather than taking on faith — background.js is about 730 lines and contains no fetch, no XMLHttpRequest, and the manifest requests no host permissions.

License

Copyright (C) 2026 Tim Howland th@wdogsystems.com

Licensed under the GNU General Public License, version 3 or later. See LICENSE for the full text.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

About

Chrome extension for full-page screenshots as PDF or PNG, with CMS-authored annotations for review

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages