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

use-page-view

v1.0.1

Published

A React hook for tracking page views and user engagement time. This hook provides real-time tracking of how long users spend on a page, their activity status, and the ability to persist time tracking across page reloads.

Readme

use-page-view

A React hook for tracking page views and user engagement time. This hook provides real-time tracking of how long users spend on a page, their activity status, and flexible callbacks for implementing custom persistence and analytics.

npm version npm downloads Bundle Size License CI Status Coverage

Features

  • 📊 Track time spent on pages
  • 👀 Monitor user activity and page visibility
  • 🔄 Periodic updates through callback
  • ⏱️ Configurable thresholds and intervals
  • 🎯 Support for one-time tracking
  • 🔑 User identification support
  • 🚀 Lightweight with minimal overhead
  • 🌐 SSR/React Router/Next.js compatible
  • 🛠️ Flexible - implement your own persistence strategy

Installation

npm install use-page-view
# or
yarn add use-page-view
# or
pnpm add use-page-view

Quick Start

import { usePageView } from 'use-page-view';

function MyPage() {
  const { timeSpent, isActive } = usePageView({
    pageId: 'my-page',
    onPageView: (data) => console.log('Page view:', data),
  });

  return (
    <div>
      <h1>My Page</h1>
      <p>
        Time spent: {timeSpent}s {isActive ? '🟢 Active' : '🔴 Inactive'}
      </p>
    </div>
  );
}

Compatibility

  • React: 16.8+ (hooks support required)
  • TypeScript: Full TypeScript support included
  • Browsers: Modern browsers
  • SSR: Compatible with React Router, Next.js and other SSR frameworks
  • React Native: Not supported (web-only)

Usage

import { usePageView } from 'use-page-view';

function BlogPost() {
  const { timeSpent, isActive } = usePageView({
    pageId: 'blog-post-123',
    userId: 'user-456', // Optional
    minTimeThreshold: 10, // Minimum time before recording (seconds)
    heartbeatInterval: 30, // How often to send updates (seconds)
    inactivityThreshold: 60, // Time before user is considered inactive (seconds)
    onPageView: async (data) => {
      try {
        await fetch('/api/track-page-view', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(data),
        });
      } catch (error) {
        console.error('Failed to track page view:', error);
      }
    },
  });

  return (
    <div>
      <div>
        Time: {formatTime(timeSpent)} {isActive ? '🟢' : '🔴'}
      </div>
      <article>Your content here...</article>
    </div>
  );
}

// Helper function to format time
function formatTime(seconds: number): string {
  const mins = Math.floor(seconds / 60);
  const secs = seconds % 60;
  return `${mins}:${secs.toString().padStart(2, '0')}`;
}

API

usePageView(options)

Options

| Option | Type | Default | Description | | --------------------- | ------------------------------ | -------- | ---------------------------------------------------------------------- | | pageId | string | Required | Unique identifier for the page being tracked | | userId | string | Optional | User identifier if user is logged in | | minTimeThreshold | number | 5 | Minimum time in seconds before recording a view | | heartbeatInterval | number | 30 | How often to send updates in seconds | | inactivityThreshold | number | 30 | Time in seconds before user is considered inactive | | onPageView | (data: PageViewData) => void | Optional | Callback function to handle page view data | | trackOnce | boolean | false | Track only the initial view | | trackOnceDelay | number | 0 | Minimum time in seconds before recording a view when trackOnce is true |

Returns

| Property | Type | Description | | ----------- | --------- | ------------------------------------------------ | | timeSpent | number | Total time spent on the page in seconds | | isActive | boolean | Whether the user is currently active on the page |

PageViewData

interface PageViewData {
  pageId: string;
  userId?: string;
  timeSpent: number;
  isActive: boolean;
}

Examples

Basic Usage

function Article() {
  const { timeSpent, isActive } = usePageView({
    pageId: 'article-789',
    onPageView: (data) => {
      console.log('Article view:', data);
    },
  });

  return (
    <div>
      <h1>Article Title</h1>
      <div>Time spent: {formatTime(timeSpent)}</div>
      <p>Article content...</p>
    </div>
  );
}

One-time Tracking

function LandingPage() {
  const { timeSpent, isActive } = usePageView({
    pageId: 'landing-page',
    trackOnce: true,
    trackOnceDelay: 30, // Track after 30 seconds
    onPageView: (data) => {
      analytics.track('landing_page_view', data);
    },
  });

  return (
    <div>
      <h1>Welcome</h1>
      <div>Time on page: {formatTime(timeSpent)}</div>
    </div>
  );
}

Error Handling

function PageWithErrorHandling() {
  const { timeSpent, isActive } = usePageView({
    pageId: 'important-page',
    onPageView: async (data) => {
      try {
        const response = await fetch('/api/analytics', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(data),
        });

        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
      } catch (error) {
        console.error('Analytics tracking failed:', error);
        // Optionally queue for retry or use alternative tracking
      }
    },
  });

  return <div>Your page content</div>;
}

Features in Detail

Time Tracking

  • Tracks total time spent on the page
  • Updates every second
  • Handles browser tab switching and page visibility changes
  • Supports custom initial time values for persistence scenarios

Activity Monitoring

  • Detects user activity through mouse, keyboard, and touch events
  • Monitors page visibility changes
  • Updates active status based on user engagement
  • Configurable inactivity threshold

Flexible Persistence

  • No built-in persistence to keep the library lightweight
  • Easy to implement custom persistence strategies

Callback System

  • Periodic updates through onPageView callback
  • Configurable update interval with heartbeatInterval
  • Minimum time threshold with minTimeThreshold
  • One-time tracking option with trackOnce

Performance

  • Minimal overhead: Efficient event handling with automatic cleanup
  • Memory efficient: Uses requestIdleCallback when available
  • Bundle size: < 5KB minified + gzipped
  • No dependencies: Zero external dependencies for maximum compatibility
  • Automatic cleanup: All event listeners and timers are cleaned up on unmount

FAQ

Q: Does this work with SSR/React Router/Next.js? A: Yes, the hook safely handles server-side rendering by checking for browser environment before initializing.

Q: How do I persist time tracking across page reloads? A: Implement your own persistence strategy using the examples above. You can use localStorage, sessionStorage, databases, or any other storage method that fits your needs.

Q: How accurate is the time tracking? A: Time tracking is updated every second and accounts for page visibility changes and user inactivity.

Q: Can I track multiple pages in the same app? A: Yes, use different pageId values for each page or component you want to track separately.

Q: Does this affect my app's performance? A: No, the hook uses efficient event handling and cleanup. The bundle size is minimal (< 3KB).

Q: What events are considered "activity"? A: Mouse movement, clicks, keyboard input, touch events, and scroll events are all considered user activity.

Q: Why doesn't the hook include built-in localStorage support? A: To keep the library lightweight and flexible. Different applications have different persistence needs, and this approach allows you to implement exactly what you need without bloating the core library.

Contributing

Please read CONTRIBUTING.md for details on our code of conduct and the process for submitting pull requests.

License

This project is licensed under the MIT License - see the LICENSE file for details.