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

@vigneshwaranbs/activity-tracker

v2.1.6

Published

Universal user activity tracking library

Readme

🎯 Activity Tracker

Universal user activity tracking library for web applications

npm version npm downloads License: MIT

Track user activity across your web applications with automatic inactivity detection, cross-tab synchronization, and real-time heartbeat monitoring.


✨ Features

Core Features

  • 🖱️ Activity Detection - Tracks mouse, keyboard, scroll, and touch events
  • ⏱️ Inactivity Monitoring - Automatic detection after configurable timeout (default: 15 minutes)
  • 💓 Heartbeat System - Regular server sync (default: 60 seconds)
  • 🔄 Cross-Tab Sync - Real-time activity sync across browser tabs via BroadcastChannel
  • 🌐 Cross-Domain Support - Server-based sync for different domains
  • 📊 Page Visibility Tracking - Detects when users switch tabs (Page Visibility API)
  • 🎯 Window Focus Tracking - Monitors when users switch to other apps/windows
  • 🔐 JWT Token Support - Automatic JWT decoding to extract userId
  • 🔁 Retry Logic - Automatic retry for failed heartbeats with exponential backoff

Detailed Behavior Tracking

  • 🖱️ Click Tracking - Captures element ID, class, text, xpath, and coordinates
  • 📜 Scroll Tracking - Records scroll depth %, position, and sections viewed
  • 🔗 Navigation Tracking - Monitors page views, time on page, and navigation path
  • 👁️ Viewport Tracking - Tracks visible elements and time in view
  • 📦 Event Batching - Automatically batches events (default: 30 seconds, max 100 events)
  • 🔒 Privacy-First - No PII, truncated text, respects data-no-track attribute

Developer Experience

  • 🔒 TypeScript Support - Full type definitions included
  • Performance Optimized - Debounced events, passive listeners, minimal overhead
  • 🔧 Highly Configurable - 30+ configuration options
  • 📱 Framework Agnostic - Works with React, Vue, Angular, Svelte, vanilla JS
  • 🌐 CDN Support - Drop-in script for no-build-tool projects
  • 📝 Comprehensive Callbacks - 7 lifecycle callbacks for custom logic
  • 🎨 HTML Attributes - Mark elements with data-section, data-track-viewport, data-no-track

📦 Installation

Option 1: NPM Package (For Build Tools)

npm install @vigneshwaranbs/activity-tracker
yarn add @vigneshwaranbs/activity-tracker
pnpm add @vigneshwaranbs/activity-tracker

Option 2: CDN (Drop-in Script - No Build Tools)

Basic Activity Tracking:

<!-- Latest version -->
<script src="https://unpkg.com/@vigneshwaranbs/activity-tracker@latest/dist/activity-tracker-universal.js"></script>

<!-- Access globally as window.activityTracker -->
<script>
  // Tracker auto-starts when page loads
  console.log('Tracker:', window.activityTracker);
</script>

Detailed Behavior Tracking (Single Collection):

<!-- Stores session + events in one collection (user_sessions) -->
<script src="https://unpkg.com/@vigneshwaranbs/activity-tracker@latest/dist/activity-tracker-universal-phase2.js"></script>

<!-- Access globally as window.activityTracker -->
<script>
  console.log('Detailed Tracker:', window.activityTracker);
</script>

Detailed Behavior Tracking (Separate Collections):

<!-- Stores sessions in user_sessions, events in user_activity_events -->
<script src="https://unpkg.com/@vigneshwaranbs/activity-tracker@latest/dist/activity-tracker-universal-userevent.js" 
        data-api-endpoint="https://your-api.com/api/user/activity">
</script>

<!-- Access globally as window.activityTracker -->
<script>
  console.log('Detailed Tracker:', window.activityTracker);
</script>

CDN Usage: Perfect for vanilla HTML, WordPress, legacy apps, or quick prototypes. No npm install needed!


🚀 Quick Start

Three Tracking Options Available

This library offers three tracking options to suit different use cases:

  1. Basic Activity Tracking - Monitor user active/inactive status with heartbeat sync
  2. Detailed Behavior Tracking (Single Collection) - Track clicks, scrolls, navigation in same collection as sessions
  3. Detailed Behavior Tracking (Separate Collections) - Store events in separate collection for better data organization

Method 1: Basic Activity Tracking

Perfect for session management, timeout detection, and presence monitoring.

NPM Installation:

npm install @vigneshwaranbs/activity-tracker

Basic Usage:

import { ActivityTracker } from '@vigneshwaranbs/activity-tracker';

// Initialize tracker
const tracker = new ActivityTracker({
  appId: 'my-app',
  apiEndpoint: 'https://api.yourapp.com/api/user/activity',
  getAuthToken: () => localStorage.getItem('userId') || ''
});

// Start tracking
tracker.start();

// Stop tracking (cleanup)
tracker.stop();

React Example

import { useEffect } from 'react';
import { ActivityTracker } from '@vigneshwaranbs/activity-tracker';

function App() {
  useEffect(() => {
    const tracker = new ActivityTracker({
      appId: 'my-react-app',
      apiEndpoint: 'https://api.yourapp.com/api/user/activity',
      getAuthToken: () => localStorage.getItem('userId') || '',
      
      // Callbacks
      onActive: (data) => {
        console.log('✅ User is active', data);
      },
      onInactive: (data) => {
        console.warn('⚠️ User inactive for', data.inactivityDuration / 60000, 'minutes');
      }
    });

    tracker.start();

    return () => tracker.stop(); // Cleanup on unmount
  }, []);

  return <div>Your App</div>;
}

Vue Example

<script setup>
import { onMounted, onUnmounted } from 'vue';
import { ActivityTracker } from '@vigneshwaranbs/activity-tracker';

let tracker;

onMounted(() => {
  tracker = new ActivityTracker({
    appId: 'my-vue-app',
    apiEndpoint: 'https://api.yourapp.com/api/user/activity',
    getAuthToken: () => localStorage.getItem('userId') || ''
  });
  
  tracker.start();
});

onUnmounted(() => {
  tracker?.stop();
});
</script>

CDN Usage (No Build Tools):

<!DOCTYPE html>
<html>
<head>
    <title>My App</title>
