Skip to main content

Overview

The @timeback/caliper package provides a TypeScript client for the Caliper Analytics API, enabling:
  • Activity Events: Track learning activity completions with metrics
  • Time Spent Events: Record time spent on activities
  • Batch Processing: Monitor event processing jobs

Installation

npm install @timeback/caliper

Quick Start

import { CaliperClient } from '@timeback/caliper'

const client = new CaliperClient({
	env: 'staging',
	auth: {
		clientId: process.env.CALIPER_CLIENT_ID!,
		clientSecret: process.env.CALIPER_CLIENT_SECRET!,
	},
})

const result = await client.events.sendActivity('https://myapp.example.com/sensors/main', {
	actor: {
		id: 'https://api.example.com/users/123',
		type: 'TimebackUser',
		email: '[email protected]',
	},
	object: {
		id: 'https://myapp.example.com/activities/456',
		type: 'TimebackActivityContext',
		subject: 'Math',
		app: { name: 'My Learning App' },
	},
	metrics: [
		{ type: 'totalQuestions', value: 10 },
		{ type: 'correctQuestions', value: 8 },
		{ type: 'xpEarned', value: 150 },
	],
})

const status = await client.jobs.waitForCompletion(result.jobId)

Activity Completed Events

Track when users complete learning activities:
await client.events.sendActivity(sensorUrl, {
	actor: {
		id: 'https://api.example.com/users/123',
		type: 'TimebackUser',
		email: '[email protected]',
	},
	object: {
		id: 'https://myapp.example.com/activities/lesson-1',
		type: 'TimebackActivityContext',
		subject: 'Math',
		app: { name: 'My Learning App' },
	},
	metrics: [
		{ type: 'totalQuestions', value: 10 },
		{ type: 'correctQuestions', value: 8 },
		{ type: 'xpEarned', value: 150 },
		{ type: 'masteredUnits', value: 2 },
	],
})

Metric Types

TypeDescription
totalQuestionsTotal number of questions attempted
correctQuestionsNumber of correct answers
xpEarnedExperience points earned
masteredUnitsNumber of units mastered

Time Spent Events

Track time spent on activities:
await client.events.sendTimeSpent(sensorUrl, {
	actor: {
		id: 'https://api.example.com/users/123',
		type: 'TimebackUser',
		email: '[email protected]',
	},
	object: {
		id: 'https://myapp.example.com/activities/lesson-1',
		type: 'TimebackActivityContext',
		subject: 'Reading',
		app: { name: 'My App' },
	},
	metrics: [
		{ type: 'active', value: 1800 }, // 30 minutes in seconds
		{ type: 'inactive', value: 300 }, // 5 minutes paused
	],
})

Job Monitoring

Event processing is asynchronous. Monitor job status:
client.events.sendActivity(sensorUrl, activityData) // Returns { jobId }
client.jobs.getStatus(jobId)
client.jobs.waitForCompletion(jobId)
MethodReturnsDescription
sendActivity(){ jobId }Send events, get job ID
getStatus()JobStatusCheck status: pending/processing/completed/failed
waitForCompletion()JobStatusPoll until job completes

Query Events

Retrieve stored events:
client.events.list({ limit?, offset?, sensor?, actorId?, actorEmail?, startDate?, endDate? })
client.events.get(externalId)
client.events.stream({ startDate?, max? })
client.events.stream({ startDate?, max? }).toArray()

SDK Integration

When using the full SDK, activity tracking automatically emits Caliper events:
import { createTimeback } from '@timeback/sdk'

const timeback = await createTimeback({
	/* ... */
})

const activity = timeback.activity.start({
	id: 'lesson-1',
	name: 'Introduction',
	course: { subject: 'Math', grade: 3 },
})

await activity.end({
	totalQuestions: 10,
	correctQuestions: 8,
	xpEarned: 80,
}) // Emits ActivityCompleted + TimeSpent events

Next Steps