Skip to content

Presentation Sessions

Sessions enable real-time synchronization between presenters and audience members during live presentations.

When you present a deck, a session is created to coordinate state across all connected clients. The session tracks which slide is active, handles follow codes, and broadcasts updates via Server-Sent Events (SSE).

  1. Create - Presenter starts presenting, session created
  2. Active - Audience joins, state synchronized
  3. Update - Presenter navigates, state broadcast
  4. Expire - No activity for 30 minutes, session cleaned up

Each session stores:

{
sessionId: 'abc123',
presentationId: 'pres456',
state: {
slideId: 'slide789',
slideIndex: 3,
slideType: 'content-slide',
stepIdx: 0,
stepParagraphs: false,
updatedAt: 1705312200000
},
controlEnabled: false,
followCodes: {
nl: 'ABCD',
en: 'EFGH'
},
followCodesCreatedAt: 1705312200000,
createdAt: 1705312200000,
lastActivityAt: 1705312200000,
clients: Set(),
heartbeatTimers: Map()
}
POST /api/present/session
Content-Type: application/json
{
"presentationId": "abc123"
}
{
"sessionId": "xyz789",
"joinPath": "/notes/xyz789",
"followCodes": {
"nl": "ABCD",
"en": "EFGH"
}
}

If an active session exists for the presentation, it’s reused:

  • Same session ID returned
  • Follow codes refreshed if expired
  • Activity timestamp updated
PropertyDescription
slideIdCurrent slide’s unique ID
slideIndex0-based slide position
slideTypeType of current slide
stepIdxBuild step within slide
stepParagraphsParagraph-level stepping enabled
updatedAtLast state change timestamp

When presenter navigates:

PATCH /api/present/session/:sessionId/state
Content-Type: application/json
{
"slideId": "slide789",
"slideIndex": 5,
"stepIdx": 2
}

State is broadcast to all connected clients via SSE.

Short, easy-to-share codes for audience to join.

https://your-instance.com/go
Code: ABCD
  • 4 uppercase letters
  • One code per language
  • Valid for 24 hours

When audience enters a code:

  1. Code looked up in database
  2. Target URL returned
  3. Viewer redirected to follow view
  4. SSE connection established

Codes are automatically refreshed:

  • When they expire (24 hours)
  • Session must still be active
  • Presenter sees updated codes

Clients connect to receive updates:

const eventSource = new EventSource(
'/api/present/session/ABC123/events'
);

On connection, clients receive:

  • Current state snapshot
  • Control enabled status
EventDescription
stateSlide navigation
controlEnabledAudience control toggle
deckUpdatedPresentation content changed
interactionStatePoll/Q&A updates
branchNavigate to branched slide

See Real-Time Updates for details.

Allow audience to self-navigate:

PATCH /api/present/session/:sessionId/control
Content-Type: application/json
{
"enabled": true
}
  • Disabled (default) - Audience locked to presenter’s slide
  • Enabled - Audience can navigate freely

Control state changes are broadcast to all clients.

Sessions expire after 30 minutes of inactivity.

These actions reset the timer:

  • State updates
  • Client connections
  • Control toggles
  • Any API calls to session

Expired sessions are:

  • Removed from memory
  • Cleaned from disk storage
  • Follow codes invalidated

Sessions can be explicitly closed:

DELETE /api/present/session/:sessionId

Active sessions are stored in memory for performance.

Sessions are periodically saved to disk:

  • On state changes (debounced)
  • On graceful shutdown
  • Loaded on server restart
./server/data/present-sessions/

Multiple users can present the same deck:

  • Same session is reused
  • State updates from any presenter
  • All audience members see same state

Last write wins - the most recent navigation is broadcast.

Keep SSE connections alive through proxies.

Every 30 seconds:

: heartbeat

Each client has its own heartbeat timer:

  • Created on connection
  • Cleared on disconnect
  • Used to detect stale connections

Default: sessions stored in memory, persisted to disk.

For multiple servers:

  • Use Redis for session storage
  • Use Redis pub/sub for broadcasts
  • Sticky sessions or distributed coordination
POST /api/present/session
GET /api/present/session/:sessionId
PATCH /api/present/session/:sessionId/state
PATCH /api/present/session/:sessionId/control
DELETE /api/present/session/:sessionId
GET /api/present/session/:sessionId/events
  • Session may have expired
  • Check sessionId is correct
  • Verify session was created
  • Code may have expired (24 hours)
  • Check code was typed correctly
  • Verify session is still active
  • Check SSE connection is open
  • Verify no network issues
  • Look for errors in browser console
  • Many concurrent sessions
  • Large numbers of connected clients
  • Consider horizontal scaling