Skip to main content

Reading Analytics

Comprehensive reading analytics system that tracks progress, sessions, reading speed, and generates personalized insights.

Free Feature

All analytics features are completely FREE!

Overview​

The Analytics system provides:

  • Reading session tracking
  • Progress monitoring
  • Time spent calculation
  • Reading speed analytics
  • Engagement scoring
  • Page heatmaps
  • Personalized insights
  • Export analytics data

Quick Start​

import { AnalyticsManager } from 'react-native-pdf-jsi/src/analytics/AnalyticsManager';
import { useAnalytics } from 'react-native-pdf-jsi/src/analytics/hooks/useAnalytics';

// Using the manager
const manager = new AnalyticsManager();
await manager.initialize();

const analytics = await manager.getAnalytics('my-pdf-id');
console.log('Completion:', analytics.readingMetrics.completionRate + '%');
console.log('Time spent:', analytics.timeAnalytics.totalTimeFormatted);
console.log('Reading speed:', analytics.readingMetrics.pagesPerHour, 'pages/hour');

// Or use the React hook
const { analytics, updateProgress } = useAnalytics('my-pdf-id');

Reading Metrics​

Track key reading statistics:

const analytics = await manager.getAnalytics(pdfId);
const metrics = analytics.readingMetrics;

console.log('Pages read:', metrics.totalPagesRead);
console.log('Total pages:', metrics.totalPages);
console.log('Completion:', metrics.completionRate + '%');
console.log('Pages per hour:', metrics.pagesPerHour);
console.log('Minutes per page:', metrics.minutesPerPage);
console.log('Reading speed:', metrics.wordsPerMinute, 'WPM');
console.log('Est. total time:', metrics.estimatedTotalTime);
console.log('Est. remaining:', metrics.estimatedTimeRemaining);

Reading Metrics Object:

{
pagesPerHour: number;
minutesPerPage: number;
completionRate: number; // 0-100
wordsPerMinute: number; // Estimated WPM
totalPagesRead: number;
totalPages: number;
timeSpent: number; // Seconds
estimatedTotalTime: number; // Seconds
estimatedTimeRemaining: number; // Seconds
}

Time Analytics​

Detailed time tracking:

const timeAnalytics = analytics.timeAnalytics;

console.log('Total time:', timeAnalytics.totalTimeFormatted); // "2h 30m"
console.log('Session count:', timeAnalytics.totalSessions);
console.log('Avg session:', timeAnalytics.avgSessionDuration, 'minutes');
console.log('Last session:', new Date(timeAnalytics.lastSession));
console.log('Reading streak:', timeAnalytics.readingStreak, 'days');

Time Analytics Object:

{
totalTime: number; // Seconds
totalTimeFormatted: string; // "2h 30m 15s"
totalSessions: number;
avgSessionDuration: number; // Minutes
longestSession: number; // Minutes
shortestSession: number; // Minutes
lastSession: number; // Timestamp
readingStreak: number; // Days
timeDistribution: object; // Hour-by-hour breakdown
}

Engagement Metrics​

Measure user engagement with the document:

const engagement = analytics.engagementMetrics;

console.log('Total bookmarks:', engagement.totalBookmarks);
console.log('Bookmarked pages:', engagement.uniqueBookmarkedPages);
console.log('Bookmark rate:', engagement.bookmarkRate + '%');
console.log('Engagement score:', engagement.engagementScore, '/100');

Engagement Score Calculation:

  • Completion contributes 40 points
  • Bookmarks contribute 30 points
  • Session frequency contributes 30 points
  • Total: 0-100

Page Analytics​

Analyze reading patterns and page access:

const pageAnalytics = analytics.pageAnalytics;

// Most bookmarked pages
pageAnalytics.mostBookmarkedPages.forEach(p => {
console.log(`Page ${p.page}: ${p.bookmarks} bookmarks`);
});

// Reading gaps (unread sections)
pageAnalytics.readingGaps.forEach(gap => {
console.log(`Unread: pages ${gap.start}-${gap.end}`);
});

