npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

frenderer

v0.0.1

Published

A lightweight, browserless SPA renderer. Execute client-side JavaScript and return fully rendered HTML without Chromium.

Readme

frenderer

Execute client-side JavaScript and extract fully rendered HTML or text — without a browser.

Perfect for scraping, SEO, and AI pipelines — use --text to extract clean, readable content from modern SPAs.

frenderer https://example.com

How it works

Most modern sites are JS-rendered — the raw HTML is just an empty <div id="root">. frenderer runs the page’s JavaScript in a sandboxed environment, lets the DOM fully resolve, then returns the final result.

Pipeline:

Tokenizer → Parser → DOM → JS Sandbox → Cleaner

frenderer exists for one simple reason: most tools either don’t execute JavaScript, or require a full browser to do it. This sits in the middle — fast, lightweight, and purpose-built for content extraction.

All built from scratch in Node.js. No Puppeteer. No Playwright. No headless browser.

Install

npm install -g frenderer

Requires Node.js 22+.

CLI

frenderer <url> [options]

| Flag | Default | Description | | ----------------------- | ------- | ---------------------------------------------------------- | | -o, --out <file> | stdout | Write output to file | | -s, --settle <ms> | 1000 | Wait after scripts run for async renders | | -t, --timeout <ms> | 30000 | Total render timeout | | --no-js | — | Skip JS execution, static fetch only | | --script-timeout <ms> | 5000 | Per-script execution kill timeout | | --attributes | — | Preserve all HTML attributes (disable attribute stripping) | | --text | — | Extract plain text only, no HTML tags | | --pretty | — | Pretty-print output | | --no-clean | — | Raw rendered HTML, no cleaning | | -H, --header <k:v> | — | Add request header (repeatable) | | -v, --verbose | — | Show script errors and timing per script | | -q, --quiet | — | Suppress progress output |

Examples

# Render a JS-heavy SPA
frenderer https://myapp.vercel.app

# Save to file
frenderer https://myapp.vercel.app -o out.html

# Extract plain text (great for LLM input or search indexing)
frenderer https://myapp.vercel.app --text -o content.txt

# Give async frameworks more time to render
frenderer https://myapp.vercel.app -s 3000

# Static fetch only, no JS
frenderer https://example.com --no-js

# Keep raw HTML with all attributes intact
frenderer https://myapp.vercel.app --no-clean --attributes

# Pass cookies for auth-protected pages
frenderer https://myapp.vercel.app -H "Cookie: session=abc123"

# Debug script errors
frenderer https://myapp.vercel.app --verbose

Library

import { frenderer } from "frenderer";

const html = await frenderer("https://myapp.vercel.app", {
  settle: 2000, // ms to wait for async rendering
  timeout: 30000, // total timeout
  js: true, // execute scripts
  clean: true, // strip noise (default)
  headers: {}, // custom request headers
});

Clean options

By default frenderer strips classes, aria labels, data attributes, scripts, styles, SVGs, comments, and Next.js image optimizer URLs — leaving lean, readable HTML.

const html = await frenderer(url, {
  clean: {
    class: true, // Tailwind / CSS classnames
    aria: true, // aria-* attributes
    data: true, // data-* attributes
    style: false, // inline styles
    id: false, // id attributes
    scripts: true, // <script> blocks
    styles: true, // <style> blocks + <link rel=stylesheet>
    svg: true, // <svg> blocks (icons)
    comments: true, // <!-- comments -->
    srcset: true, // srcset attributes
    imgattrs: true, // width/height/loading/decoding
    imgurls: true, // decode Next.js image optimizer URLs
    decimals: true, // trim long decimals in inline styles
    attributes: true, // strip ALL attributes (overrides above)
    textonly: false, // extract plain text only
    whitespace: true, // collapse blank lines
  },
});

As a prerender middleware

Drop-in SEO for existing Vite/CRA apps — serve rendered HTML to crawlers, normal SPA to users:

import { frenderer } from "frenderer";

const BOT_UA = /googlebot|bingbot|twitterbot|facebookexternalhit|crawler/i;

app.use(async (req, res, next) => {
  if (!BOT_UA.test(req.headers["user-agent"] || "")) return next();

  const html = await frenderer(`http://localhost:${PORT}${req.url}`, {
    settle: 1000,
  });
  res.send(html);
});

Security

Script execution runs inside two layers of isolation:

  1. vm context — sandboxed V8 isolate, no access to host globals (require, process, __dirname, env vars)
  2. Worker thread — each render runs in an isolated thread; even if a script escapes the vm, the main process is unaffected

Designed to safely execute untrusted page scripts using multiple isolation layers.

Limitations

  • Pages that require authentication (cookies/sessions) need headers passed manually
  • Sites using WebGL, Canvas, or WebAssembly for rendering won't work
  • Heavy anti-bot detection (Cloudflare, Akamai) may block requests
  • Not a replacement for proper SSR frameworks (Next.js, Nuxt) in new projects

Contributing

frenderer is early and intentionally simple. If something feels missing or could be cleaner, you're probably right.

Areas that could use help:

  • Better JS compatibility (framework edge cases)
  • Smarter DOM → text extraction
  • Performance improvements
  • Plugin/hooks system

PRs and ideas welcome.

License

Apache 2.0

Turn modern JS-heavy websites into clean, readable content — no browser required.