</head>
<body>
    <h1>My Application</h1>
    
    <!-- Step 1: Set JWT token in localStorage (your login code) -->
    <script>
        // After successful login, store JWT token
        localStorage.setItem('authToken', 'eyJhbGci...');
    </script>
    
    <!-- Step 2: Include universal script - appId auto-generated from domain -->
    <script src="https://unpkg.com/@vigneshwaranbs/[email protected]/dist/activity-tracker-universal.js" 
            data-api-endpoint="https://api.yourapp.com/api/user/activity">
    </script>
    
    <!-- That's it! Basic tracking starts automatically -->
    <!-- appId is automatically generated from domain (e.g., www.app.xxxx.com → app.xxxx) -->
</body>
</html>

Auto-Generated AppId:

The tracker automatically generates appId from your domain name:

| Domain | Auto-Generated AppId | |--------|---------------------| | www.app.xxxx.com | app.xxxx | | app.xxxx.com | app.xxxx | | xxxx.com | xxxx | | localhost | localhost |

Override AppId (Optional):

<!-- Manually specify appId if you want a custom name -->
<script src="https://unpkg.com/@vigneshwaranbs/[email protected]/dist/activity-tracker-universal.js" 
        data-app-id="custom-app-name"
        data-api-endpoint="https://api.yourapp.com/api/user/activity">
</script>

Basic Tracking Configuration (CDN):

<!-- All configuration via data attributes -->
<script src="https://unpkg.com/@vigneshwaranbs/[email protected]/dist/activity-tracker-universal.js" 
        data-app-id="my-app" 
        data-api-endpoint="https://api.yourapp.com/api/user/activity"
        data-auth-token-key="authToken"
        data-inactivity-timeout="900000"
        data-heartbeat-interval="60000"
        data-log-level="info">
</script>

Detailed Tracking Configuration (CDN):

<!-- Configuration for detailed tracking -->
<script src="https://unpkg.com/@vigneshwaranbs/[email protected]/dist/activity-tracker-universal-phase2.js" 
        data-app-id="my-app" 
        data-api-endpoint="https://api.yourapp.com/api/user/activity"
        data-events-api-endpoint="https://api.yourapp.com/api/user/activity/events"
        data-auth-token-key="authToken"
        data-track-clicks="true"
        data-track-scrolls="true"
        data-track-navigation="true"
        data-track-viewport="true"
        data-event-batch-interval="30000"
        data-max-events-per-batch="100">
</script>

Or use global config object:

<script>
    window.ACTIVITY_TRACKER_CONFIG = {
        appId: 'my-app',
        apiEndpoint: 'https://api.yourapp.com/api/user/activity',
        authTokenKey: 'authToken',
        inactivityTimeout: 900000,
        heartbeatInterval: 60000,
        
        // For detailed tracking (phase2 script only)
        eventsApiEndpoint: 'https://api.yourapp.com/api/user/activity/events',
        trackClicks: true,
        trackScrolls: true,
        trackNavigation: true,
        trackViewport: true,
        
        // Callbacks
        onActive: function(data) {
            console.log('User is active!', data);
        },
        onInactive: function(data) {
            console.warn('User is inactive!', data);
        }
    };
</script>
<!-- Choose appropriate script -->
<script src="https://unpkg.com/@vigneshwaranbs/[email protected]/dist/activity-tracker-universal-phase2.js"></script>

CDN is perfect for:

  • ✅ Vanilla HTML/CSS/JS projects
  • ✅ WordPress, Shopify, Wix sites
  • ✅ Legacy applications without build tools
  • ✅ Quick prototypes and demos
  • ✅ No npm install or build step needed
  • ✅ Auto-generated appId from domain (no manual configuration needed)


Method 2: Detailed Behavior Tracking

Perfect for analytics, UX optimization, heatmaps, and understanding user behavior.

Features:

  • 🖱️ Click Tracking - Captures element ID, class, text, xpath, and coordinates
  • 📜 Scroll Tracking - Records scroll depth %, position, and sections viewed
  • 🔗 Navigation Tracking - Monitors page views, time on page, and navigation path
  • 👁️ Viewport Tracking - Tracks visible elements and time in view
  • 📦 Event Batching - Automatically batches events (sends every 30 seconds)
  • 🔒 Privacy-First - No PII, truncated text, respects data-no-track attribute
  • Performance Optimized - Debounced events, passive listeners, minimal overhead

NPM Installation:

npm install @vigneshwaranbs/activity-tracker

Usage:

import { DetailedActivityTracker } from '@vigneshwaranbs/activity-tracker';

const tracker = new DetailedActivityTracker({
  // Phase 1 config (required)
  appId: 'my-app',
  apiEndpoint: 'https://api.yourapp.com/api/user/activity',
  authToken: localStorage.getItem('authToken'),
  
  // Phase 2 config (new)
  trackClicks: true,
  trackScrolls: true,
  trackNavigation: true,
  trackViewport: true,
  eventsApiEndpoint: 'https://api.yourapp.com/api/user/activity/events',
  eventBatchInterval: 30000,  // 30 seconds
  maxEventsPerBatch: 100,
  
  // Phase 2 callbacks
  onEventTracked: (event) => {
    console.log('Event tracked:', event);
  },
  onEventBatchSent: (response) => {
    console.log('Batch sent:', response.eventsReceived, 'events');
  }
});

tracker.start();

CDN Usage (No Build Tools):

<!DOCTYPE html>
<html>
<head>
    <title>My App</title>
</head>
<body>
    <h1>My Application</h1>
    
    <!-- Step 1: Set JWT token in localStorage -->
    <script>
        localStorage.setItem('authToken', 'eyJhbGci...');
    </script>
    
    <!-- Step 2: Include universal script - detailed tracking with auto-generated appId -->
    <script src="https://unpkg.com/@vigneshwaranbs/[email protected]/dist/activity-tracker-universal-phase2.js" 
            data-api-endpoint="https://api.yourapp.com/api/user/activity"
            data-events-api-endpoint="https://api.yourapp.com/api/user/activity/events"
            data-track-clicks="true"
            data-track-scrolls="true"
            data-track-navigation="true"
            data-track-viewport="true">
    </script>
    
    <!-- Detailed tracking starts automatically -->
    <!-- appId is auto-generated from domain (e.g., www.app.xxxx.com → app.xxxx) -->
    <!-- To override: add data-app-id="custom-name" -->
</body>
</html>

📊 Event Types

1. Click Events

{
  eventId: "evt-1703456789-abc123",
  eventType: "click",
  timestamp: 1703456789000,
  url: "/products",
  element: "button",
  elementId: "buy-now-btn",
  elementClass: "btn btn-primary",
  text: "Buy Now",
  xpath: "/html/body/div[1]/button",
  x: 350,
  y: 250
}