// Reading pattern
console.log('Pattern:', pageAnalytics.readingPattern);
// "sequential", "random", "chapter-by-chapter", etc.

// Page heatmap
Object.entries(pageAnalytics.heatmap).forEach(([page, count]) => {
console.log(`Page ${page}: visited ${count} times`);
});

Insights Generation​

Get personalized reading insights:

const insights = analytics.insights;

insights.forEach(insight => {
console.log(`[${insight.type}] ${insight.title}`);
console.log(` ${insight.message}`);
console.log(` Priority: ${insight.priority}`);
});

Insight Types:

  • completion - Progress-based insights
  • speed - Reading speed insights
  • engagement - Engagement insights
  • pattern - Reading pattern insights
  • recommendation - Personalized recommendations

Example Insights:

[completion] Great Progress!
You've completed 75% of this document.
Priority: high

[speed] Fast Reader
Your reading speed is above average at 280 WPM.
Priority: medium

[engagement] Active Learner
You've created 15 bookmarks - excellent engagement!
Priority: high

Complete Example: Analytics Dashboard​

import React, { useState, useEffect } from 'react';
import { View, Text, ScrollView, RefreshControl } from 'react-native';
import { useAnalytics } from 'react-native-pdf-jsi/src/analytics/hooks/useAnalytics';

const AnalyticsDashboard = ({ pdfId }) => {
const { analytics, loading, error, refresh } = useAnalytics(pdfId);

if (loading) {
return <ActivityIndicator size="large" />;
}

if (error) {
return <Text>Error loading analytics</Text>;
}

if (!analytics) {
return <Text>No analytics data available</Text>;
}

const { readingMetrics, engagementMetrics, timeAnalytics, insights } = analytics;

return (
<ScrollView
style={{ flex: 1 }}
refreshControl={
<RefreshControl refreshing={loading} onRefresh={refresh} />
}
>
{/* Progress Overview */}
<View style={{ padding: 20, backgroundColor: '#6366F1' }}>
<Text style={{ color: 'white', fontSize: 24, fontWeight: 'bold' }}>
{readingMetrics.completionRate}%
</Text>
<Text style={{ color: 'white' }}>Complete</Text>
<Text style={{ color: 'white', marginTop: 10 }}>
{readingMetrics.totalPagesRead} of {readingMetrics.totalPages} pages
</Text>
</View>

{/* Reading Stats */}
<View style={{ padding: 20 }}>
<Text style={{ fontSize: 18, fontWeight: 'bold', marginBottom: 15 }}>
Reading Statistics
</Text>

<StatCard
label="Time Spent"
value={timeAnalytics.totalTimeFormatted}
icon="⏱️"
/>
<StatCard
label="Reading Speed"
value={`${readingMetrics.pagesPerHour} pages/hour`}
icon="⚡"
/>
<StatCard
label="Sessions"
value={timeAnalytics.totalSessions}
icon="📚"
/>
<StatCard
label="Bookmarks"
value={engagementMetrics.totalBookmarks}
icon="🔖"
/>
</View>

{/* Insights */}
<View style={{ padding: 20 }}>
<Text style={{ fontSize: 18, fontWeight: 'bold', marginBottom: 15 }}>
Insights
</Text>

{insights.slice(0, 3).map((insight, index) => (
<View
key={index}
style={{
padding: 15,
marginBottom: 10,
backgroundColor: '#f5f5f5',
borderRadius: 8,
borderLeftWidth: 4,
borderLeftColor: getPriorityColor(insight.priority)
}}
>
<Text style={{ fontWeight: 'bold' }}>{insight.title}</Text>
<Text style={{ color: '#666', marginTop: 5 }}>{insight.message}</Text>
</View>
))}
</View>

{/* Most Bookmarked Pages */}
{analytics.pageAnalytics.mostBookmarkedPages.length > 0 && (
<View style={{ padding: 20 }}>
<Text style={{ fontSize: 18, fontWeight: 'bold', marginBottom: 15 }}>
Most Bookmarked Pages
</Text>

{analytics.pageAnalytics.mostBookmarkedPages.map((page, index) => (
<View
key={index}
style={{
flexDirection: 'row',
justifyContent: 'space-between',
padding: 10,
marginBottom: 5,
backgroundColor: '#f9f9f9',
borderRadius: 5
}}
>
<Text>Page {page.page}</Text>
<Text style={{ color: '#6366F1', fontWeight: 'bold' }}>
{page.bookmarks} bookmarks
</Text>
</View>
))}
</View>
)}
</ScrollView>
);
};

const StatCard = ({ label, value, icon }) => (
<View style={{
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
padding: 15,
marginBottom: 10,
backgroundColor: '#f9f9f9',
borderRadius: 8
}}>
<View>
<Text style={{ fontSize: 12, color: '#666' }}>{label}</Text>
<Text style={{ fontSize: 18, fontWeight: 'bold', marginTop: 5 }}>
{value}
</Text>
</View>
<Text style={{ fontSize: 30 }}>{icon}</Text>
</View>
);

const getPriorityColor = (priority) => {
switch (priority) {
case 'high': return '#FF6B6B';
case 'medium': return '#FFD93D';
case 'low': return '#4ECDC4';
default: return '#999';
}
};

export default AnalyticsDashboard;

useAnalytics Hook​

React hook for easy analytics integration:

import { useAnalytics } from 'react-native-pdf-jsi/src/analytics/hooks/useAnalytics';

const MyComponent = ({ pdfId }) => {
const {
analytics,
loading,
error,
refresh,
updateProgress,
trackSession
} = useAnalytics(pdfId, {
autoRefresh: true, // Auto-refresh every 30 seconds
refreshInterval: 30000
});

// Update progress on page change
const handlePageChange = (page, totalPages) => {
updateProgress({ currentPage: page, totalPages });
};

// Track reading session
useEffect(() => {
trackSession('start');
return () => trackSession('end');
}, []);

return (
<View>
{analytics && (
<Text>
Reading: {analytics.readingMetrics.completionRate}% complete
</Text>
)}
</View>
);
};

Export Analytics​

Export analytics data for external analysis:

const exportData = await manager.exportAnalytics('my-pdf-id');

console.log('Export data:', exportData);
// Can be saved to file, sent to server, etc.

// Save to file
import RNFS from 'react-native-fs';

const exportPath = `${RNFS.DocumentDirectoryPath}/analytics.json`;
await RNFS.writeFile(exportPath, JSON.stringify(exportData, null, 2));

console.log('Analytics exported to:', exportPath);

Reading Predictions​

Get predictions based on current reading patterns:

const predictions = analytics.predictions;

console.log('Estimated finish date:', predictions.estimatedFinishDate);
console.log('Estimated remaining time:', predictions.estimatedRemainingTime);
console.log('Optimal reading schedule:', predictions.suggestedSchedule);

Predictions Object:

{
estimatedFinishDate: string; // ISO date
estimatedRemainingTime: number; // Minutes
suggestedPagesPerDay: number;
suggestedSchedule: string; // "Read 15 pages/day for 10 days"
}

Real-Time Progress Tracking​

Track progress as user reads:

import { BookmarkManager } from 'react-native-pdf-jsi/src/bookmarks/BookmarkManager';

const PDFReader = ({ pdfId }) => {
const [currentPage, setCurrentPage] = useState(1);
const [sessionStart] = useState(Date.now());
const manager = new BookmarkManager();

const handlePageChange = async (page, totalPages) => {
setCurrentPage(page);

// Calculate time spent
const timeSpent = Math.floor((Date.now() - sessionStart) / 1000);

// Update progress
await manager.updateProgress(pdfId, {
currentPage: page,
totalPages: totalPages,
lastReadAt: Date.now()
});

// Update session
await manager.updateSession(pdfId, {
duration: timeSpent,
pagesRead: page
});
};

return (
<Pdf
source={{ uri: pdfPath }}
onPageChanged={(page, total) => handlePageChange(page, total)}
style={{ flex: 1 }}
/>
);
};

