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

@temps-sdk/react-analytics

v0.0.3

Published

<p align="center"> <img src="https://raw.githubusercontent.com/gotempsh/temps/refs/heads/main/web/public/logo/temps-logo-light.png" alt="Temps Platform" width="700" /> </p>

Readme


# npm
npm install @temps-sdk/react-analytics

# bun
bun add @temps-sdk/react-analytics

# pnpm
pnpm add @temps-sdk/react-analytics

# yarn
yarn add @temps-sdk/react-analytics

Peer dependencies: react >= 18

Quick Start

Wrap your app with the provider -- analytics start working immediately:

import { TempsAnalyticsProvider } from '@temps-sdk/react-analytics';

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

What you get out of the box:

| Feature | Description | |---------|-------------| | Pageview tracking | Automatic on pushState / popstate route changes | | Page leave events | Time-on-page captured via pagehide + beforeunload | | Web Vitals | LCP, FID, CLS, TTFB, FCP, INP -- sent automatically | | Engagement tracking | Heartbeat-based active time, visibility, and inactivity detection |

Provider Configuration

<TempsAnalyticsProvider
  // Core
  basePath="/api/_temps"            // API endpoint (default)
  domain="example.com"              // Override detected hostname
  disabled={false}                  // Kill switch for analytics

  // Environment
  ignoreLocalhost={true}            // Skip localhost and test environments (default)

  // Pageviews
  autoTrackPageviews={true}         // Track on pushState/popstate (default)
  autoTrackPageLeave={true}         // Track page_leave events (default)
  pageLeaveEventName="page_leave"   // Custom event name for page leave

  // Performance
  autoTrackSpeedAnalytics={true}    // Web Vitals: LCP, FID, CLS, TTFB, FCP, INP (default)

  // Engagement
  autoTrackEngagement={true}        // Heartbeat-based engagement metrics (default)
  heartbeatInterval={30000}         // Heartbeat every 30s (default)
  inactivityTimeout={30000}         // Mark inactive after 30s of no interaction (default)
  engagementThreshold={10000}       // Consider engaged after 10s (default)

  // Session Recording
  enableSessionRecording={false}    // Off by default
  sessionRecordingConfig={{
    excludedPaths: ['/settings/*', '/admin/*'],
    sessionSampleRate: 1.0,         // Record 100% of sessions (default)
    maskAllInputs: true,            // Mask all input fields (default)
    maskTextSelector: '[data-mask]', // CSS selector for text masking
    blockClass: 'rr-block',         // CSS class to block from recording
    ignoreClass: 'rr-ignore',       // CSS class to ignore
    maskTextClass: 'rr-mask',       // CSS class to mask text
    recordCanvas: false,            // Record canvas elements (default: false)
    collectFonts: false,            // Collect font data (default: false)
    batchSize: 100,                 // Events per batch (default)
    flushInterval: 5000,            // Flush interval in ms (default)
  }}
>
  {children}
</TempsAnalyticsProvider>

Custom Events

Using the Hook

import { useTempsAnalytics } from '@temps-sdk/react-analytics';

function PricingPage() {
  const { trackEvent } = useTempsAnalytics();

  return (
    <button onClick={() => trackEvent('plan_selected', { plan: 'pro', billing: 'annual' })}>
      Choose Pro
    </button>
  );
}

Using the Shorthand Hook

import { useTrackEvent } from '@temps-sdk/react-analytics';

function DownloadButton() {
  const track = useTrackEvent();

  return (
    <button onClick={() => track('file_downloaded', { format: 'pdf' })}>
      Download PDF
    </button>
  );
}

Using HTML Attributes (Zero JS)

Track events declaratively without writing any handler code:

<button temps-event-name="cta_click" temps-data-section="hero" temps-data-variant="blue">
  Get Started
</button>

Any element with temps-event-name fires an event on click. All temps-data-* attributes are sent as event properties.

Hooks Reference

useTempsAnalytics()

The core hook. Returns the full analytics context.

const { trackEvent, trackPageview, identify, enabled } = useTempsAnalytics();

| Property | Type | Description | |----------|------|-------------| | trackEvent | (name: string, data?: Record<string, JsonValue>) => Promise<void> | Send a custom event | | trackPageview | () => void | Manually fire a pageview | | identify | (userId: string, traits?) => void | Identify a user (placeholder for future use) | | enabled | boolean | Whether analytics are currently active |

useTrackEvent()

Convenience hook that returns just the trackEvent function.