2. Scroll Events

{
  eventId: "evt-1703456790-def456",
  eventType: "scroll",
  timestamp: 1703456790000,
  url: "/products",
  scrollDepth: 75,  // 75% down page
  scrollPosition: 1200,
  pageHeight: 1600,
  viewportHeight: 800,
  sectionsViewed: ["hero", "features", "pricing"]
}

3. Navigation Events

{
  eventId: "evt-1703456791-ghi789",
  eventType: "navigation",
  timestamp: 1703456791000,
  url: "/checkout",
  fromUrl: "/products",
  toUrl: "/checkout",
  timeOnPage: 45000  // 45 seconds on previous page
}

4. Viewport Events

{
  eventId: "evt-1703456792-jkl012",
  eventType: "viewport",
  timestamp: 1703456792000,
  url: "/products",
  elementsInView: [
    {
      id: "product-card-1",
      class: "product-card",
      tag: "div",
      text: "Premium Product",
      timeInView: 5000  // 5 seconds
    }
  ]
}

🎨 HTML Attributes for Tracking

Track Scroll Sections

<div data-section="hero">
  <!-- Hero content -->
</div>

<div data-section="features">
  <!-- Features content -->
</div>

<div data-section="pricing">
  <!-- Pricing content -->
</div>

When users scroll through these sections, they'll be recorded in sectionsViewed array.

Track Viewport Elements

<div data-track-viewport id="important-content">
  <!-- This element's visibility will be tracked -->
</div>

<div data-track-viewport class="product-card">
  <!-- Track how long users view this product -->
</div>

Elements with data-track-viewport attribute are monitored for visibility and time in view.

Exclude Elements from Tracking

<button data-no-track="true">
  <!-- This button won't be tracked -->
</button>

<div data-no-track="true">
  <!-- Clicks inside this div won't be tracked -->
</div>

🔧 Detailed Tracking Configuration Options

{
  // Feature Flags
  trackClicks?: boolean;           // Enable click tracking (default: true)
  trackScrolls?: boolean;          // Enable scroll tracking (default: true)
  trackNavigation?: boolean;       // Enable navigation tracking (default: true)
  trackViewport?: boolean;         // Enable viewport tracking (default: true)
  
  // API Endpoints
  eventsApiEndpoint?: string;      // Separate endpoint for events
                                   // Default: apiEndpoint + '/events'
  
  // Batching Settings
  eventBatchInterval?: number;     // How often to send events (ms)
                                   // Default: 30000 (30 seconds)
  maxEventsPerBatch?: number;      // Max events per batch
                                   // Default: 100
  
  // Callbacks
  onEventTracked?: (event: ActivityEvent) => void;
  onEventBatchSent?: (response: EventBatchResponse) => void;
  onEventBatchError?: (error: Error) => void;
}

📱 Framework Examples - Detailed Tracking

React with Detailed Tracking

import { useEffect } from 'react';
import { DetailedActivityTracker } from '@vigneshwaranbs/activity-tracker';

function App() {
  useEffect(() => {
    const tracker = new DetailedActivityTracker({
      appId: 'my-react-app',
      apiEndpoint: 'https://api.yourapp.com/api/user/activity',
      eventsApiEndpoint: 'https://api.yourapp.com/api/user/activity/events',
      authToken: localStorage.getItem('authToken'),
      
      // Enable all Phase 2 features
      trackClicks: true,
      trackScrolls: true,
      trackNavigation: true,
      trackViewport: true,
      
      // Callbacks
      onEventTracked: (event) => {
        // Send to analytics
        if (event.eventType === 'click') {
          analytics.track('Button Clicked', {
            elementId: event.elementId,
            text: event.text
          });
        }
      }
    });

    tracker.start();
    return () => tracker.stop();
  }, []);

  return (
    <div>
      <div data-section="hero">
        <h1>Welcome</h1>
        <button id="cta-button">Get Started</button>
      </div>
      
      <div data-section="features" data-track-viewport>
        <h2>Features</h2>
        {/* Feature cards */}
      </div>
    </div>
  );
}

Vue with Detailed Tracking

<template>
  <div>
    <div data-section="hero">
      <h1>Welcome</h1>
      <button id="cta-button">Get Started</button>
    </div>
    
    <div data-section="features" data-track-viewport>
      <h2>Features</h2>
    </div>
  </div>
</template>

<script setup>
import { onMounted, onUnmounted } from 'vue';
import { DetailedActivityTracker } from '@vigneshwaranbs/activity-tracker';

let tracker;

onMounted(() => {
  tracker = new DetailedActivityTracker({
    appId: 'my-vue-app',
    apiEndpoint: 'https://api.yourapp.com/api/user/activity',
    eventsApiEndpoint: 'https://api.yourapp.com/api/user/activity/events',
    authToken: localStorage.getItem('authToken'),
    trackClicks: true,
    trackScrolls: true,
    trackNavigation: true,
    trackViewport: true
  });
  
  tracker.start();
});

onUnmounted(() => {
  tracker?.stop();
});
</script>

🔍 Use Cases - Detailed Tracking

1. E-commerce Analytics

Track which products users view, how long they spend on product pages, and which "Add to Cart" buttons they click:

const tracker = new DetailedActivityTracker({
  appId: 'ecommerce-store',
  trackClicks: true,      // Track "Add to Cart", "Buy Now" clicks
  trackScrolls: true,     // See how far users scroll on product pages
  trackViewport: true,    // Track which products are viewed
  
  onEventTracked: (event) => {
    if (event.eventType === 'click' && event.elementId?.includes('add-to-cart')) {
      // User clicked "Add to Cart"
      sendToAnalytics('add_to_cart', { productId: extractProductId(event.url) });
    }
    
    if (event.eventType === 'viewport' && event.elementsInView.length > 0) {
      // Track product impressions
      event.elementsInView.forEach(el => {
        if (el.class?.includes('product-card')) {
          sendToAnalytics('product_view', { productId: el.id });
        }
      });
    }
  }
});

2. Content Engagement

Measure how users engage with blog posts or documentation:

