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

@loupekit/sdk

v0.6.0

Published

Embeddable visual-feedback layer: pin comments to the live UI and hand them to Claude.

Readme


Overview

Traditional feedback — "the revenue card looks off on the dashboard" — loses the one thing an engineer needs: which element, in what state, on which page. Loupe captures all of it at the moment of the comment, so the feedback stays actionable even after the UI changes underneath it.

Table of contents

Features

| | | | --- | --- | | 🎯 Click-to-comment inspector | Hover-highlight any element, click to pin a comment. | | 💬 Free comments | Drop a page-level note anywhere with the Note mode — no element, no screenshot. | | ▭ Free-region screenshots | Drag a free-size box, screenshot exactly that area, comment on it. The region anchors to the element under its center, so it tracks responsive reflow and scrolling. | | 🧲 Dockable control | A DevTools-style panel: dock it to the left / right / bottom edge (which pushes your page over so it's never covered) or float it as a movable, resizable window. Light/dark theme, collapses to a small launcher, and becomes a bottom sheet on mobile. Position & theme persist. | | 🔁 Redeploy-surviving re-anchoring | A multi-signal fingerprint (stable id/testid, CSS path, XPath, text, attributes, position) re-locates the element on the current page; if it can't, the pin detaches instead of pointing at the wrong thing. | | 📸 Screenshot capture | [data-loupe-redact] regions are painted over before any pixels leave the browser. | | 🧩 Shadow-DOM isolation | The widget's CSS never leaks into your page and vice-versa. | | 🔌 Pluggable storage | Talks to the Loupe backend, or persists to localStorage for offline/demo use. | | 🤖 Claude-ready | Every comment carries the element HTML + computed styles + screenshot Claude Code needs to make the fix. |

Install

npm i @loupekit/sdk

Also mirrored to GitHub Packages as @mohamed-ashraf-elsaed/sdk — add @mohamed-ashraf-elsaed:registry=https://npm.pkg.github.com to your .npmrc to install from there.

Quick start

import { init } from "@loupekit/sdk";

init({
  projectKey: "pk_live_yourkey",
  user: { id: "u_92", name: "Sara (PM)", email: "[email protected]" },
  apiBase: "https://loupe.yourbackend.com",
  // HMAC-SHA256(user.id, PROJECT_SECRET), computed on your server (see Auth model).
  userHmac: "decb2c…",
});

A dockable control panel appears with Inspect, Note (a free page-level comment), Region, and the comment list. Use the header's dock controls to dock it left / right / bottom (which pushes your page over) or float it, toggle light/dark, or close it to a small launcher. Call destroy() to tear it down. init() is idempotent — safe to call more than once. Pass label to change the brand name shown in the header.

Offline mode (no backend)

Omit apiBase and comments persist to localStorage — great for demos and local dev:

init({ projectKey: "pk_demo", user: { id: "u_1", name: "You" } });

Re-anchoring across redeploys

The crown jewel. A comment records a multi-signal fingerprint of its target. On the next page load — even after the UI is rebuilt, relabeled, or reordered — Loupe re-locates the element and moves the pin to it. Below, the "Revenue" card was relabeled to "Total Revenue" and reordered, yet the pin follows it:

Configuration

init(config: LoupeConfig):

| Option | Type | Description | | --- | --- | --- | | projectKey | string (required) | Public project key issued by the backend. | | user | { id, name, email? } (required) | The already-authenticated host-app user. | | apiBase | string | Backend base URL. Omit → localStorage (offline mode). | | userHmac | string | HMAC-SHA256(user.id, PROJECT_SECRET) computed server-side. Required in production for writes. | | autoOpen | boolean | Start with the inspector already active. | | captureScreenshot | (el: Element) => Promise<string \| undefined> | Override element screenshot capture (the extension backs this with captureVisibleTab). | | captureRegion | (rect: RegionRect) => Promise<string \| undefined> | Override free-region capture. rect is in viewport coordinates. | | headers | Record<string, string> | Extra headers merged into every backend request (e.g. a CSRF token). | | credentials | RequestCredentials | credentials mode for backend requests — set "include" for cross-origin cookie auth. |

Redaction

Any element marked data-loupe-redact is painted over in screenshots before the pixels ever leave the browser — use it on PII, secrets, or anything sensitive:

<input data-loupe-redact value="[email protected]" />

Auth model

Each project has a secret. Writes require X-Loupe-User + X-Loupe-Hmac (= HMAC-SHA256(userId, PROJECT_SECRET)), which your server computes and injects into the page — users can't spoof identity. The dashboard and MCP server authenticate as admin with the raw secret.

Storage seam

Anything implementing StorageAdapter can back the widget — swap in your own transport:

interface StorageAdapter {
  list(projectKey: string, url: string): Promise<Comment[]>;
  save(comment: Comment): Promise<Comment>;
  update(id: string, patch: Partial<Comment>): Promise<void>;
  remove(id: string): Promise<void>;
}

The loop

SDK (in your product) → backend API → Postgres + object storage → dashboard (human triage) and MCP server (Claude reads it) → status flows back.

Related packages

| Package | Description | | --- | --- | | @loupekit/mcp | MCP server that hands the comments to Claude Code. | | @loupekit/shared | The canonical TypeScript types shared across the platform. |

Browser support

Modern evergreen browsers (Chromium, Firefox, Safari). Uses Shadow DOM, MutationObserver, and the crypto / clipboard APIs.

License

MIT © Mohamed Ashraf Elsaed