const track = useTrackEvent();
track('button_clicked', { id: 'cta-hero' });

useTrackPageview()

Returns a function to manually trigger a pageview.

const trackPageview = useTrackPageview();

useEffect(() => {
  trackPageview(); // Fire on mount
}, []);

usePageLeave(options?)

Track when users leave a page, including time spent.

import { usePageLeave } from '@temps-sdk/react-analytics';

function ArticlePage() {
  const { triggerPageLeave } = usePageLeave({
    eventName: 'article_leave',       // Default: 'page_leave'
    eventData: { category: 'blog' },  // Extra data merged into the event
    enabled: true,                     // Default: true
  });

  // Fires automatically on pagehide/beforeunload.
  // Or trigger manually before client-side navigation:
  const handleNavigation = () => {
    triggerPageLeave();
    router.push('/next-page');
  };
}

The event payload automatically includes time_on_page_ms, url, referrer, and timestamp.

useSpeedAnalytics(options?)

Tracks Web Vitals performance metrics. Enabled automatically by the provider, but can be used standalone.

import { useSpeedAnalytics } from '@temps-sdk/react-analytics';

useSpeedAnalytics({
  basePath: '/api/_temps',
  disabled: false,
});

Metrics collected:

| Metric | Full Name | Description | |--------|-----------|-------------| | TTFB | Time to First Byte | Server responsiveness | | FCP | First Contentful Paint | First pixels on screen | | LCP | Largest Contentful Paint | Main content visible | | FID | First Input Delay | Input responsiveness | | CLS | Cumulative Layout Shift | Visual stability | | INP | Interaction to Next Paint | Overall responsiveness |

Initial metrics (TTFB, FCP, LCP, FID) are batched into a single request. Late metrics (CLS, INP) are sent individually as they stabilize.

useEngagementTracking(options?)

Manual engagement tracking for specific pages or components. Useful when you need per-component engagement data or custom callbacks.

import { useEngagementTracking } from '@temps-sdk/react-analytics';

function LongArticle() {
  const { engagementData, isTracking } = useEngagementTracking({
    heartbeatInterval: 15000,    // 15s heartbeats
    engagementThreshold: 5000,   // Engaged after 5s
    onEngagementUpdate: (data) => {
      console.log(`Active for ${data.engagement_time_seconds}s`);
    },
    onPageLeave: (data) => {
      console.log(`Total time: ${data.total_time_seconds}s`);
    },
  });

  return <article>{/* ... */}</article>;
}

Engagement data shape:

interface EngagementData {
  engagement_time_seconds: number;   // Active time on page
  total_time_seconds: number;        // Total time on page
  heartbeat_count: number;           // Number of heartbeats sent
  is_engaged: boolean;               // Currently engaged
  is_visible: boolean;               // Page is visible (not backgrounded)
  time_since_last_activity: number;  // Seconds since last interaction
}

useScrollVisibility(options?)

Track when elements scroll into view using Intersection Observer. Returns a ref callback to attach to any element.

import { useScrollVisibility } from '@temps-sdk/react-analytics';

function PricingSection() {
  const ref = useScrollVisibility({
    eventName: 'pricing_viewed',
    eventData: { section: 'pricing' },
    threshold: 0.75,    // 75% of element must be visible
    once: true,          // Fire only once (default)
  });

  return <section ref={ref}>Pricing Plans</section>;
}

| Option | Type | Default | Description | |--------|------|---------|-------------| | eventName | string | 'component_visible' | Event name to fire | | eventData | Record<string, JsonValue> | - | Extra data | | threshold | number | 0.5 | Visibility percentage (0.0 - 1.0) | | root | Element \| null | null (viewport) | Scroll container | | rootMargin | string | '0px' | Margin around root | | once | boolean | true | Track only the first time | | enabled | boolean | true | Enable/disable tracking |

useSessionRecording()

Control session recording programmatically from within the provider.

import { useSessionRecording } from '@temps-sdk/react-analytics';

function RecordingToggle() {
  const {
    isRecordingEnabled,
    enableRecording,
    disableRecording,
    toggleRecording,
    sessionId,
  } = useSessionRecording();

  return (
    <div>
      <p>Recording: {isRecordingEnabled ? 'ON' : 'OFF'}</p>
      {sessionId && <p>Session: {sessionId}</p>}
      <button onClick={toggleRecording}>Toggle</button>
    </div>
  );
}

useSessionRecordingControl(defaultEnabled?)