const tracker = new DetailedActivityTracker({
  appId: 'blog',
  trackScrolls: true,     // Measure read depth
  trackNavigation: true,  // Time spent on each article
  
  onEventTracked: (event) => {
    if (event.eventType === 'scroll') {
      // User scrolled to 75% - likely read the article
      if (event.scrollDepth >= 75) {
        sendToAnalytics('article_read', { 
          url: event.url,
          scrollDepth: event.scrollDepth
        });
      }
    }
    
    if (event.eventType === 'navigation') {
      // Track time spent on article
      if (event.timeOnPage > 60000) { // More than 1 minute
        sendToAnalytics('article_engagement', {
          url: event.fromUrl,
          timeSpent: event.timeOnPage
        });
      }
    }
  }
});

3. Form Optimization

Track which form fields users interact with:

<form>
  <input type="text" id="email" placeholder="Email">
  <input type="text" id="phone" placeholder="Phone">
  <button id="submit-form">Submit</button>
</form>

<script>
  const tracker = new DetailedActivityTracker({
    appId: 'signup-form',
    trackClicks: true,
    
    onEventTracked: (event) => {
      if (event.eventType === 'click') {
        if (event.elementId === 'submit-form') {
          // Track form submission
          sendToAnalytics('form_submit');
        }
      }
    }
  });
</script>

🔒 Privacy & Security

Detailed tracking respects user privacy:

  • No PII Captured - Never tracks password inputs, credit card fields
  • Text Truncation - Element text limited to 100 characters
  • Opt-out Support - data-no-track attribute excludes elements
  • No Form Values - Only tracks field interactions, not values
  • GDPR Compliant - Respects user consent and data retention policies

Excluded by Default:

  • <input type="password">
  • <input type="hidden">
  • Elements with data-no-track="true"

📊 Backend Integration - Detailed Tracking

Detailed tracking uses two API endpoints:

Basic Tracking Endpoint (Heartbeat):

POST /api/user/activity

Detailed Tracking Endpoints (Events):

POST /api/user/activity/events    # Stores events in same collection (user_sessions)
POST /api/user/userevent           # Stores events in separate collection (user_activity_events)

Example Backend (Express + MongoDB):

Option 1: Events in Same Collection (/api/user/activity/events):

// Event batching endpoint - stores in user_sessions collection
app.post('/api/user/activity/events', async (req, res) => {
  const { userId, appId, events } = req.body;
  
  // Validate
  if (!userId || !appId || !events || events.length === 0) {
    return res.status(400).json({ success: false, message: 'Invalid request' });
  }
  
  if (events.length > 100) {
    return res.status(400).json({ success: false, message: 'Max 100 events per batch' });
  }
  
  // Append events to user document
  await db.collection('user_sessions').updateOne(
    { userId: new ObjectId(userId), appId },
    { 
      $push: { 
        events: {
          $each: events,
          $slice: -1000  // Keep only last 1000 events
        }
      },
      $set: { updatedAt: new Date() }
    },
    { upsert: true }
  );
  
  res.json({ 
    success: true, 
    eventsReceived: events.length 
  });
});

Option 2: Events in Separate Collection (/api/user/userevent):

// Event batching endpoint - stores in user_activity_events collection
app.post('/api/user/userevent', async (req, res) => {
  const { userId, appId, events, timestamp } = req.body;
  
  // Validate
  if (!userId || !appId || !events || events.length === 0) {
    return res.status(400).json({ success: false, message: 'Invalid request' });
  }
  
  if (events.length > 100) {
    return res.status(400).json({ success: false, message: 'Max 100 events per batch' });
  }
  
  const now = new Date();
  
  // Get last event timestamp
  const lastEventTimestamp = events.length > 0 
    ? new Date(Math.max(...events.map(e => e.timestamp)))
    : now;
  
  // Add receivedAt timestamp to each event
  const eventsWithTimestamps = events.map(event => ({
    ...event,
    timestamp: new Date(event.timestamp),
    receivedAt: now
  }));

  // Store in separate collection
  await db.collection('user_activity_events').updateOne(
    { userId: new ObjectId(userId), appId },
    { 
      $push: { 
        events: {
          $each: eventsWithTimestamps,
          $slice: -1000
        }
      },
      $set: { 
        lastEventActivityTime: lastEventTimestamp,
        updatedAt: now 
      },
      $setOnInsert: { createdAt: now }
    },
    { upsert: true }
  );
  
  res.json({ 
    success: true, 
    eventsReceived: events.length,
    message: 'User events tracked successfully'
  });
});

MongoDB Document Structures:

Collection: user_sessions (Basic tracking + optional events):

{
  _id: ObjectId("..."),
  userId: ObjectId("..."),
  appId: "my-app",
  
  // Basic tracking fields
  isActive: true,
  lastActivityTime: ISODate("2024-12-24T10:30:00Z"),
  lastHeartbeat: ISODate("2024-12-24T10:30:00Z"),
  tabVisible: true,
  windowFocused: true,
  
  // Events array (optional - only if using activity-tracker-universal-phase2.js)
  events: [
    { 
      eventType: "click", 
      element: "button", 
      timestamp: ISODate("2024-12-24T10:30:00Z"),
      receivedAt: ISODate("2024-12-24T10:30:30Z"),
      ... 
    },
    { 
      eventType: "scroll", 
      scrollDepth: 75, 
      timestamp: ISODate("2024-12-24T10:31:00Z"),
      receivedAt: ISODate("2024-12-24T10:31:30Z"),
      ... 
    }
  ],
  
  createdAt: ISODate("2024-12-24T09:00:00Z"),
  updatedAt: ISODate("2024-12-24T10:30:00Z")
}

Collection: user_activity_events (Separate events collection - only if using activity-tracker-universal-userevent.js):

{
  _id: ObjectId("..."),
  userId: ObjectId("..."),
  appId: "my-app",
  
  // Events array
  events: [
    { 
      eventId: "evt-1234567890-abc",
      eventType: "click", 
      element: "button",
      elementId: "submit-btn",
      timestamp: ISODate("2024-12-24T10:30:00Z"),
      receivedAt: ISODate("2024-12-24T10:30:30Z"),
      x: 100,
      y: 200
    },
    { 
      eventId: "evt-1234567891-def",
      eventType: "scroll", 
      scrollDepth: 75,
      scrollY: 500,
      timestamp: ISODate("2024-12-24T10:31:00Z"),
      receivedAt: ISODate("2024-12-24T10:31:30Z")
    },
    { 
      eventId: "evt-1234567892-ghi",
      eventType: "navigation", 
      fromUrl: "/home", 
      toUrl: "/about",
      timeOnPage: 45000,
      timestamp: ISODate("2024-12-24T10:32:00Z"),
      receivedAt: ISODate("2024-12-24T10:32:30Z")
    }
  ],
  
  lastEventActivityTime: ISODate("2024-12-24T10:32:00Z"),
  createdAt: ISODate("2024-12-24T09:00:00Z"),
  updatedAt: ISODate("2024-12-24T10:32:30Z")
}

