Browser
Client-side SDK for browser environments
Overview
The browser SDK provides namespaces for interacting with the Playcademy platform from your project frontend.
All methods are accessed through the PlaycademyClient instance.
import { PlaycademyClient } from '@playcademy/sdk'
const client = await PlaycademyClient.init()
const user = await client.users.me() // get current user
const balance = await client.credits.balance() // get current balance
await client.scores.submit(gameId, 1500, { level: 5 }) // submit scoreInitialization
PlaycademyClient.init() automatically detects your environment and configures the client accordingly.
See SDK Initialization for details.
For complete documentation including all types and method signatures: SDK Reference
Core Namespaces
client.users
Retrieve current user information and manage player inventory.
// Get current user
const user = await client.users.me()
// Get inventory
const inventory = await client.users.inventory.get()
// Add items
await client.users.inventory.add('sword-123', 1)
// Remove items
await client.users.inventory.remove('potion-456', 3)client.credits
Manage platform currency (credits).
// Check balance
const balance = await client.credits.balance()
// Add credits
await client.credits.add(100)
// Spend credits
await client.credits.spend(50)client.scores
Submit scores for your project.
// Submit a score
const result = await client.scores.submit(gameId, 1500, {
level: 5,
difficulty: 'hard',
perfectRun: true,
})client.identity
Connect external identity providers (Google, Discord, etc.) to user accounts.
// Connect Google account
const result = await client.identity.connect({
provider: 'google',
callbackUrl: '/auth/callback',
})
if (result.success) {
console.log('Connected:', result.user)
}Integration Namespaces
client.timeback
Track learning activities with automatic XP calculation. Access user context for content gating.
user
Access the user's Timeback context via client.timeback.user:
const id = client.timeback.user.id // User's Timeback ID
const role = client.timeback.user.role // 'student' | 'parent' | 'teacher' | ...
const enrollments = client.timeback.user.enrollments // App-scoped course enrollments
const orgs = client.timeback.user.organizations // App-scoped organizations
// Fetch fresh data from server (cached for 5 min)
const fresh = await client.timeback.user.fetch()
const forced = await client.timeback.user.fetch({ force: true })App-Scoped
Enrollments and organizations are filtered to courses defined in your playcademy.config.js.
startActivity
Start tracking an activity. Only activityId is required:
// Minimal (most common)
client.timeback.startActivity({
activityId: 'math-quiz-1', // automatically derived to "Math Quiz 1"
})
// With custom name override
client.timeback.startActivity({
activityId: 'math-quiz-1',
activityName: 'Advanced Multiplication Quiz',
})Auto-filled Metadata
The SDK automatically fills in metadata from your project config:
- activityName: Derived from activityId ("math-quiz-1" → "Math Quiz 1")
- appName, subject, sensorUrl: From
playcademy.config.{js,json}
You can override any of these by providing them explicitly.
endActivity
End the current activity and submit results:
// 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
}){pause,resume}Activity
Pause the timer during instructional moments and resume when ready:
client.timeback.startActivity({ activityId: 'math-quiz-1' })
// Student attempts problems...
if (studentAnswerWrong) {
// Pause timer to show correct answer
client.timeback.pauseActivity()
// Let student learn from mistake
showCorrectAnswer()
// Resume when they continue playing
client.timeback.resumeActivity()
}
// End activity (only active problem-solving time counted)
await client.timeback.endActivity({
correctQuestions: 8,
totalQuestions: 10,
})See Timeback Integration for complete documentation.
client.backend
Call your backend API routes.
These methods connect to the server-side routes you create in your server/api/ directory.
Learn more here.
Always Use sdk.backend
Don't use plain fetch() for your backend routes.
The SDK automatically includes the platform authentication token, which is required for c.get('playcademyUser') to work in your routes.
// ✅ Correct - includes platform token
const data = await client.backend.get('/my-route')
// ❌ Wrong - playcademyUser will be null
const data = await fetch('/api/my-route').then(r => r.json())get
Make GET requests:
const data = await client.backend.get('/hello')
console.log(data.message)
// With custom headers
const data = await client.backend.get('/protected', {
'X-Custom-Header': 'value',
})post / put / patch
Make requests with body data:
// POST request
const result = await client.backend.post('/validate', {
answer: 'paris',
})
// PUT request
await client.backend.put('/settings', {
volume: 0.8,
})
// PATCH request
await client.backend.patch('/profile', {
displayName: 'NewName',
})delete
Delete resources:
await client.backend.delete('/cache/clear')download
Download binary files:
const response = await client.backend.download('/files?key=report.pdf')
const blob = await response.blob()
// Trigger browser download
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = 'report.pdf'
a.click()
URL.revokeObjectURL(url)Downloading Files
The download method returns a raw Response object, allowing you to access the blob, streams,
or other binary data.
url
Build URLs for HTML elements (images, videos, etc.):
// Tagged template literal (recommended)
const imageUrl = client.backend.url`/assets/${sprite.key}`
<img src={imageUrl} />
// Regular function call
const videoUrl = client.backend.url('/videos/intro.mp4')
<video src={videoUrl} />Perfect for catchall routes that serve files by path.
See Custom Routes and Bucket Storage for more examples.
Runtime & Lifecycle
client.runtime
Game lifecycle events, messaging, and static asset loading.
// Signal ready
client.runtime.ready()
// Exit
client.runtime.exit()
// Listen for pause
client.runtime.onPause(() => {
pauseGame()
})
// Listen for resume
client.runtime.onResume(() => {
resumeGame()
})
// Load static assets at runtime
const levelData = await client.runtime.assets.json`levels/level-${id}.json`
img.src = client.runtime.assets.url`badges/${badgeType}.png`
audio.src = client.runtime.assets.url`sfx/${soundEffect}.wav`Connection Monitoring
The platform automatically monitors connection health and shows baseline alerts to users.
Your application only needs to handle the logic for what to do when a user's connection is degraded or lost.
Platform Shows Baseline Alerts
The platform automatically shows connection alerts ("Connection Lost", "Slow Connection", etc.).
Your onDisconnect handler is just for app-specific logic.
Basic Example
const client = await PlaycademyClient.init({
onDisconnect: async ({ state, displayAlert }) => {
if (state === 'offline') {
// Save critical data and return to safe location
await saveToLocalStorage(appState)
returnToLobby()
// Optional: Add app-specific context
displayAlert('Progress saved locally. Returning to lobby...', { type: 'info' })
}
},
})Pause App on Connection Issues
const client = await PlaycademyClient.init({
onDisconnect: ({ state }) => {
if (state === 'offline' || state === 'degraded') {
pause()
showReconnectingOverlay()
}
},
})
client.on('connectionChange', ({ state }) => {
if (state === 'online') {
hideReconnectingOverlay()
resume()
}
})API Reference
Connection states:
| State | Description |
|---|---|
online | Connection is healthy |
offline | No connectivity |
degraded | Slow/unstable connection |
Methods:
| Method | Description |
|---|---|
client.getConnectionState() | Get current connection state |
client.checkConnection() | Force immediate connection check |
client.onDisconnect(handler) | Register disconnect handler |
client.on('connectionChange', handler) | Listen to connection state changes |
Display custom alerts:
Use displayAlert() to show a toast notification in the top-left corner.
This is the same mechanism and location the platform uses for automatic network degradation alerts.
displayAlert('Custom message', {
type: 'error', // 'info' | 'warning' | 'error'
duration: 5000, // Auto-dismiss in ms (optional)
})Disable monitoring:
const client = await PlaycademyClient.init({
enableConnectionMonitoring: false,
})Event System
Listen for platform events:
// Pause event
client.on('pause', () => {
pause()
})
// Resume event
client.on('resume', () => {
resume()
})
// Credits changed
client.on('creditsChanged', (balance: number) => {
updateBalanceUI(balance)
})
// Item purchased
client.on('itemPurchased', (item: ItemWithId) => {
showItemAcquired(item)
})
// Level up
client.on('levelUp', (status: LevelStatus) => {
showLevelUpAnimation(status)
})
// Exit requested
client.on('exit', () => {
cleanup()
})