Standalone recording control without needing the provider context. Persists user preference to localStorage.

const { isEnabled, enable, disable, toggle } = useSessionRecordingControl(false);

useAnalytics(options)

Low-level hook for plugging in a custom analytics client. Useful if you want the hook interface without the Temps provider.

import { useAnalytics } from '@temps-sdk/react-analytics';

const track = useAnalytics({
  client: {
    track: (event, data) => myAnalytics.send(event, data),
    identify: (userId) => myAnalytics.identify(userId),
  },
  defaultContext: { app: 'my-app' },
});

Session Recording

Session recording captures DOM mutations and user interactions using rrweb and streams them to your Temps instance for replay.

Enable Recording

<TempsAnalyticsProvider
  enableSessionRecording={true}
  sessionRecordingConfig={{
    sessionSampleRate: 0.1,  // Record 10% of sessions
  }}
>
  {children}
</TempsAnalyticsProvider>

Privacy Controls

Recording respects user privacy by default:

sessionRecordingConfig={{
  maskAllInputs: true,                // All input values are masked
  maskTextSelector: '[data-mask]',    // Mask specific text elements
  blockClass: 'rr-block',            // Block elements entirely
  ignoreClass: 'rr-ignore',          // Ignore elements from recording
}}

In your markup:

<!-- All inputs are masked by default (passwords, emails, etc.) -->
<input type="password" />

<!-- This element won't appear in recordings at all -->
<div class="rr-block">Sensitive content</div>

<!-- This text will be replaced with asterisks -->
<p data-mask>User's private note</p>

<!-- This element is ignored (not captured) -->
<aside class="rr-ignore">Debug panel</aside>

Path Exclusions

Exclude specific routes from recording:

sessionRecordingConfig={{
  excludedPaths: [
    '/settings/*',    // Wildcard: all settings subpages
    '/admin/*',       // Wildcard: entire admin area
    '/checkout',      // Exact match
  ],
}}

Recording automatically pauses when navigating to excluded paths and resumes when leaving them.

How It Works

  1. SessionRecorder initializes a session via POST /api/_temps/session-replay/init with device metadata
  2. DOM mutations are captured by rrweb, packed with @rrweb/packer, and batched (100 events or 10s)
  3. Batches are base64-encoded and sent to POST /api/_temps/session-replay/events
  4. On page unload, remaining events are flushed via navigator.sendBeacon for reliability
  5. Failed sends use exponential backoff (up to 5 retries before dropping)
  6. Full DOM snapshots are taken every 30s or every 200 events for replay accuracy

Standalone Engagement Tracker

For non-React environments or custom integrations, use the EngagementTracker class directly:

import { EngagementTracker } from '@temps-sdk/react-analytics';

const tracker = new EngagementTracker({
  basePath: '/api/_temps',
  domain: 'example.com',
  heartbeatInterval: 30000,
  inactivityTimeout: 30000,
  engagementThreshold: 10000,
});

// Clean up when done
tracker.destroy();

Framework Setup

Next.js (App Router)

The SDK ships with "use client" directives. Create a client-side provider wrapper:

// app/providers.tsx
'use client';

import { TempsAnalyticsProvider } from '@temps-sdk/react-analytics';

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <TempsAnalyticsProvider
      enableSessionRecording={process.env.NODE_ENV === 'production'}
    >
      {children}
    </TempsAnalyticsProvider>
  );
}

// app/layout.tsx
import { Providers } from './providers';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}

Vite / Create React App

// main.tsx
import { TempsAnalyticsProvider } from '@temps-sdk/react-analytics';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <TempsAnalyticsProvider>
    <App />
  </TempsAnalyticsProvider>
);

Environment Detection

The SDK automatically disables itself in non-production environments when ignoreLocalhost is true (default):

| Environment | Detection method | |---|---| | Localhost | localhost, 127.0.0.1, ::1, *.local | | Test runners | jest, mocha, vitest, cypress globals | | Manual override | localStorage.temps_ignore = "true" |

TypeScript

All hooks, components, and types are fully typed and exported:

import type {
  AnalyticsContextValue,
  TempsAnalyticsProviderProps,
  EngagementData,
  EngagementTrackerOptions,
  WebVitalMetric,
  SpeedMetric,
  JsonValue,
} from '@temps-sdk/react-analytics';

Requirements

  • React 18+ or React 19
  • A running Temps instance with the analytics proxy configured

Related

License

MIT