Skip to main content

User ID Management

Learn how to manage user identity and maintain conversation persistence across sessions using the Estuary SDK.

Overview

User ID management is crucial for:

  • Conversation Persistence: Continue conversations where the user left off
  • Context Retention: AI remembers previous interactions
  • User Personalization: Tailor experiences based on history

The Estuary SDK provides automatic User ID management through the EstuaryCredentials component.


How User IDs Work

Each user is identified by a unique userId (also called playerId in the SDK). This ID is sent with every connection to the Estuary server.

┌─────────────────────────────────────────────────────────────┐
│ User ID Flow │
├─────────────────────────────────────────────────────────────┤
│ │
│ Session 1 (First Use) │
│ ┌────────────────────┐ ┌────────────────────┐ │
│ │ EstuaryCredentials │---→│ Generate User ID │ │
│ │ (userId empty) │ │ "spectacles_abc123"│ │
│ └────────────────────┘ └─────────┬──────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────┐ │
│ │ Store in Device │ │
│ │ PersistentStorage │ │
│ └───────────────────┘ │
│ │
│ Session 2+ (Return User) │
│ ┌────────────────────┐ ┌────────────────────┐ │
│ │ EstuaryCredentials │---→│ Load from Storage │ │
│ │ (userId empty) │ │ "spectacles_abc123"│ │
│ └────────────────────┘ └─────────┬──────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────┐ │
│ │ Same User ID! │ │
│ │ Conversation │ │
│ │ Context Restored │ │
│ └───────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘

Automatic User ID Management

The EstuaryCredentials component handles User IDs automatically:

Priority Order

  1. Manual ID (if userIdField is set in Inspector) → Used and stored
  2. Stored ID (from device's PersistentStorage) → Loaded and used
  3. Generated ID (if no stored ID exists) → Created and stored

Default Behavior

// When EstuaryCredentials initializes, it:

// 1. Checks if userIdField has a value
if (this.userIdField && this.userIdField.length > 0) {
this._resolvedUserId = this.userIdField;
store.putString("estuary_user_id", this._resolvedUserId);
// Manual ID will be used and persisted
}

// 2. Otherwise, tries to load from storage
else if (store.has("estuary_user_id")) {
this._resolvedUserId = store.getString("estuary_user_id");
// Previous session's ID restored
}

// 3. Otherwise, generates a new ID
else {
this._resolvedUserId = "spectacles_" + Date.now().toString(36);
store.putString("estuary_user_id", this._resolvedUserId);
// New user, new ID
}

Configuration Options

In the EstuaryCredentials component Inspector:

FieldDescription
User IDLeave empty for automatic management, or enter a specific ID

Console Output

When initialized, EstuaryCredentials logs the User ID:

╔════════════════════════════════════════════════════════════╗
║ ESTUARY USER ID: spectacles_lq8x7k4j ║
╚════════════════════════════════════════════════════════════╝

Manual User ID Setting

For Testing Specific Conversations

You can set a specific User ID to test or resume a specific conversation:

  1. Open EstuaryCredentials in the Inspector
  2. Enter the desired User ID in the User ID field
  3. This ID will be used and stored for future sessions
// In Inspector:
userIdField: "test_user_12345"

// Result:
// - Uses "test_user_12345" for this and future sessions
// - Previous conversation with this ID will be restored

Programmatic User ID

For dynamic User ID assignment:

@component
export class CustomUserManagement extends BaseScriptComponent {

onAwake() {
// Create character with specific user ID
const userId = this.getOrCreateUserId();
const character = new EstuaryCharacter(characterId, userId);
}

private getOrCreateUserId(): string {
const store = global.persistentStorageSystem.store;

// Check for existing ID
if (store.has("my_custom_user_id")) {
return store.getString("my_custom_user_id");
}

// Generate new ID based on your logic
const newId = this.generateCustomId();
store.putString("my_custom_user_id", newId);
return newId;
}

private generateCustomId(): string {
// Your custom ID generation logic
return `user_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
}

Accessing the User ID

From EstuaryCredentials Singleton

import { EstuaryCredentials } from 'estuary-lens-studio-sdk';

// Check if credentials exist
if (EstuaryCredentials.hasInstance) {
const userId = EstuaryCredentials.instance.userId;
print(`Current User ID: ${userId}`);
}

From Session Info

After connecting, the session info includes the player ID:

character.on('connected', (session: SessionInfo) => {
print(`Session ID: ${session.sessionId}`);
print(`Player ID: ${session.playerId}`);
print(`Conversation ID: ${session.conversationId}`);
});

The conversationId is particularly useful - it remains the same across sessions for the same user, enabling conversation continuity.


Conversation Persistence

How It Works

When a user reconnects with the same User ID:

  1. Server recognizes the playerId
  2. Loads previous conversation history
  3. AI has full context of past interactions
  4. Conversation continues seamlessly

Session vs Conversation

ConceptDescriptionPersistence
Session IDUnique per connectionChanges each connect
Player IDUser identifierPersists on device
Conversation IDThread identifierTied to Player ID

Resetting User Identity

Clear Stored User ID

To start fresh (new user, new conversation):

// Clear the stored User ID
const store = global.persistentStorageSystem.store;
store.remove("estuary_user_id");

// Next initialization will generate a new ID

Force New Conversation

Alternatively, use a different User ID format:

// Generate unique ID per session (no persistence)
const sessionOnlyId = `session_${Date.now()}`;
const character = new EstuaryCharacter(characterId, sessionOnlyId);

Multi-User Scenarios

For experiences with multiple users:

@component
export class MultiUserManager extends BaseScriptComponent {

private users: Map<string, EstuaryCharacter> = new Map();

/**
* Create or get a character instance for a specific user
*/
getCharacterForUser(userId: string): EstuaryCharacter {
if (this.users.has(userId)) {
return this.users.get(userId)!;
}

const character = new EstuaryCharacter(
characterId,
userId
);

this.users.set(userId, character);
return character;
}

/**
* Switch active user
*/
switchToUser(userId: string) {
const character = this.getCharacterForUser(userId);
EstuaryManager.instance.setActiveCharacter(character);
}
}

Best Practices

Let the SDK Manage IDs

Unless you have specific requirements, let EstuaryCredentials handle User IDs automatically:

// Just leave userIdField empty in Inspector
// SDK handles generation and persistence

Don't Expose User IDs

User IDs should be treated as internal identifiers:

// Don't show to users
print(`Your ID is: ${userId}`);

// Keep internal
// Just use for conversation persistence

Handle Storage Errors Gracefully

try {
const store = global.persistentStorageSystem.store;
userId = store.getString("estuary_user_id");
} catch (e) {
// Fall back to generated ID
userId = this.generateFallbackId();
}

Consider Privacy

  • User IDs should not contain personal information
  • Generated IDs are random and anonymous
  • No user data is stored in the ID itself

Troubleshooting

User ID Not Persisting

  1. Ensure EstuaryCredentials is in your scene
  2. Check that it runs before other Estuary components
  3. Verify PersistentStorageSystem is available

Wrong Conversation Context

If the AI doesn't remember previous conversations:

  1. Verify the same User ID is being used
  2. Check console for the User ID banner
  3. Try setting the ID manually in Inspector

Multiple IDs Being Generated

If a new ID is generated each session:

  1. Check for errors in PersistentStorage
  2. Ensure the storage key isn't being cleared elsewhere
  3. Verify EstuaryCredentials.onAwake() is running

Next Steps