Session Tracking​

Track individual reading sessions:

// Start session
const sessionId = await manager.startSession(pdfId);

// Update session during reading
await manager.updateSession(pdfId, {
duration: timeElapsed,
pagesRead: currentPage
});

// End session
await manager.endSession(pdfId, sessionId);

// Get session history
const sessions = await manager.getSessions(pdfId);

sessions.forEach(session => {
console.log('Session on:', new Date(session.startTime));
console.log('Duration:', session.duration, 'seconds');
console.log('Pages read:', session.pagesRead);
});

Engagement Score​

Get engagement score (0-100):

const engagementMetrics = analytics.engagementMetrics;

console.log('Engagement score:', engagementMetrics.engagementScore, '/100');
console.log('Total bookmarks:', engagementMetrics.totalBookmarks);
console.log('Bookmark rate:', engagementMetrics.bookmarkRate + '%');

Score Breakdown:

  • 40 points: Reading completion (0-100%)
  • 30 points: Bookmark usage (more bookmarks = higher score)
  • 30 points: Session frequency (regular reading sessions)

Interpretation:

  • 80-100: Highly engaged reader
  • 60-79: Moderately engaged
  • 40-59: Casual reader
  • 0-39: Low engagement

Page Heatmap​

Visualize page access frequency:

const heatmap = analytics.pageAnalytics.heatmap;

// Heatmap: { page: visitCount }
// { 1: 5, 5: 3, 10: 8, ... }

// Find most visited pages
const mostVisited = Object.entries(heatmap)
.sort((a, b) => b[1] - a[1])
.slice(0, 5);

mostVisited.forEach(([page, count]) => {
console.log(`Page ${page}: visited ${count} times`);
});

Reading Pattern Analysis​

Identify reading patterns:

const pattern = analytics.pageAnalytics.readingPattern;

console.log('Reading pattern:', pattern);
// Possible values:
// - "sequential" - Reading in order
// - "random" - Jumping around
// - "chapter-by-chapter" - Reading by sections
// - "selective" - Reading specific pages

Reading Gaps​

Find unread sections:

const gaps = analytics.pageAnalytics.readingGaps;

gaps.forEach(gap => {
console.log(`Unread section: pages ${gap.start} to ${gap.end}`);
console.log(` Pages: ${gap.pages.length}`);
});

// Suggest reading gaps to user
if (gaps.length > 0) {
Alert.alert(
'Unread Sections',
`You have ${gaps.length} unread sections. Would you like to continue reading?`
);
}

Complete Analytics Example​

Full implementation with all features:

import React, { useState, useEffect } from 'react';
import { View, Text, ScrollView } from 'react-native';
import { AnalyticsManager } from 'react-native-pdf-jsi/src/analytics/AnalyticsManager';
import { CircularProgress, StatCard } from 'react-native-pdf-jsi/src/analytics/components/SimpleCharts';

