@edtechimpact/edtech-analytics-plugin
v1.0.5
Published
Educational analytics plugin for @analytics/core with privacy-first browser interaction recording
Maintainers
Readme
@edtechimpact/edtech-analytics-plugin
Educational analytics plugin for @analytics/core with privacy-first browser interaction recording designed specifically for EdTech applications.
🎯 Features
- 📚 Learning-focused tracking - Question attempts, video interactions, help requests
- 🔒 Privacy-first design - FERPA/COPPA compliant data handling
- ⚡ Real-time insights - Struggle detection and engagement monitoring
- 📊 xAPI compatible - Export to Learning Record Stores
- 🎨 Auto-tracking - Clicks, forms, scrolling, focus events
- 📱 Cross-platform - Works on web, mobile web, and hybrid apps
- 🔧 Zero dependencies - Lightweight and performant
🚀 Installation
npm install @edtechimpact/edtech-analytics-plugin analytics📖 Quick Start
import Analytics from 'analytics'
import edTechPlugin from '@edtechimpact/edtech-analytics-plugin'
// Initialize analytics with EdTech plugin
const analytics = Analytics({
app: 'my-learning-app',
plugins: [
edTechPlugin({
endpoint: '/api/analytics/events',
studentId: 'student_123',
privacyMode: true
})
]
})
// Standard analytics methods work automatically
analytics.page('Math Lesson 1')
analytics.track('lesson_started', { topic: 'algebra' })
// Use EdTech-specific methods
analytics.recordQuestionAttempt('q1', 'x=5', true, 30000)
analytics.recordVideoInteraction('intro-video', 'play', 45, 120)
analytics.recordHelpRequest('hint', { questionId: 'q1' })⚙️ Configuration
edTechPlugin({
// Required: Your analytics endpoint
endpoint: '/api/analytics/events',
// Student identification
studentId: 'student_123', // or function: () => getCurrentStudentId()
// Privacy settings
privacyMode: true, // Don't record sensitive text content
// Performance settings
bufferSize: 50, // Events to buffer before sending
flushInterval: 5000, // Send events every 5 seconds
// Auto-tracking toggles
autoTrackClicks: true, // Track all click interactions
autoTrackForms: true, // Track form inputs and submissions
autoTrackScrolling: true, // Track scroll behavior
autoTrackEngagement: true, // Track focus/blur events
// EdTech features
enableLearningEvents: true, // Learning-specific event tracking
enableStruggleDetection: true, // Automatic frustration detection
enableRealTimeAlerts: false, // Real-time teacher notifications
// Debug mode
debug: false // Enable console logging
})📚 API Reference
Standard Analytics Methods
These work automatically with the plugin:
// Page tracking
analytics.page('Lesson Title', { topic: 'algebra', difficulty: 2 })
// Custom event tracking
analytics.track('custom_event', { property: 'value' })
// User identification
analytics.identify('student_123', { grade: '8th', school: 'Demo School' })EdTech-Specific Methods
Access via analytics.plugins.edtechAnalytics:
recordQuestionAttempt(questionId, answer, isCorrect, timeSpent, metadata?)
analytics.recordQuestionAttempt(
'algebra_q1', // Question identifier
'x = 5', // Student's answer
true, // Whether correct
30000, // Time spent in milliseconds
{ // Optional metadata
concept: 'linear_equations',
difficulty: 2,
attempts: 1
}
)recordVideoInteraction(videoId, action, currentTime, duration, metadata?)
analytics.recordVideoInteraction(
'intro_video', // Video identifier
'pause', // Action: play, pause, seek, complete
45, // Current timestamp
120, // Total duration
{ lessonId: 'math_101' } // Optional metadata
)recordHelpRequest(type, context, metadata?)
analytics.recordHelpRequest(
'hint', // Help type: hint, explanation, example
{ questionId: 'q1' }, // Context information
{ attemptNumber: 2 } // Optional metadata
)recordProgressMilestone(milestone, level, score, metadata?)
analytics.recordProgressMilestone(
'level_complete', // Milestone type
'algebra_basics', // Level/unit identifier
85, // Score achieved
{ totalTime: 1800000 } // Optional metadata
)Control Methods
// Get current session information
const stats = analytics.getSessionStats()
// Returns: { sessionId, duration, eventCount, lastActivity, isRecording }
// Control recording
analytics.startRecording()
analytics.stopRecording()
// Manual event flushing
analytics.flushEvents()🎭 HTML Data Attributes
Enhance automatic tracking by adding educational context to your HTML:
<!-- Question context -->
<div data-question-id="q1"
data-concept-id="algebra"
data-difficulty="2"
data-lesson-id="math_101">
<p>Solve for x: 2x + 5 = 13</p>
<!-- Answers are automatically tracked -->
<input type="radio" name="q1" value="4"> x = 4
<!-- Action buttons -->
<button onclick="submitAnswer()">Submit</button>
<button onclick="getHint()" data-action="help">Need Help?</button>
</div>
<!-- Video context -->
<div data-video-id="intro-video" data-lesson-id="algebra-101">
<!-- Video player controls are automatically tracked -->
<video controls>...</video>
</div>📡 Event Data Structure
Events sent to your endpoint:
{
"sessionId": "session_1642089600000_abc123",
"events": [
{
"type": "learning_event",
"eventType": "question_attempt",
"timestamp": 15000,
"sessionId": "session_1642089600000_abc123",
"url": "/math-lesson-1",
"questionId": "q1",
"isCorrect": true,
"timeSpent": 30000,
"concept": "algebra",
"difficulty": 2
},
{
"type": "click",
"timestamp": 16000,
"element": {
"tagName": "button",
"questionId": "q1"
},
"coordinates": { "x": 245, "y": 180 }
}
],
"metadata": {
"totalEvents": 2,
"sessionDuration": 16000,
"lastActivity": 1642089616000,
"flushReason": "periodic"
}
}🔐 Privacy & Compliance
This plugin is designed for educational environments with strict privacy requirements:
- FERPA Compliant - No personally identifiable information in events
- COPPA Safe - Appropriate for users under 13
- Privacy Mode - Sensitive content is never recorded
- Data Minimization - Only educationally relevant interactions tracked
- Anonymization - Student answers can be hashed instead of stored
- Consent Aware - Respects do-not-track and privacy preferences
Privacy Configuration
edTechPlugin({
privacyMode: true, // Enable privacy protections
hashAnswers: true, // Hash student answers
respectDoNotTrack: true, // Honor DNT header
anonymizeIPs: true, // Don't send IP addresses
dataRetention: '2-years', // Automatic data expiration
consentRequired: false // Wait for explicit consent
})🔄 xAPI Integration
Export events as xAPI statements for Learning Record Stores:
// Get xAPI statements
const xapiStatements = analytics.exportToXAPI()
// Send to LRS
await fetch('https://lrs.school.edu/statements', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic ' + btoa('username:password'),
'X-Experience-API-Version': '1.0.3'
},
body: JSON.stringify(xapiStatements)
})📊 Real-time Analytics
The plugin automatically detects learning patterns:
// Struggle detection
analytics.on('struggle_detected', (data) => {
console.log('Student needs help:', data)
// { type: 'rapid_clicking', studentId: '123', indicators: {...} }
})
// Engagement monitoring
analytics.on('engagement_low', (data) => {
console.log('Student may be disengaged:', data)
})
// Mastery indicators
analytics.on('mastery_achieved', (data) => {
console.log('Student showing mastery:', data)
})🏗️ Backend Integration
Express.js Example
const express = require('express')
const app = express()
app.post('/api/analytics/events', (req, res) => {
const { sessionId, events, metadata } = req.body
// Process educational events
events.forEach(event => {
if (event.type === 'learning_event') {
// Store learning data
saveLearningEvent(event)
// Check for interventions needed
if (event.eventType === 'question_attempt' && !event.isCorrect) {
checkForStruggle(event.sessionId)
}
}
})
res.json({ success: true, eventsProcessed: events.length })
})Database Schema Example
-- Events table
CREATE TABLE learning_events (
id SERIAL PRIMARY KEY,
session_id VARCHAR(100) NOT NULL,
student_id VARCHAR(100) NOT NULL,
event_type VARCHAR(50) NOT NULL,
timestamp BIGINT NOT NULL,
question_id VARCHAR(100),
is_correct BOOLEAN,
time_spent INTEGER,
concept VARCHAR(100),
difficulty INTEGER,
metadata JSONB,
created_at TIMESTAMP DEFAULT NOW()
);
-- Indexes for performance
CREATE INDEX idx_learning_events_student_id ON learning_events(student_id);
CREATE INDEX idx_learning_events_session_id ON learning_events(session_id);
CREATE INDEX idx_learning_events_question_id ON learning_events(question_id);🎨 React Integration
import { useEffect } from 'react'
import Analytics from 'analytics'
import edTechPlugin from '@edtechimpact/edtech-analytics-plugin'
// Initialize once at app level
const analytics = Analytics({
app: 'my-react-app',
plugins: [
edTechPlugin({
endpoint: '/api/analytics/events',
studentId: () => getCurrentUser().id
})
]
})
// Question component
function MathQuestion({ questionId, concept, difficulty }) {
const handleSubmit = (answer, isCorrect, timeSpent) => {
analytics.recordQuestionAttempt(
questionId,
answer,
isCorrect,
timeSpent,
{ concept, difficulty }
)
}
return (
<div data-question-id={questionId}
data-concept-id={concept}
data-difficulty={difficulty}>
{/* Question content */}
</div>
)
}🧪 Testing
The plugin includes comprehensive tests:
npm test # Run all tests
npm run test:watch # Run tests in watch mode
npm run test:coverage # Generate coverage report🤝 Contributing
We welcome contributions! Please read our Contributing Guide for details.
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Commit changes:
git commit -m 'Add amazing feature' - Push to branch:
git push origin feature/amazing-feature - Open a Pull Request
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🔗 Links
🙋 Support
Made with ❤️ for educators and learners everywhere.
