AppSession represents one user’s active connection to your app. Each time a user starts your app on their glasses, a new AppSession is created with a unique ID.
Core Concept
When you extend AppServer, you override onSession() which receives an AppSession object:
import { AppServer , AppSession } from '@mentraos/sdk' ;
class MyApp extends AppServer {
protected async onSession ( session : AppSession , sessionId : string , userId : string ) {
// 'session' is the AppSession object
// Use it to interact with this user's glasses
}
}
What AppSession Provides
AppSession is your interface to everything happening on the user’s glasses:
Property Purpose session.eventsSubscribe to data streams (voice, buttons, sensors) session.layoutsUpdate what displays on glasses session.audioPlay audio, text-to-speech, capture voice session.cameraTake photos, stream video session.ledControl LED lights session.locationAccess GPS location session.dashboardShow persistent status info session.simpleStorageStore user preferences and data session.settingsAccess app settings from dev console session.capabilitiesCheck what hardware is available session.loggerStructured logging with session context
Session Lifecycle
1. Session Starts
Cloud calls your onSession() with:
session - The AppSession object
sessionId - Unique ID (UUID string)
userId - User’s ID (email)
protected async onSession ( session : AppSession , sessionId : string , userId : string ) {
session . logger . info ( 'Session started' , { sessionId , userId });
// Set up your app for this user
this . setupApp ( session );
}
2. Session is Active
Use the session object to interact with glasses:
protected async onSession ( session : AppSession , sessionId : string , userId : string ) {
// Display content
session . layouts . showTextWall ( 'Welcome!' );
// Listen for voice input
session . events . onTranscription (( data ) => {
session . logger . info ( 'User said:' , data . text );
});
// Play audio
session . audio . playTTS ( 'Hello from your app' );
}
3. Session Ends
Session ends when:
User stops the app
Glasses disconnect
Network error occurs
Your server calls session.disconnect()
protected async onStop ( sessionId : string , userId : string , reason : string ) {
// Clean up resources
console . log ( `Session ${ sessionId } ended: ${ reason } ` );
}
The session object is NOT available in onStop(). Do cleanup that doesn’t require the session object.
One Session Per User
Each user gets their own isolated AppSession:
class MyApp extends AppServer {
private sessions = new Map < string , AppSession >();
protected async onSession ( session : AppSession , sessionId : string , userId : string ) {
// Store this user's session
this . sessions . set ( sessionId , session );
session . layouts . showTextWall ( `Active users: ${ this . sessions . size } ` );
// Each user has independent state
session . events . onTranscription (( data ) => {
// Only this user's voice data
session . layouts . showTextWall ( `You said: ${ data . text } ` );
});
}
protected async onStop ( sessionId : string , userId : string , reason : string ) {
this . sessions . delete ( sessionId );
}
}
Key points:
Sessions don’t interfere with each other
Each has separate event subscriptions
Each has separate display state
Each has separate storage (via userId)
Access session details:
protected async onSession ( session : AppSession , sessionId : string , userId : string ) {
// Session identifiers
console . log ( 'Session ID:' , sessionId ); // UUID
console . log ( 'User ID:' , userId ); // Email address
// Device capabilities
if ( session . capabilities ) {
console . log ( 'Device:' , session . capabilities . modelName );
console . log ( 'Has camera:' , session . capabilities . hasCamera );
console . log ( 'Has display:' , session . capabilities . hasDisplay );
}
// User settings from dev console
const theme = session . settings . get ( 'theme' , 'light' );
// User's stored data
const savedData = await session . simpleStorage . get ( 'preferences' );
}
Working with Sessions
Store Session References
class MyApp extends AppServer {
private userSessions = new Map < string , AppSession >();
protected async onSession ( session : AppSession , sessionId : string , userId : string ) {
// Store by sessionId for cleanup
this . userSessions . set ( sessionId , session );
// Or store by userId to find user's session later
this . userSessions . set ( userId , session );
}
// Helper to get a user's session
private getSessionForUser ( userId : string ) : AppSession | undefined {
return this . userSessions . get ( userId );
}
}
Session-Scoped State
protected async onSession ( session : AppSession , sessionId : string , userId : string ) {
// Store state specific to this session
const sessionState = {
startTime: Date . now (),
messageCount: 0 ,
currentView: 'home'
};
session . events . onTranscription (( data ) => {
sessionState . messageCount ++ ;
if ( data . text . includes ( 'stats' )) {
const duration = Date . now () - sessionState . startTime ;
session . layouts . showTextWall (
`Messages: ${ sessionState . messageCount } \n ` +
`Time: ${ Math . floor ( duration / 1000 ) } s`
);
}
});
}
Cross-Session Communication
class ChatApp extends AppServer {
private activeSessions = new Map < string , AppSession >();
protected async onSession ( session : AppSession , sessionId : string , userId : string ) {
this . activeSessions . set ( sessionId , session );
// Broadcast to all connected users
session . events . onTranscription (( data ) => {
if ( data . isFinal ) {
this . broadcastMessage ( userId , data . text );
}
});
}
private broadcastMessage ( fromUserId : string , message : string ) {
// Send to all active sessions
for ( const [ sid , sess ] of this . activeSessions ) {
sess . layouts . showTextWall ( ` ${ fromUserId } : ${ message } ` );
}
}
protected async onStop ( sessionId : string , userId : string , reason : string ) {
this . activeSessions . delete ( sessionId );
}
}
Important Notes
Don’t share AppSession objects between users. Each session is isolated and user-specific.
UserId is persistent for each user
If a user stops and restarts your app, they get the same userId.
Use session.logger for debugging. It automatically includes session context in logs.
Quick Reference
protected async onSession ( session : AppSession , sessionId : string , userId : string ) {
// Display
session . layouts . showTextWall ( 'Hello' );
// Events
session . events . onTranscription ( data => {});
session . events . onButtonPress ( data => {});
// Audio
await session . audio . playTTS ( 'Hello' );
// Storage
await session . simpleStorage . set ( 'key' , 'value' );
const val = await session . simpleStorage . get ( 'key' );
// Settings
const setting = session . settings . get ( 'settingKey' , 'default' );
// Capabilities
if ( session . capabilities ?. hasCamera ) {
await session . camera . requestPhoto ();
}
// Logging
session . logger . info ( 'Message' , { extra: 'data' });
// Disconnect
session . disconnect ();
}
Next Steps
Display & UI Control what shows on glasses
Events & Data Subscribe to real-time streams
Device Control Use audio, camera, LED, location
API Reference Complete AppSession documentation