const ComprehensiveAnalytics = ({ pdfId }) => {
const [analytics, setAnalytics] = useState(null);
const [manager] = useState(() => new AnalyticsManager());

useEffect(() => {
loadAnalytics();
const interval = setInterval(loadAnalytics, 30000); // Refresh every 30s
return () => clearInterval(interval);
}, [pdfId]);

const loadAnalytics = async () => {
try {
await manager.initialize();
const data = await manager.getAnalytics(pdfId);
setAnalytics(data);
} catch (error) {
console.error('Analytics error:', error);
}
};

if (!analytics) {
return <Text>Loading analytics...</Text>;
}

const { readingMetrics, timeAnalytics, engagementMetrics, insights } = analytics;

return (
<ScrollView style={{ flex: 1, backgroundColor: '#f5f5f5' }}>
{/* Progress Ring */}
<View style={{ alignItems: 'center', padding: 30, backgroundColor: 'white' }}>
<CircularProgress
percentage={readingMetrics.completionRate}
size={150}
strokeWidth={12}
color="#6366F1"
/>
<Text style={{ marginTop: 20, fontSize: 24, fontWeight: 'bold' }}>
{readingMetrics.completionRate}% Complete
</Text>
<Text style={{ color: '#666' }}>
{readingMetrics.totalPagesRead} of {readingMetrics.totalPages} pages
</Text>
</View>

{/* Stats Grid */}
<View style={{ padding: 20 }}>
<View style={{ flexDirection: 'row', flexWrap: 'wrap' }}>
<StatCard
label="Time Spent"
value={timeAnalytics.totalTimeFormatted}
icon="⏱️"
style={{ width: '48%', margin: '1%' }}
/>
<StatCard
label="Reading Speed"
value={`${readingMetrics.pagesPerHour}/hr`}
icon="⚡"
style={{ width: '48%', margin: '1%' }}
/>
<StatCard
label="Sessions"
value={timeAnalytics.totalSessions}
icon="📚"
style={{ width: '48%', margin: '1%' }}
/>
<StatCard
label="Engagement"
value={`${engagementMetrics.engagementScore}/100`}
icon="🎯"
style={{ width: '48%', margin: '1%' }}
/>
</View>
</View>

{/* Insights */}
<View style={{ padding: 20 }}>
<Text style={{ fontSize: 18, fontWeight: 'bold', marginBottom: 15 }}>
Insights
</Text>

{insights.map((insight, index) => (
<View
key={index}
style={{
padding: 15,
marginBottom: 10,
backgroundColor: 'white',
borderRadius: 8,
borderLeftWidth: 4,
borderLeftColor: getPriorityColor(insight.priority)
}}
>
<Text style={{ fontWeight: 'bold', marginBottom: 5 }}>
{insight.title}
</Text>
<Text style={{ color: '#666' }}>{insight.message}</Text>
</View>
))}
</View>

{/* Most Bookmarked Pages */}
{analytics.pageAnalytics.mostBookmarkedPages.length > 0 && (
<View style={{ padding: 20 }}>
<Text style={{ fontSize: 18, fontWeight: 'bold', marginBottom: 15 }}>
Most Bookmarked
</Text>

{analytics.pageAnalytics.mostBookmarkedPages.map((page, index) => (
<View
key={index}
style={{
flexDirection: 'row',
justifyContent: 'space-between',
padding: 15,
marginBottom: 5,
backgroundColor: 'white',
borderRadius: 5
}}
>
<Text>Page {page.page}</Text>
<Text style={{ color: '#6366F1', fontWeight: 'bold' }}>
{page.bookmarks} bookmarks
</Text>
</View>
))}
</View>
)}
</ScrollView>
);
};

const getPriorityColor = (priority) => {
const colors = {
high: '#FF6B6B',
medium: '#FFD93D',
low: '#4ECDC4'
};
return colors[priority] || '#999';
};

export default ComprehensiveAnalytics;

Export Analytics Data​

const exportedData = await manager.exportAnalytics('my-pdf-id');

// Exported data includes all analytics
const data = {
pdfId: 'my-pdf-id',
readingMetrics: { ... },
timeAnalytics: { ... },
engagementMetrics: { ... },
pageAnalytics: { ... },
insights: [ ... ],
bookmarks: [ ... ],
sessions: [ ... ],
exportedAt: '2025-01-06T...'
};

// Use for:
// - Backup
// - Cloud sync
// - External analysis
// - Sharing with study groups

Best Practices​

1. Initialize Once​

const [manager] = useState(() => new AnalyticsManager());

useEffect(() => {
manager.initialize();
}, []);

2. Update Progress Frequently​

// Update on every page change
onPageChanged={(page, total) => {
manager.updateProgress(pdfId, { currentPage: page, totalPages: total });
}}

3. Track Sessions​

useEffect(() => {
manager.startSession(pdfId);
return () => manager.endSession(pdfId);
}, [pdfId]);

4. Refresh Analytics Periodically​

useEffect(() => {
const interval = setInterval(() => {
refresh();
}, 30000); // Every 30 seconds
return () => clearInterval(interval);
}, []);

See Also​