Level 4: Insights API
Access coaching insights generated from student learning activity to power dashboards, reports, and intervention workflows.
What Insights Provides
The Insights API gives you read access to coaching insights that TimeBack generates from Caliper events (Level 3). By integrating with Insights, you enable:
- Student behavior dashboards showing time-on-task and waste patterns
- Session-level analytics with detailed insight breakdowns
- Trend analysis over configurable time ranges
- Cross-session aggregations for progress tracking
Without the Insights API, you can send learning events but can't programmatically access the insights TimeBack generates. With Insights, you can build custom dashboards and integrate coaching data into your app's existing analytics.
Prerequisites
Before implementing Insights:
- Implement Level 3 (Caliper Events)—insights are generated from Caliper events you send
- Request OAuth credentials with the
events.readonlyscope (see Authentication Guide)
API Endpoints
The Insights API provides four endpoints for accessing coaching data:
| Endpoint | Description |
|---|---|
GET /insights/1.0/users/{userId} |
Get insights for a specific user |
GET /insights/1.0/users/{userId}/sessions |
Get session list for a user |
GET /insights/1.0/sessions/{sessionId} |
Get insights for a specific session |
GET /insights/1.0/users/{userId}/overview |
Get aggregated trend and breakdown data |
Authentication
All Insights endpoints require OAuth 2.0 authentication. Request the events read scope:
scope: https://purl.imsglobal.org/spec/caliper/v1p2/scope/events.readonly
Include your access token in requests:
const response = await fetch(`https://platform.timeback.com/insights/1.0/users/${userId}`, {
method: 'GET',
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
});
Get User Insights
Retrieve insights for a specific user with optional filtering and pagination.
GET /insights/1.0/users/{userId}
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
applicationId |
uuid | No | Filter insights to a specific learning app |
after |
datetime | No | Filter insights after this timestamp (inclusive) |
before |
datetime | No | Filter insights before this timestamp (inclusive) |
limit |
integer | No | Maximum items to return (1-100, default 20) |
offset |
integer | No | Number of items to skip (default 0) |
type |
string | No | Comma-separated insight types to filter by |
Example Request
const userId = 'student-platform-id'; // From LTI 'sub' or roster lookup
const response = await fetch(
`https://platform.timeback.com/insights/1.0/users/${userId}?limit=10&after=2025-01-01T00:00:00Z`,
{
headers: { Authorization: `Bearer ${accessToken}` },
},
);
const data = await response.json();
Example Response
{
"session": {
"startedAtTime": "2025-01-15T09:00:00Z",
"endedAtTime": "2025-01-15T10:30:00Z",
"durationInSeconds": 5400,
"wasteDurationInSeconds": 720,
"wastePercentage": 13
},
"insights": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"insightType": "Idling",
"reason": "No activity detected for extended period",
"startedAtTime": "2025-01-15T09:15:00Z",
"endedAtTime": "2025-01-15T09:20:00Z",
"durationInSeconds": 300,
"version": "v1"
}
],
"offset": 0,
"limit": 10,
"total": 1
}
Get User Sessions
Retrieve sessions for a user with optional filtering.
GET /insights/1.0/users/{userId}/sessions
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
applicationId |
uuid | No | Filter sessions to a specific learning app |
startedAfter |
datetime | No | Lower bound for session start time (inclusive) |
startedBefore |
datetime | No | Upper bound for session start time (inclusive) |
isProctored |
boolean | No | Filter by proctored status |
limit |
integer | No | Maximum items to return (1-100, default 20) |
offset |
integer | No | Number of items to skip (default 0) |
Example Request
const response = await fetch(
`https://platform.timeback.com/insights/1.0/users/${userId}/sessions?startedAfter=2025-01-01T00:00:00Z`,
{
headers: { Authorization: `Bearer ${accessToken}` },
},
);
const data = await response.json();
Example Response
{
"sessions": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"applicationId": "learning-app-uuid",
"startedAtTime": "2025-01-15T09:00:00Z",
"endedAtTime": "2025-01-15T10:30:00Z",
"durationInSeconds": 5400,
"wasteDurationInSeconds": 720,
"wastePercentage": 13,
"isProctored": true,
"proctoredResult": "PASSED",
"recordingStartedAtTime": "2025-01-15T09:00:05Z",
"recordingEndedAtTime": "2025-01-15T10:29:55Z",
"recordingS3Key": "recordings/2025/01/15/session-550e8400.webm"
}
],
"offset": 0,
"limit": 20,
"total": 1
}
Get Session Insights
Retrieve insights for a specific session.
GET /insights/1.0/sessions/{sessionId}
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
sessionId |
uuid | Yes | Session ID from the sessions list |
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
isProctored |
boolean | No | Filter insights by proctored status |
limit |
integer | No | Maximum items to return (1-100, default 20) |
offset |
integer | No | Number of items to skip (default 0) |
type |
string | No | Comma-separated insight types to filter by |
Example Request
const sessionId = '550e8400-e29b-41d4-a716-446655440000';
const response = await fetch(`https://platform.timeback.com/insights/1.0/sessions/${sessionId}`, {
headers: { Authorization: `Bearer ${accessToken}` },
});
const data = await response.json();
Get User Insights Overview
Retrieve aggregated overview data including trends and breakdowns for a time range.
GET /insights/1.0/users/{userId}/overview
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
startedAfter |
datetime | Yes | Lower bound for time window (inclusive) |
startedBefore |
datetime | Yes | Upper bound for time window (exclusive) |
targetTimezone |
string | Yes | IANA timezone for local-day bucketing |
Example Request
const params = new URLSearchParams({
startedAfter: '2025-01-01T00:00:00Z',
startedBefore: '2025-01-08T00:00:00Z',
targetTimezone: 'America/New_York',
});
const response = await fetch(`https://platform.timeback.com/insights/1.0/users/${userId}/overview?${params}`, {
headers: { Authorization: `Bearer ${accessToken}` },
});
const data = await response.json();
Example Response
{
"summary": {
"totalDurationInSeconds": 36000,
"totalWasteDurationInSeconds": 5400,
"wastePercentage": 15,
"biggestInsight": {
"level": "OnDeviceDistractions",
"durationInSeconds": 2400,
"wastePercentage": 7
}
},
"trend": {
"buckets": [
{
"startedAtTime": "2025-01-01T00:00:00Z",
"endedAtTime": "2025-01-02T00:00:00Z",
"totalDurationInSeconds": 7200,
"wasteDurationInSeconds": 1080,
"wastePercentage": 15,
"levels": [
{ "level": "StudentNotPresent", "durationInSeconds": 300 },
{ "level": "OnDeviceDistractions", "durationInSeconds": 780 }
]
}
]
},
"breakdown": {
"levels": [
{
"level": "OnDeviceDistractions",
"durationInSeconds": 2400,
"wastePercentage": 7,
"subtypes": [
{ "insightType": "Game", "durationInSeconds": 1200 },
{ "insightType": "NonLearningContent", "durationInSeconds": 1200 }
]
}
]
}
}
Insight Types
TimeBack generates the following insight types from student activity:
Waste Insights (Time Off-Task)
| Type | Description |
|---|---|
AwayFromSeat |
Student not detected at their desk |
EyesOffScreen |
Student looking away from screen |
Idling |
No activity for extended period |
NonLearningContent |
Browsing non-educational content |
Socializing |
Social media or messaging activity |
IgnoringHelp |
Student dismissed or ignored coaching suggestions |
SkipAssessment |
Student skipped assessment questions |
AbandonedAssessment |
Student left assessment incomplete |
TopicShopping |
Rapidly switching between topics without progress |
Proctoring Insights
| Type | Description |
|---|---|
UnauthorizedAppUse |
Using applications not allowed during session |
HelpFromAnotherPerson |
Receiving unauthorized help |
Safety Insights
| Type | Description |
|---|---|
BullyingOrHarassment |
Bullying or harassment detected |
EmbarrassingOrDefaming |
Embarrassing or defaming content |
MentalHealthDistress |
Signs of mental health distress |
PornographyOrSexualContent |
Pornographic or sexual content |
SelfHarmOrSuicide |
Self-harm or suicide-related content |
SubstanceAbuse |
Substance abuse detected |
ViolenceOrAbuse |
Violence or abuse detected |
WebcamNudity |
Nudity detected via webcam |
Overview Levels
Overview data groups insights into four levels:
| Level | Description |
|---|---|
StudentNotPresent |
Student away from seat or eyes off screen |
EnvironmentalDistractions |
External distractions (eating, socializing) |
OnDeviceDistractions |
Digital distractions (games, social media) |
LearningAppBestPractices |
Learning behavior issues (skipping, shopping) |
Looking Up Application Information
Insights and sessions include an applicationId field that identifies which learning app the data came from. To map application IDs to application names and details, use the Applications API.
Get All Applications
GET /applications/1.0
This endpoint returns all applications. Each application's sourcedId is the applicationId you'll see in insights responses.
Required scope: https://purl.imsglobal.org/spec/lti/v1p3/scope/lti.readonly
This endpoint supports filtering, pagination, sorting, and field selection. See OneRoster API Conventions for details.
Example Request
const response = await fetch('https://platform.timeback.com/applications/1.0', {
headers: { Authorization: `Bearer ${accessToken}` },
});
const data = await response.json();
Example Response
{
"applications": [
{
"sourcedId": "app-uuid",
"name": "Math Learning Suite",
"description": "Comprehensive math learning platform",
"logoUrl": "https://example.com/logo.png",
"applicationType": "learning_app",
"wasteMeter": "on",
"proctoringMode": "off"
}
],
"offset": 0,
"limit": 10,
"total": 1
}
Building an Application Lookup Map
Cache application information to efficiently display app names in your dashboards:
interface ApplicationInfo {
name: string;
logoUrl: string;
}
async function buildApplicationLookup(accessToken: string): Promise<Map<string, ApplicationInfo>> {
const response = await fetch('https://platform.timeback.com/applications/1.0?limit=100', {
headers: { Authorization: `Bearer ${accessToken}` },
});
const data = await response.json();
const applicationMap = new Map<string, ApplicationInfo>();
for (const app of data.applications) {
applicationMap.set(app.sourcedId, {
name: app.name,
logoUrl: app.logoUrl,
});
}
return applicationMap;
}
// Usage: Display application name for a session
const applicationLookup = await buildApplicationLookup(accessToken);
const session = sessions[0];
const applicationInfo = applicationLookup.get(session.applicationId);
console.log(`Session in: ${applicationInfo?.name}`); // "Session in: Math Learning Suite"
Common Use Cases
Building a Student Dashboard
Use the overview endpoint to show weekly trends:
async function getWeeklyOverview(userId: string, timezone: string): Promise<Overview> {
const now = new Date();
const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
const params = new URLSearchParams({
startedAfter: weekAgo.toISOString(),
startedBefore: now.toISOString(),
targetTimezone: timezone,
});
const response = await fetch(`https://platform.timeback.com/insights/1.0/users/${userId}/overview?${params}`, {
headers: { Authorization: `Bearer ${accessToken}` },
});
return response.json();
}
Listing Recent Sessions with Waste Stats
async function getRecentSessions(userId: string): Promise<Session[]> {
const response = await fetch(`https://platform.timeback.com/insights/1.0/users/${userId}/sessions?limit=10`, {
headers: { Authorization: `Bearer ${accessToken}` },
});
const data = await response.json();
return data.sessions;
}
Drilling into Session Details
async function getSessionDetails(sessionId: string): Promise<Insights> {
const response = await fetch(`https://platform.timeback.com/insights/1.0/sessions/${sessionId}`, {
headers: { Authorization: `Bearer ${accessToken}` },
});
return response.json();
}
Error Handling
The API returns standard HTTP status codes:
| Status | Description |
|---|---|
| 200 | Success |
| 400 | Bad request (invalid parameters) |
| 401 | Unauthorized (missing or invalid token) |
| 403 | Forbidden (insufficient scope) |
| 404 | Not found (session or user doesn't exist) |
| 500 | Internal server error |
Error responses include details:
{
"error": "Bad request",
"message": "Invalid UUID format for userId"
}
Related Docs
Level 3: Caliper Events
Insights are generated from Caliper events. Implement Level 3 first to start generating insights.
Authentication
Obtain OAuth client credentials and access tokens required for the Insights API.
OneRoster API Conventions
Learn about filtering, pagination, sorting, and field selection for the Applications API.