🎛️ Advanced Usage - Detailed Tracking

Selective Feature Enabling

// Only track clicks and scrolls
const tracker = new DetailedActivityTracker({
  appId: 'my-app',
  trackClicks: true,
  trackScrolls: true,
  trackNavigation: false,  // Disabled
  trackViewport: false     // Disabled
});

Custom Event Handling

const tracker = new DetailedActivityTracker({
  appId: 'my-app',
  trackClicks: true,
  
  onEventTracked: (event) => {
    // Send to multiple analytics platforms
    if (event.eventType === 'click') {
      googleAnalytics.event('click', { elementId: event.elementId });
      mixpanel.track('Button Click', { button: event.text });
      amplitude.logEvent('click', { element: event.element });
    }
  },
  
  onEventBatchSent: (response) => {
    console.log(`✅ Sent ${response.eventsReceived} events to backend`);
  },
  
  onEventBatchError: (error) => {
    console.error('❌ Failed to send events:', error);
    // Retry logic or alert user
  }
});

Force Send Batch

// Manually trigger batch send (useful before page unload)
tracker.forceSendBatch();

// Example: Send batch before user leaves
window.addEventListener('beforeunload', () => {
  tracker.forceSendBatch();
});

Get Current Batch Size

const batchSize = tracker.getBatchSize();
console.log(`Current batch has ${batchSize} events`);

📈 Performance Considerations

Detailed tracking is optimized for production:

  • Debounced Events - Scroll events debounced by 1 second
  • Passive Listeners - Non-blocking event listeners
  • Event Batching - Reduces API calls by 50%
  • Smart Filtering - Only tracks significant scroll changes (5%+)
  • Memory Management - Automatic queue cleanup
  • Minimal Overhead - <1% CPU usage, <50MB memory

Data Volume Estimate (1000 users):

  • Events per user per day: ~5,000
  • Storage per user per day: ~25 MB
  • With 1000-event limit: ~5 MB per user
  • Total: ~5 GB per day (1000 users)

Optimization Tips:

  • Use 90-day data retention (auto-delete old events)
  • Enable only needed features (disable viewport if not needed)
  • Increase eventBatchInterval to reduce API calls
  • Use sampling (track 10% of users for detailed analytics)

🆚 Comparison: Basic vs Detailed Tracking

| Feature | Basic Tracking | Detailed Tracking | |---------|----------------|-------------------| | Active/Inactive Detection | ✅ | ✅ | | Heartbeat to Backend | ✅ | ✅ | | Tab Visibility | ✅ | ✅ | | Window Focus | ✅ | ✅ | | Click Tracking | ❌ | ✅ | | Scroll Tracking | ❌ | ✅ | | Navigation Tracking | ❌ | ✅ | | Viewport Tracking | ❌ | ✅ | | Event Batching | ❌ | ✅ | | Class | ActivityTracker | DetailedActivityTracker | | CDN Script | activity-tracker-universal.js | activity-tracker-universal-phase2.js | | API Endpoints | 1 endpoint | 2 endpoints | | Use Case | Session management, timeouts | Analytics, UX optimization |

Choose Basic Tracking for:

  • ✅ Session timeout management
  • ✅ User presence monitoring
  • ✅ Active/inactive status
  • ✅ Lightweight tracking
  • ✅ Simple analytics

Choose Detailed Tracking for:

  • ✅ E-commerce analytics
  • ✅ Content engagement metrics
  • ✅ UX optimization
  • ✅ A/B testing insights
  • ✅ Heatmap data collection
  • ✅ User behavior analysis

⚙️ Configuration Reference

Basic Tracking Configuration

Required Options

| Option | Type | Description | |--------|------|-------------| | appId | string | Unique identifier for your application | | apiEndpoint | string | API endpoint URL for heartbeat requests | | userId or authToken or getAuthToken | string \| function | User identification |

Optional Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | inactivityTimeout | number | 900000 (15 min) | Time before marking user inactive (ms) | | heartbeatInterval | number | 60000 (1 min) | Interval between heartbeat requests (ms) | | checkInterval | number | 10000 (10 sec) | Interval for checking inactivity (ms) | | crossTabSync | boolean | true | Enable cross-tab activity sync via BroadcastChannel | | serverSync | boolean | true | Enable server heartbeat sync | | trackPageVisibility | boolean | true | Track tab visibility changes (Page Visibility API) | | trackWindowFocus | boolean | true | Track window focus/blur events | | debounceDelay | number | 1000 (1 sec) | Debounce delay for activity events (ms) | | retryAttempts | number | 3 | Number of retry attempts for failed heartbeats | | logLevel | string | 'warn' | Log level: 'debug', 'info', 'warn', 'error', 'none' | | customHeaders | object | {} | Custom HTTP headers for API requests | | metadata | object | {} | Custom metadata to include in heartbeat |

CDN Data Attributes (Basic Tracking)

| Attribute | Type | Default | Description | |-----------|------|---------|-------------| | data-app-id | string | required | Application identifier | | data-api-endpoint | string | required | Heartbeat API endpoint | | data-auth-token-key | string | 'authToken' | localStorage key for auth token | | data-user-id-key | string | 'userId' | localStorage key for user ID | | data-inactivity-timeout | number | 900000 | Inactivity timeout in milliseconds | | data-heartbeat-interval | number | 60000 | Heartbeat interval in milliseconds | | data-check-interval | number | 10000 | Activity check interval in milliseconds | | data-cross-tab-sync | boolean | true | Enable cross-tab sync | | data-server-sync | boolean | true | Enable server sync | | data-track-page-visibility | boolean | true | Track page visibility | | data-track-window-focus | boolean | true | Track window focus | | data-debounce-delay | number | 1000 | Debounce delay in milliseconds | | data-retry-attempts | number | 3 | Retry attempts for failed requests | | data-log-level | string | 'warn' | Log level |

Callbacks

