New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

react-page-tracker

Package Overview
Dependencies
Maintainers
0
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-page-tracker

A lightweight, zero-dependency library providing accurate navigation tracking, fixed document.referrer value, and complete history support for React frameworks.

  • 0.3.1
  • latest
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
161
increased by3.87%
Maintainers
0
Weekly downloads
 
Created
Source

React Page Tracker

react-page-tracker Logo

react-page-tracker is a lightweight, zero-dependency library providing accurate navigation tracking, fixed document.referrer value, and complete history support for React frameworks. Fully compatible with Next.js, Remix, TanStack Query, and React Router.

👉 Demo

📖 Documentation

🚀 An awesome use case: Magic Back Button in shadcn/ui expansions

Features

  • 📝 Identifies whether the user navigated to the page via browser back/forward buttons or by clicking a link.
  • 🧩 Works with History.go(), history.forward(), history.back(), and history.pushState().
  • 🐞 Fixes incorrect document.referrer after navigation, providing the correct referrer for tracking purposes.
  • 💡 Accurately determines whether the current page is the first or last page.
  • 🧭 Offers a complete history browsing record.
  • 🚀 Supports Next.js, Remix, TanStack Query, and React Router.
  • ⚡️ zero deps.
  • ⭐️ typed-safe.

Usage

type PageTrackerState = {
  /** current page index */
  pageIndex: number;
  /** correct `document.referrer` */
  referrer: string;
  /** whether the current page is the first page */
  isFirstPage: boolean;
  /** whether the current page is the last page */
  isLastPage: boolean;
  /** whether the user navigated to the page via browser back/forward buttons or by clicking a link */
  pageEvent?: PageEvent; // 'back' | 'forward' | 'push' | undefined.  undefined for first visit.
  /** history browsing record */
  pageHistory: string[]; // ['/', '/products', '/pdocuts/1', '/products/2', '/about', ...]
  /**
   * total page history length.
   * When user press `back` button, the `pageHistory`'s end link will become the current link.
   * You may need this total length to handle `history.go(N)` to forward N page.
   */  
  pageHistoryLength: number;
}

Simply to get the values you need in any component.

  const { pageIndex, referrer, isFirstPage, isLastPage, pageEvent, pageHistory } = usePageTrackerStore((state) => state);

Installation

npm install react-page-tracker
▲ Next.js

layout.tsx

+ import { PageTracker } from 'react-page-tracker';
export default function RootLayout({ children }: Readonly<{ children: React.ReactNode; }>) {
  return (
    <html lang="en">
    <body>
+      <PageTracker /> // next 14, there's an auto detection. A better way is to follow your environment. e,g. `enableStrictModeHandler={process.env.NODE_ENV === 'local'}`
+      <PageTracker enableStrictModeHandler={false} /> // next 15+. always be false
        {children}
    </body>
    </html>
  );
}

If you are using nextjs 15, you have to set enableStrictModeHandler to false

In nextjs 14, strict mode will execute twice when push a page (e,g. click an Anchor link) which may cause pageHistory values error and hard to handle in development mode.

But in remix, tanstack/query, react-router, it will not execute twice. works fine.

There's an automatic detection for nextjs strict mode, so you don't need to set this prop.

But I can't detect 14 or 15, so you have to set this prop to false in next 15.

PS: DO NOT set enableStrictModeHandler to true in production, it may cause issues.

You are all set up! Now you can access the page tracking information in any component.

component.tsx

import { usePageTrackerStore } from 'react-page-tracker';

export const PageTrackerValue = () => {
  // get all state
  const state = usePageTrackerStore((state) => state);
  // get the specific state you'd like to use
  const pickState = usePageTrackerStore((state) => ({
    isFirstPage: state.isFirstPage,
    referrer: state.referrer,
    pageHistory: state.pageHistory,
  }));

  return (
    <div className="flex">
      <div className="flex flex-col gap-3">
        <pre className="rounded-md bg-gray-100 px-2 py-0.5 font-bold">
          state: {JSON.stringify(state)}
        </pre>
        <pre className="rounded-md bg-gray-100 px-2 py-0.5 font-bold">
          pickState: {JSON.stringify(pickState)}
        </pre>
      </div>
    </div>
  );
};

Next.js template

🆁 Remix

force Vite to build to CommonJS

vite.config.ts

export default defineConfig({
+  ssr: {
+    noExternal: ['react-page-tracker'], // force Vite to build to CommonJS
+  },
  plugins: [
    remix({
      future: {
        v3_fetcherPersist: true,
        v3_relativeSplatPath: true,
        v3_throwAbortReason: true,
        v3_singleFetch: true,
        v3_lazyRouteDiscovery: true,
      },
    }),
    tsconfigPaths(),
  ],
});

root.tsx

import { Links, Meta, Outlet, Scripts, ScrollRestoration } from '@remix-run/react';
import type { LinksFunction } from '@remix-run/node';

import './tailwind.css';
+ import { PageTracker } from 'react-page-tracker';

export const links: LinksFunction = () => [
  { rel: 'preconnect', href: 'https://fonts.googleapis.com' },
  {
    rel: 'preconnect',
    href: 'https://fonts.gstatic.com',
    crossOrigin: 'anonymous',
  },
  {
    rel: 'stylesheet',
    href: 'https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap',
  },
];

export function Layout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <Meta />
        <Links />
      </head>
      <body>
+       <PageTracker />
        {children}
        <ScrollRestoration />
        <Scripts />
      </body>
    </html>
  );
}

export default function App() {
  return <Outlet />;
}

You are all set up! Now you can access the page tracking information in any component.

component.tsx

import { usePageTrackerStore } from 'react-page-tracker';

export const PageTrackerValue = () => {
  // get all state
  const state = usePageTrackerStore((state) => state);
  // get the specific state you'd like to use
  const pickState = usePageTrackerStore((state) => ({
    isFirstPage: state.isFirstPage,
    referrer: state.referrer,
    pageHistory: state.pageHistory,
  }));

  return (
    <div className="flex">
      <div className="flex flex-col gap-3">
        <pre className="rounded-md bg-gray-100 px-2 py-0.5 font-bold">
          state: {JSON.stringify(state)}
        </pre>
        <pre className="rounded-md bg-gray-100 px-2 py-0.5 font-bold">
          pickState: {JSON.stringify(pickState)}
        </pre>
      </div>
    </div>
  );
};

Remix template

Contributing

Be welcome to contribute! Here's how you can contribute:

  • Open an issue if you believe you've encountered a bug.
  • Make a pull request to add new features/make quality-of-life improvements/fix bugs.

Built by Hsuan Yi, Chou

BuyMeACoffee

License

Licensed under the MIT License.

Keywords

FAQs

Package last updated on 21 Nov 2024

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc