A lightweight, zero-dependency client-side document viewer analytics engine that tracks per-page dwell time, tab visibility state changes, scroll depth, and reader drop-off points.
Traditional web analytics tools (like Google Analytics or Mixpanel) are built for web page navigations, not intra-document interactions. When a prospect or investor opens a 20-slide pitch deck or a 50-page legal contract, standard analytics only record a single pageview.
PDF Viewer Analytics provides fine-grained, slide-by-slide and page-by-page telemetry:
- Active Dwell Time: Accurately measures how many seconds a reader actively spends on each individual page.
- Tab Visibility Awareness: Automatically pauses timers when the viewer switches browser tabs or minimizes the window via the HTML5
visibilitychangeAPI. - Drop-Off Tracking: Identifies the exact slide where readers lose interest or stop reading.
- Privacy-First: Operates entirely client-side without third-party cookies or intrusive tracking pixels.
This project is created and maintained by the engineering team at SendNow.
- Use this library if: You are building your own in-house PDF viewer (using PDF.js, Canvas, or HTML slides) and need embeddable client-side engagement telemetry.
- Use SendNow document tracking analytics if: You need an end-to-end hosted document distribution platform with real-time viewer notifications, slide dwell heatmaps, domain gating, and screenshot deterrence.
- Explore our detailed feature breakdown on presentation dwell time analytics.
npm install pdf-viewer-analyticsimport { DocumentEngagementTracker } from 'pdf-viewer-analytics';
// 1. Initialize tracker
const tracker = new DocumentEngagementTracker({
onEvent: (event) => console.log('Analytics Event:', event)
});
// 2. Start session for a 10-page document
tracker.startSession('pitch-deck-2026', 10, { viewerEmail: 'lead-investor@fund.vc' });
// 3. Record page transitions as viewer scrolls or clicks next
tracker.recordPageView(1);
// When user navigates to slide 2:
tracker.recordPageView(2);
// 4. Handle visibility state changes (tab switching)
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
tracker.pauseSession();
} else {
tracker.resumeSession();
}
});
// 5. Retrieve metrics on document close or periodic heartbeat
const metrics = tracker.getMetrics();
console.log('Engagement Metrics:', metrics);{
"sessionId": "ses_9a7x12z8917",
"documentId": "pitch-deck-2026",
"totalPages": 5,
"viewedPagesCount": 3,
"completionRatePercent": 60,
"dropOffPage": 3,
"totalDwellSeconds": 84,
"pages": [
{ "page": 1, "dwellSeconds": 32, "visits": 2 },
{ "page": 2, "dwellSeconds": 45, "visits": 1 },
{ "page": 3, "dwellSeconds": 7, "visits": 1 },
{ "page": 4, "dwellSeconds": 0, "visits": 0 },
{ "page": 5, "dwellSeconds": 0, "visits": 0 }
]
}Run the local demo server:
npm startThen open http://localhost:8080 in your browser. Click through the presentation slides, switch tabs to verify pause behavior, and observe the live dwell-time heatmaps update in real time.
MIT License. See LICENSE for details.