Sessions Management
Last Updated: 2026-01-08
Native session lifecycle management for user-facing agentic platforms with multi-device support, activity tracking, and configurable timeouts.
Overview
Cortex provides built-in session management through the cortex.sessions.* API. Sessions track user interactions, manage activity timeouts, and provide isolated context for conversations.
Why Sessions Matter:
- Multi-Device Support: Users can have concurrent sessions (web, mobile, API) with activity tracked per device
- Activity-Based Lifecycle: Automatic idle detection and session expiration protect resources
- Context Isolation: Sessions provide a boundary for conversation context
- Analytics Ready: Built-in tracking of message counts, memory usage, and activity patterns
Quick Start
import { Cortex } from "@cortex-platform/sdk";
const cortex = new Cortex({
convexUrl: process.env.CONVEX_URL!,
});
// Start a session when user connects
const session = await cortex.sessions.create({
userId: "user-123",
metadata: {
deviceType: "web",
userAgent: navigator.userAgent,
},
});
// Keep session alive with heartbeat
await cortex.sessions.touch(session.sessionId);
// End session on logout
await cortex.sessions.end(session.sessionId);
Session Lifecycle
Sessions follow a three-state lifecycle:
Default Timeouts:
| State | Timeout | Description |
|---|---|---|
| Active | 30m | No activity moves session to idle |
| Idle | 24h | After 24h idle, session is ended |
Timeouts are configurable via the Governance Policies.
Core Operations
Creating Sessions
// Create a new session
const session = await cortex.sessions.create({
userId: "user-123",
tenantId: "tenant-abc", // Optional: multi-tenant isolation
memorySpaceId: "personal", // Optional: associate with memory space
metadata: {
deviceType: "mobile",
appVersion: "2.1.0",
platform: "ios",
},
});
// Or get existing session if active, create new if not
const session = await cortex.sessions.getOrCreate("user-123", {
deviceType: "web",
});
Activity Tracking
Keep sessions alive by calling touch() on user interactions:
// Update activity timestamp
await cortex.sessions.touch(session.sessionId);
// Prevents session from going idle
// Call on message send, page navigation, etc.
Ending Sessions
// End single session (on logout)
await cortex.sessions.end(session.sessionId);
// End all sessions for user (on password change)
const result = await cortex.sessions.endAll("user-123");
console.log(`Ended ${result.ended} sessions`);
// End sessions for specific tenant only
await cortex.sessions.endAll("user-123", {
tenantId: "tenant-abc",
});
Querying Sessions
// Get specific session
const session = await cortex.sessions.get("session-xyz");
// List active sessions for user
const activeSessions = await cortex.sessions.list({
userId: "user-123",
status: "active",
});
// Count sessions by status
const activeCount = await cortex.sessions.count({
tenantId: "tenant-abc",
status: "active",
});
console.log(`${activeCount} users currently online`);
Real-World Patterns
Session Resume Flow
Automatically resume existing sessions when users reconnect:
async function handleUserConnection(
userId: string,
deviceInfo: Record<string, unknown>,
) {
// Try to resume existing active session
const existingSessions = await cortex.sessions.getActive(userId);
if (existingSessions.length > 0) {
const session = existingSessions[0];
await cortex.sessions.touch(session.sessionId);
return session;
}
// Create new session
return cortex.sessions.create({
userId,
metadata: deviceInfo,
});
}
Multi-Device Management
Show users their active devices and allow remote logout:
// Get all active sessions for "active devices" UI
async function getActiveSessions(userId: string) {
const sessions = await cortex.sessions.getActive(userId);
return sessions.map((s) => ({
id: s.sessionId,
device: s.metadata?.deviceType || "unknown",
lastActive: new Date(s.lastActiveAt),
isCurrent: s.sessionId === currentSessionId,
}));
}
// Logout from all other devices
async function logoutOtherDevices(userId: string, currentSessionId: string) {
const sessions = await cortex.sessions.getActive(userId);
for (const session of sessions) {
if (session.sessionId !== currentSessionId) {
await cortex.sessions.end(session.sessionId);
}
}
}
Session Analytics Dashboard
Track platform engagement:
async function getSessionStats(tenantId: string) {
const [active, idle, ended] = await Promise.all([
cortex.sessions.count({ tenantId, status: "active" }),
cortex.sessions.count({ tenantId, status: "idle" }),
cortex.sessions.count({ tenantId, status: "ended" }),
]);
return {
currentlyOnline: active,
recentlyActive: idle,
totalSessions: active + idle + ended,
};
}
Background Session Cleanup
Run periodic cleanup of idle sessions:
// Background job (e.g., cron every 15 minutes)
async function cleanupIdleSessions() {
const result = await cortex.sessions.expireIdle({
tenantId: "tenant-abc",
idleTimeout: 30 * 60 * 1000, // 30 minutes
});
console.log(`Expired ${result.expired} idle sessions`);
}
Session Metadata
The metadata field is fully flexible and stores any data your application needs:
// Device and client info
await cortex.sessions.create({
userId: "user-123",
metadata: {
deviceType: "mobile",
appVersion: "2.1.0",
platform: "ios",
deviceId: "device-xyz",
},
});
// Auth provider claims
await cortex.sessions.create({
userId: "user-123",
metadata: {
authProvider: "auth0",
authMethod: "oauth",
email: "user@example.com",
roles: ["admin", "editor"],
permissions: ["read", "write", "delete"],
},
});
// Geographic context
await cortex.sessions.create({
userId: "user-123",
metadata: {
ipAddress: "192.168.1.1",
country: "US",
timezone: "America/New_York",
locale: "en-US",
},
});
Multi-Tenancy
Sessions support full multi-tenant isolation:
// Create tenant-scoped session
const session = await cortex.sessions.create({
userId: "user-123",
tenantId: "customer-abc", // SaaS platform isolation
metadata: { ... },
});
// Query sessions within tenant
const tenantSessions = await cortex.sessions.list({
tenantId: "customer-abc",
status: "active",
});
When using Auth Context, tenantId is automatically injected:
import { createAuthContext } from "@cortex-platform/sdk";
const auth = createAuthContext({
userId: "user-123",
sessionId: "session-xyz",
tenantId: "tenant-abc", // Auto-injected to all operations
});
const cortex = new Cortex({
convexUrl: process.env.CONVEX_URL!,
auth,
});
// tenantId is automatically applied
const session = await cortex.sessions.create({
userId: "user-123",
// tenantId auto-injected from auth context
});
GDPR Compliance
Sessions are included in GDPR cascade deletion:
// When deleting a user, all their sessions are deleted
await cortex.users.delete("user-123", { cascade: true });
// Cascade includes:
// - User profile
// - All sessions for user
// - All conversations
// - All memories
// - All facts
// - Graph nodes (if configured)
Error Handling
The Sessions API throws SessionValidationError for validation failures:
import { SessionValidationError } from "@cortex-platform/sdk";
try {
await cortex.sessions.create({
userId: "", // Invalid: empty userId
});
} catch (error) {
if (error instanceof SessionValidationError) {
console.log(`Validation error: ${error.message}`);
console.log(`Code: ${error.code}`); // e.g., "EMPTY_USER_ID"
console.log(`Field: ${error.field}`); // e.g., "userId"
}
}
Common Validation Errors:
| Code | Description |
|---|---|
MISSING_USER_ID | userId is required |
EMPTY_USER_ID | userId cannot be empty |
INVALID_STATUS_VALUE | status must be: active, idle, or ended |
INVALID_LIMIT | limit must be between 1 and 1000 |
Related Features
- User Profiles - User management and GDPR deletion
- Governance Policies - Configure session lifecycle policies
- Memory Spaces - Associate sessions with memory spaces
- Resilience Layer - Built-in protection for session operations