Generate Your First Report
Generate Your First Report
Learn how to generate reports, view analytics, and export learner progress data.
Table of Contents
- Overview
- Prerequisites
- Report Types
- Generating Reports
- Exporting Data
- Custom Reports
- Common Scenarios
- Troubleshooting
Overview
The SCORM API provides comprehensive reporting capabilities to track learner progress, completion rates, scores, and time spent. Reports are available via:
- Customer Routes (
/api/customer/reports/*) - For web application users (Clerk authentication) - API Routes (
/api/v1/*) - For programmatic access (API key authentication)
Prerequisites
- API key with
readscope (for API routes) - OR Clerk authentication (for customer routes)
- At least one completed session
Report Types
1. Learner Progress Report
Shows completion rates, scores, and time spent per package.
2. Custom Reports
Flexible reports with custom filters, date ranges, and visualizations.
3. Session Reports
Detailed session-level data with CMI information.
Generating Reports
Method 1: Learner Progress Report (Customer Route)
For web application users authenticated via Clerk:
const response = await fetch('/api/customer/reports/learner-progress?range=30d', {
credentials: 'include', // Include Clerk session cookie
});
const data = await response.json();
Query Parameters:
range(optional): Time range7d- Last 7 days (default)30d- Last 30 days90d- Last 90 daysall- All time
Response:
{
"packages": [
{
"package_id": "pkg_abc123",
"package_title": "Introduction to Safety Training",
"total_sessions": 25,
"completed_sessions": 18,
"completion_rate": 72.0,
"avg_time_spent_seconds": 1250,
"avg_score": 0.85,
"passed": 15,
"failed": 3,
"unknown": 7
}
],
"summary": {
"total_packages": 5,
"total_sessions": 125,
"total_completed": 90,
"overall_completion_rate": 72.0,
"avg_time_spent_seconds": 1180
}
}
Method 2: List Sessions (API Route)
For programmatic access with API keys:
curl -X GET "https://scorm-api.allurelms.com/api/v1/sessions?package_id=pkg_abc123&completion_status=completed" \
-H "X-API-Key: your-api-key-here"
Query Parameters:
package_id(optional) - Filter by packageuser_id(optional) - Filter by usercompletion_status(optional) - Filter by status (not_attempted,incomplete,completed)success_status(optional) - Filter by success (unknown,passed,failed)page(optional) - Page number (default: 1)limit(optional) - Results per page (default: 20, max: 100)
Response:
{
"sessions": [
{
"id": "session-789",
"package_id": "pkg_abc123",
"tenant_id": "tenant-456",
"user_id": "user-abc",
"completion_status": "completed",
"success_status": "passed",
"score": {
"scaled": 0.95,
"raw": 95,
"min": 0,
"max": 100
},
"attempts": 1,
"time_spent_seconds": 3600,
"session_time": "PT1H",
"created_at": "2025-01-15T00:00:00Z",
"updated_at": "2025-01-15T01:00:00Z",
"package": {
"title": "Course Title",
"version": "1.2"
}
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 150,
"total_pages": 8
}
}
Exporting Data
Export Learner Progress (CSV)
const response = await fetch('/api/customer/reports/learner-progress/export?range=30d', {
credentials: 'include',
});
const csv = await response.text();
// Download CSV
const blob = new Blob([csv], { type: 'text/csv' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'learner-progress.csv';
a.click();
CSV Format:
Package ID,Package Title,Total Sessions,Completed,Completion Rate,Avg Time (seconds),Avg Score,Passed,Failed,Unknown
pkg_abc123,Introduction to Safety Training,25,18,72.0%,1250,0.85,15,3,7
Export Custom Report
const response = await fetch('/api/customer/reports/custom/export?format=csv', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({
type: 'completion',
dateFrom: '2025-01-01',
dateTo: '2025-01-31',
packageId: 'pkg_abc123'
})
});
const csv = await response.text();
Formats:
csv- Comma-separated values (default)json- JSON format
Custom Reports
Generate flexible reports with custom filters and visualizations:
const response = await fetch('/api/customer/reports/custom', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({
type: 'completion',
dateFrom: '2025-01-01',
dateTo: '2025-01-31',
packageId: 'pkg_abc123',
userId: 'user_xyz789',
chartType: 'bar',
groupBy: 'day'
})
});
const report = await response.json();
Request Parameters:
type(required): Report typecompletion- Completion ratestime- Time spentscore- Scores
dateFrom(required): Start date (ISO 8601)dateTo(required): End date (ISO 8601)packageId(optional): Filter by packageuserId(optional): Filter by userchartType(optional): Visualization typebar- Bar chartline- Line charttable- Data table
groupBy(optional): Grouping periodday- Daily aggregationweek- Weekly aggregationmonth- Monthly aggregation
Response:
{
"type": "completion",
"chartType": "bar",
"dateRange": {
"from": "2025-01-01",
"to": "2025-01-31"
},
"rows": [
["2025-01-01", 10, 8, "80.0%"],
["2025-01-02", 15, 12, "80.0%"],
["2025-01-03", 20, 18, "90.0%"]
]
}
Common Scenarios
Scenario 1: Display Completion Dashboard
async function loadDashboard() {
// Get learner progress
const progressResponse = await fetch('/api/customer/reports/learner-progress?range=30d', {
credentials: 'include'
});
const progress = await progressResponse.json();
// Display summary
document.getElementById('total-packages').textContent = progress.summary.total_packages;
document.getElementById('completion-rate').textContent =
`${progress.summary.overall_completion_rate}%`;
document.getElementById('total-sessions').textContent = progress.summary.total_sessions;
// Display package list
const packagesList = document.getElementById('packages');
progress.packages.forEach(pkg => {
const item = document.createElement('div');
item.innerHTML = `
<h3>${pkg.package_title}</h3>
<p>Completion: ${pkg.completion_rate}%</p>
<p>Average Score: ${(pkg.avg_score * 100).toFixed(1)}%</p>
`;
packagesList.appendChild(item);
});
}
Scenario 2: Export Monthly Report
async function exportMonthlyReport(year: number, month: number) {
const dateFrom = `${year}-${String(month).padStart(2, '0')}-01`;
const lastDay = new Date(year, month, 0).getDate();
const dateTo = `${year}-${String(month).padStart(2, '0')}-${lastDay}`;
const response = await fetch(
`/api/customer/reports/custom/export?format=csv`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({
type: 'completion',
dateFrom,
dateTo,
groupBy: 'day'
})
}
);
const csv = await response.text();
downloadCSV(csv, `report-${year}-${month}.csv`);
}
Scenario 3: Track Package Performance
async function getPackagePerformance(packageId: string) {
// Get all sessions for package
const sessionsResponse = await fetch(
`/api/v1/sessions?package_id=${packageId}`,
{ headers: { 'X-API-Key': apiKey } }
);
const { sessions } = await sessionsResponse.json();
// Calculate metrics
const total = sessions.length;
const completed = sessions.filter(s => s.completion_status === 'completed').length;
const passed = sessions.filter(s => s.success_status === 'passed').length;
const avgScore = sessions
.filter(s => s.score)
.reduce((sum, s) => sum + (s.score.scaled || 0), 0) / total;
const avgTime = sessions
.reduce((sum, s) => sum + (s.time_spent_seconds || 0), 0) / total;
return {
total,
completed,
completionRate: (completed / total) * 100,
passed,
passRate: (passed / completed) * 100,
avgScore: avgScore * 100,
avgTimeMinutes: Math.round(avgTime / 60)
};
}
Troubleshooting
Error: "No Data Available"
Causes:
- No sessions in the date range
- Filters too restrictive
- No completed sessions
Solutions:
- Expand date range
- Remove filters
- Check that sessions exist
Error: "Unauthorized"
Causes:
- Missing authentication
- Invalid API key
- Tenant mismatch
Solutions:
- Verify authentication
- Check API key validity
- Ensure correct tenant
Export Fails
Causes:
- Large dataset
- Network timeout
- Invalid format
Solutions:
- Use date filters to reduce data
- Increase timeout
- Verify format parameter
Best Practices
- Use Date Filters: Always filter by date range to improve performance
- Cache Results: Cache report data for frequently accessed reports
- Paginate Large Datasets: Use pagination for large result sets
- Export Asynchronously: For large exports, use async processing
- Monitor Performance: Track report generation time and optimize queries
Next Steps
- API Guide - Complete endpoint documentation (API Reference coming soon)
- Custom Reports Guide - Advanced reporting
- Webhook Setup - Real-time report updates
- Analytics Dashboard - Build custom dashboards
Last Updated: 2025-01-15
Related Documentation: