Skip to main content

Overview

Activity tracking lets you record learning sessions, measure time spent, and calculate XP based on performance.

Basic Usage

Start and end an activity:
const activity = timeback.activity.start({
	id: 'lesson-123',
	name: 'Introduction to Fractions',
	course: { subject: 'Math', grade: 3 },
})

// When the user completes the activity
await activity.end({
	totalQuestions: 10,
	correctQuestions: 8,
	xpEarned: 80,
})

Framework Integration

import { useTimeback } from '@timeback/sdk/react'
import { useEffect } from 'react'

function LessonPage({ lessonId, lessonName }) {
	const timeback = useTimeback()

	useEffect(() => {
		if (!timeback) return

		const activity = timeback.activity.start({
			id: lessonId,
			name: lessonName,
			course: { subject: 'Math', grade: 3 },
		})

		return () => {
			activity.end({
				totalQuestions: 10,
				correctQuestions: 8,
				xpEarned: 80,
			})
		}
	}, [timeback, lessonId, lessonName])

	return <div>Lesson content...</div>
}

Activity Lifecycle

Pause and Resume

Track active vs inactive time:
const activity = timeback.activity.start({
	id: 'lesson-1',
	name: 'Lesson',
	course: { subject: 'Math', grade: 3 },
})

// User pauses (e.g., switches tabs)
activity.pause()

// User resumes
activity.resume()

// End with final metrics
await activity.end({
	totalQuestions: 10,
	correctQuestions: 8,
	xpEarned: 80,
})

End Metrics

When ending an activity, you can provide these metrics:
await activity.end({
	totalQuestions: 10,
	correctQuestions: 8,
	xpEarned: 80,
	masteredUnits: 1,
	pctComplete: 67,
})
totalQuestions
number
Total questions in the activity
correctQuestions
number
Questions answered correctly
xpEarned
number
required
XP earned for this activity
masteredUnits
number
Units mastered (optional)
pctComplete
number
Completion percentage, 0-100 (optional)
totalQuestions and correctQuestions must be provided together.If you provide one, you must provide the other.

Time Override

By default, the SDK automatically tracks active and inactive time. For advanced scenarios where you need to override the timing (e.g., offline sync or batch imports), use the time parameter:
await activity.end({
	totalQuestions: 10,
	correctQuestions: 8,
	xpEarned: 80,
	time: {
		active: 1800000, // 30 minutes active
		inactive: 300000, // 5 minutes paused
	},
})

Activity Properties

Access activity state during the session:
const activity = timeback.activity.start({
	id: 'lesson-1',
	name: 'Lesson',
	course: { subject: 'Math', grade: 3 },
})

activity.startedAt
activity.isPaused
activity.elapsedMs
startedAt
Date
When the activity was started
isPaused
boolean
Whether the activity is paused
elapsedMs
number
Active time in milliseconds (excludes paused time)

Configuration

Activity ingestion requires a Caliper sensor URL in timeback.config.json:
timeback.config.json
{
	"$schema": "https://timeback.dev/schema.json",
	"name": "My App",
	"sensor": "https://my-app.example.com/sensors/default",
	"courses": [
		{
			"subject": "Math",
			"grade": 3,
			"courseCode": "MATH-3",
			"sensor": "https://my-app.example.com/sensors/math",
			"overrides": {
				"staging": {
					"sensor": "https://staging.my-app.example.com/sensors/math"
				}
			}
		}
	]
}

Sensor Precedence

The SDK resolves sensors in this order (highest to lowest):
  1. Per-course env override: course.overrides[env].sensor
  2. Per-course base override: course.sensor
  3. Top-level default: config.sensor

How It Works

When you call activity.end(), the SDK:
  1. Calculates elapsed time (active vs paused)
  2. Generates Caliper ActivityEvent and TimeSpentEvent
  3. Sends events to the configured sensor
  4. Updates the user’s XP and progress
┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│   Client     │────>│   Server     │────>│  Caliper API │
│  activity.   │     │  /activity   │     │              │
│    end()     │     │   handler    │     │              │
└──────────────┘     └──────────────┘     └──────────────┘

Best Practices

Always start activities in lifecycle hooks to ensure proper cleanup.
Use cleanup functions to ensure activities are ended when components unmount.
Check if the timeback client exists before creating activities (it may be null if not authenticated).
Use stable, unique IDs that identify the specific lesson or content piece.

Next Steps