PlaycademyPlaycademy

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.

Playcademy simplifies Timeback integration - showing activity tracking workflow

Getting Started

Command
$ playcademy init
Output
# ...Integrations:? Would you like to set up Timeback integration? Yes? Select subjects: Math? Select grade levels: 3, 4
$ playcademy timeback init

Configuration

After enabling Timeback, your playcademy.config.js file will include Timeback configuration:

playcademy.config.js
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:

playcademy.config.js
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:

Command
$ playcademy timeback setup$ playcademy timeback verify
Output
✔ 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 complete

Run 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.)

playcademy.config.js
/**
 * 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

CommandDescriptionWhen to Use
timeback setupCreate OneRoster coursesAfter enabling Timeback
timeback verifyCheck course statusAfter running timeback setup
timeback updateSync config changesAfter modifying courses in config
timeback cleanupRemove Timeback integrationRemove 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.

Command
$ playcademy timeback setup

After 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.

Command
$ playcademy timeback update

Check that all Timeback resources were created successfully and are properly configured in OneRoster.

Run this after setup to confirm everything is ready.

Command
$ playcademy timeback verify

Clean up Timeback integration from OneRoster if you need to remove it.

This deletes the resources but keeps your project intact.

Command
$ playcademy timeback cleanup

Learning Loops

Every app has two fundamental time scales. Understanding them helps you think about what to track and when.

ConceptScopeDurationYou Track
SessionChain of activities in one sittingMinutesXP, accuracy, time
UnitMastery-based goal tied to a standard (may require multiple sessions)Hours/Days/WeeksmasteredUnits

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.

Course progression example showing three courses with a student enrolled in Grade 3, completing units and calculating pctCompleteApp

What counts as a "unit" depends on your app's structure:

App StructureExample Units
Level-basedLevels, stages, worlds
Rank-basedRanks, tiers, badges
Skills-basedSkills, competencies, standards
Module-basedModules, quizzes, chapters
Custom structuresAny discrete learning milestone

Configure masterableUnits per course:

playcademy.config.js
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:

Example
const id = client.timeback.user.id
// 'abc123-def456-...'

role

The user's primary Timeback role:

Example
const role = client.timeback.user.role
// 'student' | 'parent' | 'teacher' | 'administrator' | 'guardian'

enrollments

Array of courses the user is enrolled in, scoped to your project:

Example
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:

Example
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.

Example
// 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().

Example
// 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
FieldTypeDescriptionDefault
gradenumberGrade level to filter (must be used with subject)All grades
subjectstringSubject to filter (must be used with grade)All subjects
includestring[]Additional data: 'perCourse', 'today'[]
forcebooleanBypass cache and fetch fresh datafalse
Response
FieldTypeDescription
totalXpnumberTotal XP across queried courses
todayXpnumberToday's XP (if 'today' included)
coursesarrayPer-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.

startActivity Example
// 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
FieldTypeDescriptionExample
activityIdstringIdentifier for this activity"math-quiz-1"
gradenumberGrade level3
subjectstringSubject area"Math"
Optional Fields
FieldTypeDescriptionDefault
activityNamestringDisplay name for the activityPrettified activityId
appNamestringApplication nameFrom playcademy.config.{js,json}
sensorUrlstringURL where activity is hostedDeployed 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.

endActivity Example
// 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
FieldTypeDescriptionExample
correctQuestionsnumberNumber of correct answers8
totalQuestionsnumberTotal number of questions10
Optional Fields
FieldTypeDescriptionDefault
xpAwardednumberOverride automatic XP calculationBased on time and accuracy
masteredUnitsnumberNumber of units mastered0

XP Calculation

By default, XP is calculated as:

Base XP = Active time in minutes × Accuracy multiplier

AccuracyMultiplierExample (10 min)
100%1.25×10 min × 1.25 = 12.5 XP
80-99%1.0×10 min × 1.0 = 10 XP
< 80%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.

pauseActivity Example
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.

vite.config.ts
export default defineConfig({
    plugins: [
        playcademy(), // All courses enrolled automatically with mock data
    ],
})

Customization

Override defaults for specific testing scenarios:

vite.config.ts
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:

.env
# 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.com

See Timeback Authentication and Endpoints for details.

Hotkeys

Press these keys in the terminal during development:

KeyAction
tCycle Timeback role (student → parent → teacher → ...)

See Development Mode for full configuration options.


What's Next?

On this page