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

perceived-perf

v1.0.0

Published

Measure user-perceived performance between interaction and visible UI response

Readme

perceived-perf

Measure user-perceived performance in frontend applications: the time between a user interaction (click, action) and the visible UI response, not raw render or network timings.

What is user-perceived performance?

User-perceived performance is how fast the app feels to the user. It’s the delay from “I clicked” to “I see the result.” That includes:

  • Your async work (e.g. API calls, state updates)
  • The browser’s layout and paint
  • The moment the screen actually updates

This library measures that full span so you can keep it under control (e.g. < 100ms) and avoid sluggish UX.

Why this library?

  • UX-focused: Measures interaction → visible response, not low-level timings.
  • Dev-only: Automatically no-ops in production; no runtime cost or logs.
  • Framework-agnostic core: Use with any stack; optional React helpers.
  • Zero runtime dependencies: Small, tree-shakable, and easy to reason about.

Install

npm install perceived-perf

Usage

Core: wrap an async action

import { trackInteraction, getInteractionMetrics } from "perceived-perf";

const data = await trackInteraction(
  "fetch-user",
  () => fetch("/api/user").then((r) => r.json()),
  { thresholdMs: 100 }
);

// Later: inspect recorded metrics (e.g. in dev tools or tests)
const metrics = getInteractionMetrics();
// [{ name: "fetch-user", start, end, duration, status: "success" }]

If the measured duration exceeds thresholdMs, a single console warning is emitted in development.

Core: manual start/end

import { startInteraction, endInteraction } from "perceived-perf";

startInteraction("open-modal");
await doSomething();
// After UI has updated, end is recorded after next paint
endInteraction("open-modal");

React: track click → next paint

import { trackClick } from "perceived-perf/react";

function SubmitButton() {
  return (
    <button {...trackClick("submit")}>Submit</button>
  );
}

To run your own handler and still track, call the returned onClick first:

<button
  onClick={(e) => {
    trackClick("submit").onClick(e);
    handleSubmit();
  }}
>
  Submit
</button>

trackClick("submit") returns { onClick }. On click it starts the interaction and ends it after the next paint, so the metric reflects “click → visible response.”

Dev-only behavior

  • Production: All tracking is disabled (NODE_ENV !== "development"). No timers, no store writes, no console output.
  • Development: Metrics are kept in memory; no analytics backend or network. Console is used only when a run exceeds thresholdMs.

So you can leave trackInteraction / trackClick in your code and ship without any performance or logging impact.

Example output

When a run exceeds the threshold in development:

[perceived-perf] "fetch-user" exceeded threshold (142ms > 100ms)

Recorded metric (from getInteractionMetrics()):

{
  name: "fetch-user",
  start: 123456.78,
  end: 123598.92,
  duration: 142.14,
  status: "success"
}

API

| API | Description | |-----|-------------| | trackInteraction(name, fn, options?) | Runs fn(), waits for resolution + next paint, records duration, warns if > thresholdMs. Returns fn’s result. | | startInteraction(name) | Starts a manual interaction. | | endInteraction(name) | Ends it (recorded after next paint). | | getInteractionMetrics() | Returns a copy of all recorded metrics. |

React (from perceived-perf/react):

| API | Description | |-----|-------------| | trackClick(name) | Returns { onClick }; on click, starts interaction and ends after next paint. |

License

MIT