| Callback | Parameters | Description | |----------|------------|-------------| | onActive | (data: ActivityData) => void | Called when user becomes active | | onInactive | (data: InactivityData) => void | Called when user becomes inactive | | onHeartbeatSuccess | (response: HeartbeatResponse) => void | Called on successful heartbeat | | onHeartbeatError | (error: Error) => void | Called on heartbeat failure |


Detailed Tracking Configuration

Additional Options (extends Basic Tracking)

| Option | Type | Default | Description | |--------|------|---------|-------------| | eventsApiEndpoint | string | apiEndpoint + '/events' | Separate endpoint for event batching | | trackClicks | boolean | true | Enable click event tracking | | trackScrolls | boolean | true | Enable scroll event tracking | | trackNavigation | boolean | true | Enable navigation event tracking | | trackViewport | boolean | true | Enable viewport element tracking | | eventBatchInterval | number | 30000 (30 sec) | How often to send event batches (ms) | | maxEventsPerBatch | number | 100 | Maximum events per batch |

CDN Data Attributes (Detailed Tracking)

| Attribute | Type | Default | Description | |-----------|------|---------|-------------| | data-events-api-endpoint | string | apiEndpoint + '/events' | Events API endpoint | | data-track-clicks | boolean | true | Enable click tracking | | data-track-scrolls | boolean | true | Enable scroll tracking | | data-track-navigation | boolean | true | Enable navigation tracking | | data-track-viewport | boolean | true | Enable viewport tracking | | data-event-batch-interval | number | 30000 | Event batch interval in milliseconds | | data-max-events-per-batch | number | 100 | Max events per batch |

Additional Callbacks

| Callback | Parameters | Description | |----------|------------|-------------| | onEventTracked | (event: ActivityEvent) => void | Called when an event is tracked | | onEventBatchSent | (response: EventBatchResponse) => void | Called when batch is sent successfully | | onEventBatchError | (error: Error) => void | Called when batch send fails |


Configuration Examples

Minimal Configuration (NPM)

const tracker = new ActivityTracker({
  appId: 'my-app',
  apiEndpoint: 'https://api.yourapp.com/api/user/activity',
  userId: 'user-123'
});
tracker.start();

Minimal Configuration (CDN)

<script src="https://unpkg.com/@vigneshwaranbs/[email protected]/dist/activity-tracker-universal.js" 
        data-app-id="my-app" 
        data-api-endpoint="https://api.yourapp.com/api/user/activity">
</script>

Full Configuration (NPM)

const tracker = new DetailedActivityTracker({
  // Basic tracking
  appId: 'my-app',
  apiEndpoint: 'https://api.yourapp.com/api/user/activity',
  getAuthToken: () => localStorage.getItem('authToken') || '',
  inactivityTimeout: 600000,      // 10 minutes
  heartbeatInterval: 30000,       // 30 seconds
  checkInterval: 5000,            // 5 seconds
  crossTabSync: true,
  serverSync: true,
  trackPageVisibility: true,
  trackWindowFocused: true,
  debounceDelay: 2000,           // 2 seconds
  retryAttempts: 5,
  logLevel: 'info',
  
  // Detailed tracking
  eventsApiEndpoint: 'https://api.yourapp.com/api/user/activity/events',
  trackClicks: true,
  trackScrolls: true,
  trackNavigation: true,
  trackViewport: true,
  eventBatchInterval: 20000,     // 20 seconds
  maxEventsPerBatch: 50,
  
  // Callbacks
  onActive: (data) => console.log('Active:', data),
  onInactive: (data) => console.warn('Inactive:', data),
  onHeartbeatSuccess: (res) => console.log('Heartbeat:', res),
  onHeartbeatError: (err) => console.error('Error:', err),
  onEventTracked: (event) => console.log('Event:', event),
  onEventBatchSent: (res) => console.log('Batch sent:', res),
  onEventBatchError: (err) => console.error('Batch error:', err)
});
tracker.start();

Full Configuration (CDN)

<script src="https://unpkg.com/@vigneshwaranbs/[email protected]/dist/activity-tracker-universal-phase2.js" 
        data-app-id="my-app" 
        data-api-endpoint="https://api.yourapp.com/api/user/activity"
        data-events-api-endpoint="https://api.yourapp.com/api/user/activity/events"
        data-auth-token-key="authToken"
        data-inactivity-timeout="600000"
        data-heartbeat-interval="30000"
        data-check-interval="5000"
        data-cross-tab-sync="true"
        data-server-sync="true"
        data-track-page-visibility="true"
        data-track-window-focus="true"
        data-debounce-delay="2000"
        data-retry-attempts="5"
        data-log-level="info"
        data-track-clicks="true"
        data-track-scrolls="true"
        data-track-navigation="true"
        data-track-viewport="true"
        data-event-batch-interval="20000"
        data-max-events-per-batch="50">
</script>

📖 Advanced Examples

With Custom Metadata

const tracker = new ActivityTracker({
  appId: 'my-app',
  apiEndpoint: 'https://api.yourapp.com/api/user/activity',
  getAuthToken: () => localStorage.getItem('userId') || '',
  
  // Custom metadata
  metadata: {
    userAgent: navigator.userAgent,
    screenResolution: `${window.screen.width}x${window.screen.height}`,
    timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
    language: navigator.language,
    referrer: document.referrer
  }
});

tracker.start();

With Custom Headers (Authentication)

const tracker = new ActivityTracker({
  appId: 'my-app',
  apiEndpoint: 'https://api.yourapp.com/api/user/activity',
  userId: 'user-123',
  
  // Custom headers for API authentication
  customHeaders: {
    'Authorization': `Bearer ${localStorage.getItem('authToken')}`,
    'X-API-Key': 'your-api-key',
    'X-App-Version': '1.0.0'
  }
});

tracker.start();

With All Callbacks

const tracker = new ActivityTracker({
  appId: 'my-app',
  apiEndpoint: 'https://api.yourapp.com/api/user/activity',
  getAuthToken: () => localStorage.getItem('userId') || '',
  
  // Activity callbacks
  onActive: (data) => {
    console.log('✅ User is active');
    console.log('Last activity:', new Date(data.lastActivityTime));
    // Send to analytics
    analytics.track('user_active', data);
  },
  
  onInactive: (data) => {
    console.warn('⚠️ User inactive');
    console.warn('Duration:', data.inactivityDuration / 60000, 'minutes');
    // Show warning modal
    showInactivityWarning();
  },
  
  onHeartbeatSuccess: (response) => {
    console.log('💓 Heartbeat sent successfully');
    // Handle server response
    if (response.action === 'logout') {
      logout();
    }
  },
  
  onHeartbeatError: (error) => {
    console.error('❌ Heartbeat failed:', error.message);
    // Send to error tracking (e.g., Sentry)
    Sentry.captureException(error);
  }
});

