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

@zsoltcsaszti/lens

v0.2.1

Published

Reader intelligence for publishers. One script tag. Zero tracking cookies.

Readme

Lens SDK

npm license

Reader intelligence for publishers. One script tag. Zero tracking cookies.


Install

Via CDN (recommended for most publishers):

<script
  src="https://unpkg.com/@zsoltcsaszti/lens/dist/lens.umd.js"
  data-site-id="YOUR_SITE_ID"
  data-api="https://your-lens-server.com"
  data-mode="emphasis">
</script>

Paste before </body> on every page. That's it — no API keys for readers, no accounts, no configuration files.

Via npm (for bundler-based setups):

npm install @zsoltcsaszti/lens
import '@zsoltcsaszti/lens' // side-effect import — auto-initialises from data-* attributes

WordPress: the plugin is included in the npm package. After npm install @zsoltcsaszti/lens, copy node_modules/@zsoltcsaszti/lens/wordpress/lens-analytics/ into wp-content/plugins/, activate, and configure under Settings → Lens Analytics.


What it does

Lens silently observes how each visitor reads — which sections they dwell on, re-read, copy — and builds an anonymous interest profile in their browser. After a couple of visits, it subtly adapts section emphasis so each reader sees what matters most to them first.

What Lens never does:

  • Never rewrites a word of your content
  • Never sends browsing history or personal data anywhere
  • Never requires readers to sign up or install anything

The visitor profile lives entirely in localStorage. Only anonymised engagement metrics (section dwell times, scroll depth) are sent to the analytics server.


Live demos

Run npm start then open:

| URL | What you see | |-----|-------------| | http://localhost:3000/ | Demo landing page | | http://localhost:3000/demo/article-tech.html | Tech deep-dive article | | http://localhost:3000/demo/article-breaking-news.html | Breaking news style | | http://localhost:3000/demo/article-magazine.html | Long-form magazine essay | | http://localhost:3000/demo/article-tutorial.html | Step-by-step tutorial | | http://localhost:3000/dashboard?site=demo | Publisher analytics dashboard | | http://localhost:3000/public/index.html | Privacy positioning page |


Run the analytics server

cd lens-sdk
npm install
npm start         # production
npm run dev       # auto-restart on file change

Server starts at http://localhost:3000. Set the PORT env variable to change it.


Script tag options

| Attribute | Values | Default | Description | |-----------|--------|---------|-------------| | data-site-id | any string | demo | Your unique publisher identifier | | data-api | URL | — | Your Lens server endpoint for analytics | | data-mode | emphasis · collapse · both · off | emphasis | How to adapt presentation | | data-debug | true · false | false | Show relevance scores on each section |

Modes:

  • emphasis — subtle left accent on highly relevant sections
  • collapse — folds low-relevance sections to 2 lines with "Show more"
  • both — emphasis on high, collapse on low
  • off — analytics only, no visual changes

Dashboard

The dashboard shows what your readers actually engage with — not just pageviews.

http://localhost:3000/dashboard?site=YOUR_SITE_ID

What's included:

  • Section engagement ranked by average dwell time
  • Section interest heatmap — sections in article order, coloured cold→hot by attention
  • The gap between word count and actual attention (the insight that drives editorial decisions)
  • Scroll depth distribution
  • Top pages by traffic

How the interest profile builds

The profile is entirely local — it never leaves the visitor's browser.

| Signal | Weight | Why | |--------|--------|-----| | Re-read (scrolled back) | 1.0 | Strongest signal — deliberate | | Clipboard copy | 1.0 | User found it worth saving | | Dwell > 5s | 0.5 | Moderate — attention held | | Slow scroll velocity | 0.2 | Weak — ambiguous |

Keywords from engaged sections are weighted using an exponential moving average (EWMA). The top 120 keywords form the profile. No topic categories are pre-defined — the profile emerges from what each person reads.

Adaptation doesn't start until visit 2. The first visit is silent — building the profile — so there's no false adaptation before the system has signal.


Privacy model

| Data | Where it lives | Sent to server? | |------|----------------|-----------------| | Visitor interest profile | localStorage only | Never | | Section dwell times | Analytics server (aggregate) | Yes — anonymous, no user identity | | Scroll depth | Analytics server | Yes — anonymous | | Page path | Server stores path only | Yes — no query string, no user linkage | | IP address | Not recorded by Lens | Arrives as normal HTTP traffic | | Device fingerprint | Never collected | — | | Cross-site tracking | Impossible — localStorage is same-origin | — |

GDPR-compatible for analytics use without a consent banner (no personal data collected). If you enable visual adaptation, check your jurisdiction's requirements for disclosures about personalised content.


Build the npm package

npm run build        # produces dist/lens.umd.js + dist/lens.esm.js
npm publish --dry-run  # verify what's included
npm publish --access public

Deploy to production

Standard Node.js/Express. Deploy to Railway, Render, Fly.io, or any VPS:

PORT=3000 node server/index.js

Then point data-api in your script tag to your deployed URL.


Roadmap

  • [x] Section interest heatmap in dashboard
  • [x] WordPress plugin
  • [x] Multi-format demo (tech, news, magazine, tutorial)
  • [x] npm package (@zsoltcsaszti/lens)
  • [ ] Multi-page interest graph (track topics across your whole publication)
  • [ ] A/B mode — adapted vs. non-adapted to 50/50 of visitors, measure engagement delta
  • [ ] Weekly publisher digest — "what your readers actually cared about this week"
  • [ ] Ghost / Webflow plugins
  • [ ] Optional AI-generated per-reader summary (publisher provides API key)