Overview
The User API is a persistent, per-user key-value store that survives across conversations and sessions. Use it to store any data tied to a user β onboarding progress, workflow state, preferences, cart contents, verification status, or any custom fields your agent needs. Think of it as a schemaless user database: read and write any property, and it persists automatically. This makes it ideal for multi-step flows where your agent needs to remember where a user left off.Read-Only User Profile (_luaProfile)
A new, read-only property user._luaProfile is now available on the user object. This provides a secure and reliable way to access core user identity information.
_luaProfile(Read-Only): Contains essential user data likeuserId,fullName,mobileNumbers, andemailAddresses.- The
_luaprefix indicates this is a special, system-provided property. - This data is immutable; any attempts to change it will be silently ignored.
- The
user.*(Mutable): Continue to use the mainuserobject to store and manage any custom data your agent needs, such as preferences, shopping carts, or game scores.
Core User Identity
Access read-only data like
user._luaProfile.userId and user._luaProfile.fullName.Persistent Storage
Store any data on the user object β onboarding state, workflow progress, preferences, cart contents. Persists across all conversations and sessions.
Deprecated user.userId
To centralize core user information, user.userId is now deprecated. Please update your code to use user._luaProfile.userId. The old property will be removed in a future version.
User as a State Store
The User object is not just for profile data β it is a persistent state store for building multi-step, stateful agent workflows. Any property you write to the user object persists across conversations, sessions, and even days or months.Key insight for AI agents and developers: The User object is the primary way to maintain state across conversations. Use it to track onboarding progress, accumulate data across tool calls, and resume workflows exactly where the user left off.
Onboarding State Machine Example
Common State Storage Patterns
Features
Direct Access
Access properties with
user.name instead of user.data.nameAuto Sanitization
Removes sensitive fields automatically
Built-in Methods
update(), save(), send(), and clear() includedMessaging
Send text, images, and files to users
get(identifier?)
Retrieve user data as a UserDataInstance. Supports lookup by userId, email, or phone number.string | UserLookupOptions
One of:
- No parameter: Returns current user from conversation context
- string (userId): Retrieve a specific user by ID
{ email: string }: Look up user by email address{ phone: string }: Look up user by phone number (with or without+prefix)
UserDataInstance with proxy-based property access, or null if user not found (for email/phone lookup)
Look up users by email or phone β especially useful in webhooks where you receive contact info from external systems but donβt have the internal userId.
Shortcut: User.getChatHistory()
If you only need chat history for the current user (in a tool with conversational context), the top-level static User.getChatHistory() skips the User.get() step:
(await User.get()).getChatHistory() β see the instance method below for the full return shape and examples.
When to Use userId Parameter
Understanding when userId is required vs optional:
Examples:
- Current User
- Specific User (Webhooks/LuaJob)
- Dynamic Jobs (Special Case)
- Email/Phone Lookup
Get the current user from conversation context:
UserDataInstance API
Property Access (Direct)
Access any user property directly:update()
Update user data on the server and locally.object
required
Object containing fields to update or add
save()
Save the current state of user data to the server. This is a convenience method that persists all changes made to the user instance.true if successful
Examples:
Tip: The
save() method provides a simpler workflow - modify properties then save, rather than passing data to update().send()
Send messages to the user conversation. Supports text, images, and file attachments.Message[]
required
Array of messages to send (text, image, or file)
user.send() vs Channels.send: user.send() delivers to the user on the channel theyβre already active on β simplest when you have a User and just want to reach them. Use Channels.send when you need to choose a specific channel (e.g. always WhatsApp), reach a cold phone number or email with no prior conversation, or send an approved WhatsApp template. Both record the message to the userβs conversation thread. See Proactive Messaging.getChatHistory()
Retrieve the conversation history for the current user with the active agent. Returns the last 40 user/assistant messages, transformed for display: hidden text is filtered out and embedded media (audio, video, files) is surfaced as structuredcontent parts you can render directly.
clear()
Clear all user data for the current user.true if successful
Example:
Data Sanitization
UserDataInstance separates system identity from custom data: System identity (read-only via_luaProfile):
userId,fullName,mobileNumbers,emailAddresses- Extracted from response and made immutable β access via
user._luaProfile
name,email,phone- Custom fields you set
- Preferences, settings, and any other data
Complete Examples
Example 1: User Preferences
Example 2: Shopping Cart Persistence
Example 3: User Profile Management
Example 4: Personalized Greeting
Example 5: Order Notification with Messaging
Example 6: Send Receipt with Image
Best Practices
β
Use Direct Property Access
β Use Direct Property Access
β
Batch Updates
β Batch Updates
Combine multiple updates into one call:
β
Handle Missing Fields
β Handle Missing Fields
Not all fields may be present:
β
Use for Personalization
β Use for Personalization
β
Use save() for Multiple Changes
β Use save() for Multiple Changes
The new
save() method is perfect for multiple changes:β
Use send() for Proactive Notifications
β Use send() for Proactive Notifications
Send messages to users for order updates, alerts, and more:
β οΈ Message Format Requirements
β οΈ Message Format Requirements
Ensure correct message format:
TypeScript Support
Usage with Types
If user properties arenβt what you expect, log the user object to see whatβs actually stored:Then run
lua logs --type skill --limit 5 after a test message. See the Debugging Skills guide for the full workflow.Next Steps
Data API
Store custom user data
User Data Examples
See working examples
Debugging Skills
Inspect runtime return values