tracker.start();

Development vs Production Config

const isDevelopment = process.env.NODE_ENV === 'development';

const tracker = new ActivityTracker({
  appId: isDevelopment ? 'my-app-dev' : 'my-app',
  apiEndpoint: isDevelopment 
    ? 'http://localhost:4000/api/user/activity'
    : 'https://api.yourapp.com/api/user/activity',
  getAuthToken: () => localStorage.getItem('userId') || '',
  
  // Development: shorter intervals for testing
  inactivityTimeout: isDevelopment ? 2 * 60 * 1000 : 15 * 60 * 1000,
  heartbeatInterval: isDevelopment ? 10 * 1000 : 60 * 1000,
  
  // Development: verbose logging
  logLevel: isDevelopment ? 'debug' : 'warn'
});

tracker.start();

React Custom Hook

// hooks/useActivityTracker.ts
import { useEffect, useState } from 'react';
import { ActivityTracker } from '@vigneshwaranbs/activity-tracker';

export function useActivityTracker(appId: string) {
  const [isActive, setIsActive] = useState(true);
  const [tracker, setTracker] = useState<ActivityTracker | null>(null);

  useEffect(() => {
    const activityTracker = new ActivityTracker({
      appId,
      apiEndpoint: 'https://api.yourapp.com/api/user/activity',
      getAuthToken: () => localStorage.getItem('userId') || '',
      
      onActive: () => setIsActive(true),
      onInactive: () => setIsActive(false)
    });

    activityTracker.start();
    setTracker(activityTracker);

    return () => activityTracker.stop();
  }, [appId]);

  return { isActive, tracker };
}

// Usage
function MyComponent() {
  const { isActive } = useActivityTracker('my-app');
  
  return (
    <div>
      <StatusBadge active={isActive} />
      {!isActive && <InactivityWarning />}
    </div>
  );
}

🔌 Backend API Integration

Expected API Endpoint

Your backend should handle POST requests to the configured apiEndpoint:

Request:

POST /api/user/activity
Content-Type: application/json

{
  "userId": "676966c6c0b4b40f8cc2db9a",
  "appId": "my-app",
  "isActive": true,
  "lastActivityTime": 1703456789000,
  "tabVisible": true,
  "windowFocused": true,
  "metadata": {
    "userAgent": "Mozilla/5.0...",
    "platform": "MacIntel",
    "language": "en-US",
    "screenResolution": "1920x1080",
    "viewport": "1440x900",
    "timezone": "America/New_York",
    "url": "https://app.example.com/dashboard"
  }
}

Response:

{
  "success": true,
  "message": "Activity tracked successfully",
  "activeInOtherApp": false,
  "lastActivityTime": 1703456789000,
  "action": "continue" // or "logout", "warn"
}

Express.js Backend Example

// server.js
import express from 'express';
import { MongoClient, ObjectId } from 'mongodb';

const app = express();
app.use(express.json());

const MONGODB_URI = process.env.MONGODB_URI;
const client = await MongoClient.connect(MONGODB_URI);
const db = client.db('your-database');

app.post('/api/user/activity', async (req, res) => {
  try {
    const { userId, appId, isActive, lastActivityTime, tabVisible, windowFocused, metadata } = req.body;
    
    const now = new Date();
    const sessionData = {
      userId: new ObjectId(userId),
      appId,
      isActive,
      lastActivityTime: new Date(lastActivityTime),
      lastHeartbeat: now,
      tabVisible,
      windowFocused,
      metadata,
      updatedAt: now
    };
    
    // Upsert: one document per userId + appId
    await db.collection('user_sessions').updateOne(
      { userId: new ObjectId(userId), appId },
      { $set: sessionData, $setOnInsert: { createdAt: now } },
      { upsert: true }
    );
    
    res.json({ success: true, message: 'Activity tracked successfully' });
  } catch (error) {
    console.error('Activity tracking error:', error);
    res.status(500).json({ success: false, error: error.message });
  }
});

app.listen(4000, () => console.log('Server running on port 4000'));

MongoDB Schema

// Collection: user_sessions
{
  "_id": ObjectId("..."),
  "userId": ObjectId("676966c6c0b4b40f8cc2db9a"),
  "appId": "my-app",
  "isActive": true,
  "lastActivityTime": ISODate("2024-12-24T10:30:00.000Z"),
  "lastHeartbeat": ISODate("2024-12-24T10:30:00.000Z"),
  "tabVisible": true,
  "windowFocused": true,
  "metadata": {
    "userAgent": "Mozilla/5.0...",
    "platform": "MacIntel",
    "language": "en-US",
    "screenResolution": "1920x1080",
    "viewport": "1440x900",
    "timezone": "America/New_York",
    "url": "https://app.example.com/dashboard"
  },
  "createdAt": ISODate("2024-12-24T09:00:00.000Z"),
  "updatedAt": ISODate("2024-12-24T10:30:00.000Z")
}

// Recommended indexes
db.user_sessions.createIndex({ userId: 1, appId: 1 }, { unique: true });
db.user_sessions.createIndex({ lastActivityTime: -1 });
db.user_sessions.createIndex({ isActive: 1 });
db.user_sessions.createIndex({ updatedAt: -1 });

🎯 Use Cases

1. Session Timeout Management

const tracker = new ActivityTracker({
  appId: 'my-app',
  apiEndpoint: 'https://api.yourapp.com/api/user/activity',
  getAuthToken: () => localStorage.getItem('userId') || '',
  inactivityTimeout: 15 * 60 * 1000, // 15 minutes
  
  onInactive: (data) => {
    // Show warning modal
    showModal({
      title: 'Session Timeout Warning',
      message: `You've been inactive for ${data.inactivityDuration / 60000} minutes. Your session will expire soon.`,
      actions: ['Stay Logged In', 'Logout']
    });
  }
});

2. Multi-Tab Activity Sync

const tracker = new ActivityTracker({
  appId: 'my-app',
  apiEndpoint: 'https://api.yourapp.com/api/user/activity',
  getAuthToken: () => localStorage.getItem('userId') || '',
  crossTabSync: true, // Enable cross-tab sync
  
  onActive: () => {
    // Activity detected in any tab syncs to all tabs
    console.log('User active in this or another tab');
  }
});

