Timeback
Track learning activities and award XP with educational integration
Overview
Integrate your project with Timeback to track learning activities and award XP based on student performance.
Timeback is 1EdTech-compliant, enabling deep interoperability between learning applications and educational systems.
Getting Started
$ playcademy init# ...Integrations:? Would you like to set up Timeback integration? Yes? Select subjects: Math? Select grade levels: 3, 4$ playcademy timeback initConfiguration
After enabling Timeback, your playcademy.config.js file will include Timeback configuration:
export default {
name: 'My Math Project',
integrations: {
// ↓ Added
timeback: {
courses: [
{
subject: 'Math',
grade: 3,
totalXp: null, // TODO: Set before setup
masterableUnits: null, // TODO: Set before setup
},
{
subject: 'Math',
grade: 4,
totalXp: null, // TODO: Set before setup
masterableUnits: null, // TODO: Set before setup
},
],
},
},
}Required Configuration Before Setup
You must configure totalXp and masterableUnits for each course before running playcademy timeback setup.
Both are critical for accurate progress tracking and completion calculation.
Configure these values based on your educational content:
timeback: {
courses: [
{
subject: 'Math',
grade: 3,
totalXp: 1000, // Total XP available in grade 3
masterableUnits: 10, // Total levels/ranks/skills in grade 3
},
// ... other courses
],
}Run Setup
Once configured, create the OneRoster resources:
$ playcademy timeback setup$ playcademy timeback verify✔ Created 3 course(s)✔ Timeback integration set up successfully! Grade 3 (Math): course-id-1 Grade 4 (Math): course-id-2 Grade 5 (Math): course-id-3✔ Verification completeRun Before Deploying
Run playcademy timeback setup before deploying your
project.
Custom Configuration
If you need to customize the Timeback configuration, you can do so by modifying your playcademy.config.js file.
(Note that customizing the configuration is not required, and the default configuration will work for most use cases.)
/**
* Shared configuration applies to all courses
*/
export default {
name: 'Math Adventure',
integrations: {
timeback: {
base: {
organization: {
name: 'My School District',
type: 'district',
},
course: {
title: '{appName} - Grade {grade}', // Template variables
totalXp: 100, // Default XP for all courses
masterableUnits: 10, // Default units for all courses
},
},
courses: [
{ subject: 'Math', grade: 3 },
{ subject: 'Math', grade: 4 },
],
},
},
}/**
* Customize individual courses
*/
export default {
name: 'Math Adventure',
integrations: {
timeback: {
courses: [
{
subject: 'Math',
grade: 3,
totalXp: 100,
masterableUnits: 10,
},
{
subject: 'Math',
grade: 4,
title: 'Advanced 4th Grade Math',
courseCode: 'ADV-MATH-4',
totalXp: 150,
masterableUnits: 15,
},
],
},
},
}/**
* Base config + per-course overrides
*/
export default {
name: 'Math Adventure',
integrations: {
timeback: {
base: {
organization: {
name: 'My School',
},
course: {
title: '{appName} - Grade {grade}',
totalXp: 100, // Default
masterableUnits: 10, // Default
},
},
courses: [
{ subject: 'Math', grade: 3 },
{
subject: 'Math',
grade: 4,
title: 'Custom Title', // Overrides base
totalXp: 150, // Overrides base
masterableUnits: 15, // Overrides base
},
],
},
},
}Template Variables
Use {grade}, {subject}, {appSlug}, {appName} in base config strings.
The CLI will expand these variables for you when creating OneRoster resources.
Management Commands
| Command | Description | When to Use |
|---|---|---|
timeback setup | Create OneRoster courses | After enabling Timeback |
timeback verify | Check course status | After running timeback setup |
timeback update | Sync config changes | After modifying courses in config |
timeback cleanup | Remove Timeback integration | Remove Timeback but keep your project |
View Full Command Documentation
See Timeback CLI Reference for all options.
Common Workflows
Run this after configuring your courses in playcademy.config.js to initialize all OneRoster resources.
This creates courses, components, and the interactive resource for your app.
$ playcademy timeback setupAfter modifying your course configuration (e.g., changing masterableUnits or adding grades), sync those changes to OneRoster.
Use this whenever you update your Timeback config to keep your OneRoster resources in sync.
$ playcademy timeback updateCheck that all Timeback resources were created successfully and are properly configured in OneRoster.
Run this after setup to confirm everything is ready.
$ playcademy timeback verifyClean up Timeback integration from OneRoster if you need to remove it.
This deletes the resources but keeps your project intact.
$ playcademy timeback cleanupLearning Loops
Every app has two fundamental time scales. Understanding them helps you think about what to track and when.
| Concept | Scope | Duration | You Track |
|---|---|---|---|
| Session | Chain of activities in one sitting | Minutes | XP, accuracy, time |
| Unit | Mastery-based goal tied to a standard (may require multiple sessions) | Hours/Days/Weeks | masteredUnits |
Sessions
A session is a single, focused learning activity that students complete in one sitting.
Call startActivity() when it begins and endActivity() when it ends.
Every session awards 0 or more XP based on accuracy and active time.
Units
A unit is a discrete mastery-based milestone that students work toward across multiple sessions.
When a student completes a unit (beats a level, earns a rank, etc.), report masteredUnits: 1 in endActivity().
The platform accumulates these to calculate pctCompleteApp: (masteredUnits / masterableUnits) × 100.
When to Report Mastery
Mastery is typically achieved when a session meets minimum accuracy and maximum time thresholds.
For example: completing a quiz with ≥90% accuracy in under 5 minutes might demonstrate mastery.
Your app defines the thresholds that determine when a unit is mastered.
Progress
Set masterableUnits in playcademy.config.js to define the total number of units in your course.
As students complete units, report masteredUnits: 1 to track their progress toward course completion.
What counts as a "unit" depends on your app's structure:
| App Structure | Example Units |
|---|---|
| Level-based | Levels, stages, worlds |
| Rank-based | Ranks, tiers, badges |
| Skills-based | Skills, competencies, standards |
| Module-based | Modules, quizzes, chapters |
| Custom structures | Any discrete learning milestone |
Configure masterableUnits per course:
export default {
name: 'Astro Math',
integrations: {
timeback: {
courses: [
{
subject: 'FastMath',
grade: 3,
totalXp: 300,
masterableUnits: 3, // Grade 3: 3 units
},
{
subject: 'FastMath',
grade: 4,
totalXp: 450,
masterableUnits: 5, // Grade 4: 5 units
},
],
},
},
}Activity Tracking vs Mastery Tracking?
When students complete a discrete learning unit, report masteredUnits: 1 in endActivity().
The platform tracks cumulative progress and calculates pctCompleteApp as (masteredUnits / masterableUnits) × 100
Using Timeback in Your App
The @playcademy/sdk provides everything you need to access student context and track learning activities.
Learn more about the client.timeback namespace.
User Context
Access the user's Timeback context via client.timeback.user.
id
The user's unique Timeback identifier:
const id = client.timeback.user.id
// 'abc123-def456-...'role
The user's primary Timeback role:
const role = client.timeback.user.role
// 'student' | 'parent' | 'teacher' | 'administrator' | 'guardian'enrollments
Array of courses the user is enrolled in, scoped to your project:
const enrollments = client.timeback.user.enrollments
// [{ subject: 'FastMath', grade: 3, courseId: '...' }, ...]App-Scoped
Enrollments are filtered to courses defined in your playcademy.config.js.
organizations
Array of all organizations (schools/districts) the user is affiliated with:
const orgs = client.timeback.user.organizations
// [{ id: '...', name: 'Playcademy Studios', type: 'school', isPrimary: true }, ...]App-Scoped
Like enrollments, organizations are app-scoped.
Only organizations associated with the user's enrollments for your project are included.
fetch()
Fetch fresh user data from the server. Results are cached for 5 minutes by default.
// Fetch fresh data (cached for 5 min)
const fresh = await client.timeback.user.fetch()
// Force refresh bypassing cache
const forced = await client.timeback.user.fetch({ force: true })When to Fetch
The user context is initialized when the app loads.
Use fetch() if you need to ensure you have the latest data, such as after a user might have been enrolled in a new course mid-session.
xp
Access the current student's XP data via client.timeback.user.xp.fetch().
// Get XP for all courses
const xp = await client.timeback.user.xp.fetch()
// → { totalXp: 1500 }
// Get XP for a specific grade/subject (must match a course in your config)
const xp = await client.timeback.user.xp.fetch({
grade: 3,
subject: 'Math',
})
// → { totalXp: 800 }
// Get XP with per-course breakdown + today's XP
const xp = await client.timeback.user.xp.fetch({
include: ['perCourse', 'today'],
})
// → {
// totalXp: 1500,
// todayXp: 50,
// courses: [
// { grade: 3, subject: 'Math', title: 'Math Grade 3', totalXp: 800, todayXp: 30 },
// { grade: 4, subject: 'Math', title: 'Math Grade 4', totalXp: 700, todayXp: 20 },
// ]
// }
// Force fresh data (bypass 5s cache)
const fresh = await client.timeback.user.xp.fetch({ force: true })App-Scoped
XP is scoped to courses defined in your playcademy.config.{js,json} file.
This method only returns the student's XP for your app, not their total XP across all of Timeback.
Options
| Field | Type | Description | Default |
|---|---|---|---|
grade | number | Grade level to filter (must be used with subject) | All grades |
subject | string | Subject to filter (must be used with grade) | All subjects |
include | string[] | Additional data: 'perCourse', 'today' | [] |
force | boolean | Bypass cache and fetch fresh data | false |
Response
| Field | Type | Description |
|---|---|---|
totalXp | number | Total XP across queried courses |
todayXp | number | Today's XP (if 'today' included) |
courses | array | Per-course breakdown (if 'perCourse' included) |
Caching
XP data is cached for 5 seconds to avoid redundant network requests. Use force: true to bypass the cache.
Activity Tracking
startActivity
Begin tracking a learning activity. Starts an internal timer and prepares data for OneRoster submission.
// Minimal (most common)
client.timeback.startActivity({
activityId: 'math-quiz-1',
grade: 3,
subject: 'Math',
})
// Activity name auto-derived: "Math Quiz 1"
// With custom name override
client.timeback.startActivity({
activityId: 'multiplication-drill',
activityName: 'Advanced Multiplication Drill',
grade: 4,
subject: 'Math',
})Required Fields
| Field | Type | Description | Example |
|---|---|---|---|
activityId | string | Identifier for this activity | "math-quiz-1" |
grade | number | Grade level | 3 |
subject | string | Subject area | "Math" |
Optional Fields
| Field | Type | Description | Default |
|---|---|---|---|
activityName | string | Display name for the activity | Prettified activityId |
appName | string | Application name | From playcademy.config.{js,json} |
sensorUrl | string | URL where activity is hosted | Deployed project URL |
Course Routing
The grade and subject fields determine which OneRoster course receives the activity data.
Ensure these match a course in your playcademy.config.{js,json} Timeback configuration.
endActivity
End the current activity and submit results to OneRoster. Calculates XP based on accuracy and active time.
// Auto-calculate XP based on score
await client.timeback.endActivity({
correctQuestions: 8,
totalQuestions: 10,
})
// Override XP calculation
await client.timeback.endActivity({
correctQuestions: 8,
totalQuestions: 10,
xpAwarded: 15, // award exactly 15 XP
})
// Report mastery (e.g., unit completed)
await client.timeback.endActivity({
correctQuestions: 8,
totalQuestions: 10,
masteredUnits: 1, // student mastered 1 unit
})When to Report Mastery
Send masteredUnits: 1 when the student completes a discrete learning unit in your app:
- Level-based: Student completes a level, stage, or world
- Rank-based: Student earns a rank, tier, or badge
- Skills-based: Student masters a skill, competency, or standard
- Module-based: Student completes a module, quiz, or chapter
The platform tracks cumulative mastery and calculates completion automatically based on your mastery configuration.
Required Fields
| Field | Type | Description | Example |
|---|---|---|---|
correctQuestions | number | Number of correct answers | 8 |
totalQuestions | number | Total number of questions | 10 |
Optional Fields
| Field | Type | Description | Default |
|---|---|---|---|
xpAwarded | number | Override automatic XP calculation | Based on time and accuracy |
masteredUnits | number | Number of units mastered | 0 |
XP Calculation
By default, XP is calculated as:
Base XP = Active time in minutes × Accuracy multiplier
| Accuracy | Multiplier | Example (10 min) |
|---|---|---|
| 100% | 1.25× | 10 min × 1.25 = 12.5 XP |
| 80-99% | 1.0× | 10 min × 1.0 = 10 XP |
| < 80% | 0× | 0 XP (mastery not demonstrated) |
Base rate: 1 minute of active learning = 1 XP
Re-attempts earn diminishing XP: 50% on 1st re-attempt, 25% on 2nd, 0% on 3rd+.
pauseActivity
Pause the activity timer. Use this during non-instructional moments like showing feedback or explanations.
client.timeback.startActivity({
activityId: 'speed-math-1',
grade: 4,
subject: 'Math',
})
// Student attempts a problem...
if (studentAnswerWrong) {
// Pause timer during feedback
client.timeback.pauseActivity()
// Show correct answer or explanation
await showCorrectAnswer()
// Resume timer when they continue
client.timeback.resumeActivity()
}
// End activity (only active time counted)
await client.timeback.endActivity({
correctQuestions: 40,
totalQuestions: 50,
})When to Pause
Pause when:
- Tutorial/instruction screens
- Showing hints or explanations
- Waiting for external resources to load
- Any non-active learning time
This ensures XP reflects actual learning time.
resumeActivity
Resume the activity timer after a pause.
// After pausing
client.timeback.pauseActivity()
// ... show feedback ...
// Resume when ready
client.timeback.resumeActivity()Must Call startActivity First
You must call startActivity() before using pauseActivity() or resumeActivity().
Calling these methods without an active activity will log a warning.
Local Development
The Vite Plugin automatically enrolls mock users in all courses defined in your playcademy.config.js.
export default defineConfig({
plugins: [
playcademy(), // All courses enrolled automatically with mock data
],
})Customization
Override defaults for specific testing scenarios:
playcademy({
timeback: {
id: '...', // real student sourcedId for live testing
role: 'teacher', // test different user roles
organization: { id: '...', name: '...', type: 'school' }, // custom organization
courses: {
// FastMath:3 is enrolled by default if it is defined in your playcademy.config.js
'FastMath:4': false, // not enrolled
'FastMath:5': '00000033-0003-0003-0003-000000000003', // real course ID for integration testing
},
},
})Use null or false to exclude a course from enrollment.
This can be useful for testing how your app behaves when a student is enrolled in specific grades only.
Full Configuration Options
Learn more about Timeback configuration.
Live Timeback Integration
To test against live Timeback services, you must also your .env file with credentials:
# Required: Timeback API credentials
TIMEBACK_API_CLIENT_ID=your-client-id
TIMEBACK_API_CLIENT_SECRET=your-client-secret
TIMEBACK_API_AUTH_URL=https://auth.example.com
# Required: OneRoster and Caliper endpoints
TIMEBACK_ONEROSTER_API_URL=https://oneroster.example.com
TIMEBACK_CALIPER_API_URL=https://caliper.example.comSee Timeback Authentication and Endpoints for details.
Hotkeys
Press these keys in the terminal during development:
| Key | Action |
|---|---|
t | Cycle Timeback role (student → parent → teacher → ...) |
See Development Mode for full configuration options.
What's Next?
Custom Routes
Add your own backend logic alongside Timeback.
Deployment Guide
Deploy your project with Timeback integration.
Browser SDK
Explore the complete Timeback API in the SDK.
CLI Commands
Complete reference for all Timeback CLI commands.