3. Analytics Integration

const tracker = new ActivityTracker({
  appId: 'my-app',
  apiEndpoint: 'https://api.yourapp.com/api/user/activity',
  getAuthToken: () => localStorage.getItem('userId') || '',
  
  onActive: (data) => {
    // Track active sessions in analytics
    analytics.track('session_active', {
      userId: data.userId,
      appId: data.appId,
      timestamp: data.lastActivityTime
    });
  },
  
  onInactive: (data) => {
    // Track session end in analytics
    analytics.track('session_inactive', {
      userId: data.userId,
      duration: data.inactivityDuration
    });
  }
});

4. Real-Time User Presence

const tracker = new ActivityTracker({
  appId: 'collaboration-app',
  apiEndpoint: 'https://api.yourapp.com/api/user/activity',
  getAuthToken: () => localStorage.getItem('userId') || '',
  heartbeatInterval: 30 * 1000, // 30 seconds for real-time presence
  
  onHeartbeatSuccess: (response) => {
    // Update UI with active users from server response
    updateActiveUsersList(response.activeUsers);
  }
});

🔍 What Gets Tracked?

Activity Events

  • Mouse: mousedown, mousemove, click
  • Keyboard: keypress, keydown
  • Touch: touchstart (mobile devices)
  • Scroll: scroll (page scrolling)

Browser State

  • Page Visibility: Tab active/hidden (Visibility API)
  • Window Focus: Window focused/blurred
  • Tab Visibility: User switched tabs

Metadata (Optional)

  • User agent
  • Platform (OS)
  • Language
  • Screen resolution
  • Viewport size
  • Timezone
  • Current URL
  • Referrer
  • Custom metadata

🏗️ Architecture

┌─────────────────────────────────────────────────────────┐
│                   Browser Tab 1                         │
│  ActivityTracker Instance                               │
│    ├─ DOM Event Listeners (mouse, keyboard, scroll)     │
│    ├─ BroadcastChannel (cross-tab sync)                 │
│    └─ Heartbeat Timer (60s)                             │
└─────────────────────────────────────────────────────────┘
                          │
                          │ POST /api/user/activity
                          ▼
┌─────────────────────────────────────────────────────────┐
│                   Backend API                           │
│  Express / Next.js / Fastify                            │
│    └─ POST /api/user/activity                           │
└─────────────────────────────────────────────────────────┘
                          │
                          │ Upsert (one doc per user)
                          ▼
┌─────────────────────────────────────────────────────────┐
│                   MongoDB Database                      │
│  Collection: user_sessions                              │
│    └─ { userId, appId, isActive, lastActivityTime }     │
└─────────────────────────────────────────────────────────┘

⚡ Performance

Optimizations

  • Debouncing: Activity events debounced by 1 second (configurable)
  • Passive Listeners: Non-blocking event listeners for scroll/touch
  • Efficient Intervals: Minimal timer overhead
  • Retry Queue: Failed heartbeats queued and retried
  • Cross-Tab Sync: BroadcastChannel for instant sync (no polling)

Benchmarks

  • Memory: ~50KB (minified + gzipped)
  • CPU: < 0.1% average
  • Network: 1 request per 60 seconds (configurable)
  • Event Overhead: < 1ms per debounced event

🛠️ TypeScript Support

Full TypeScript definitions included:

import { 
  ActivityTracker, 
  ActivityTrackerConfig,
  ActivityData,
  InactivityData,
  HeartbeatPayload,
  HeartbeatResponse 
} from '@vigneshwaranbs/activity-tracker';

const config: ActivityTrackerConfig = {
  appId: 'my-app',
  apiEndpoint: 'https://api.yourapp.com/api/user/activity',
  getAuthToken: () => localStorage.getItem('userId') || '',
  inactivityTimeout: 15 * 60 * 1000,
  onActive: (data: ActivityData) => console.log(data),
  onInactive: (data: InactivityData) => console.warn(data)
};

const tracker = new ActivityTracker(config);
tracker.start();

🧪 Testing

Manual Testing

// Create tracker with short timeouts for testing
const tracker = new ActivityTracker({
  appId: 'test-app',
  apiEndpoint: 'http://localhost:4000/api/user/activity',
  userId: 'test-user',
  
  // Short intervals for testing
  inactivityTimeout: 30 * 1000,  // 30 seconds
  heartbeatInterval: 10 * 1000,  // 10 seconds
  checkInterval: 5 * 1000,       // 5 seconds
  
  // Verbose logging
  logLevel: 'debug',
  
  // Test callbacks
  onActive: () => console.log('✅ ACTIVE'),
  onInactive: () => console.log('⚠️ INACTIVE'),
  onHeartbeatSuccess: (res) => console.log('💓 HEARTBEAT', res),
  onHeartbeatError: (err) => console.error('❌ ERROR', err)
});

tracker.start();

// Test inactivity: Stop moving mouse for 30 seconds
// Test heartbeat: Check network tab for POST requests every 10 seconds
// Test cross-tab: Open multiple tabs and check sync

📚 API Reference

Constructor

new ActivityTracker(config: ActivityTrackerConfig)

Methods

| Method | Description | |--------|-------------| | start() | Start tracking user activity | | stop() | Stop tracking and cleanup | | isUserActive() | Check if user is currently active | | getLastActivityTime() | Get timestamp of last activity | | forceHeartbeat() | Manually trigger a heartbeat |

Example

const tracker = new ActivityTracker({ /* config */ });

tracker.start();                        // Start tracking
const active = tracker.isUserActive();  // Check status
const lastTime = tracker.getLastActivityTime(); // Get timestamp
tracker.forceHeartbeat();              // Force sync
tracker.stop();                        // Stop and cleanup

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.


📄 License

MIT © Vigneshwaran BS


🔗 Links

  • NPM Package: https://www.npmjs.com/package/@vigneshwaranbs/activity-tracker
  • GitHub Repository: https://github.com/vigneshwaranbs/activity-tracker
  • Issues: https://github.com/vigneshwaranbs/activity-tracker/issues
  • Author: Vigneshwaran BS

💡 Support

For questions, issues, or feature requests:

  • Email: [email protected]
  • GitHub Issues: https://github.com/vigneshwaranbs/activity-tracker/issues

Made with ❤️ by Vigneshwaran BS