Channel storage and live user metadata updates
Hotsock v1.12 introduces channel storage for persistent per-key state on channels and live user metadata updates so clients can change their user metadata (umd) without reconnecting. Both features are designed to reduce the amount of state your backend needs to manage and push more real-time coordination into Hotsock itself.
Channel storage
Channels can now have persistent key-value storage entries that subscribers can read, write, and observe in real-time. Storage entries have independent TTLs for flexible data retention and are automatically delivered to observers when they subscribe.
This is useful for any state that should be available to current and future subscribers of a channel — things like configuration, feature flags, room settings, shared cursors, or game state. Instead of fetching this from your backend after subscribing, the client gets it immediately as part of the subscribe flow.
Setting up permissions
Storage permissions are configured per-key using the new storage directive inside channel claims. Keys support wildcards and regex patterns, just like channel names and event names.
{
"exp": 1743580800,
"scope": "connect",
"channels": {
"game.lobby": {
"subscribe": true,
"storage": {
"settings": {
"observe": true
},
"player.123": {
"observe": true,
"set": true,
"store": 86400,
"emitPubSubEvent": true
}
}
}
}
}
Each storage key directive supports these options:
observe— receivehotsock.channelStorageUpdatedmessages in real-time when the value changes, and get current values automatically on subscribeget— fetch the current value on demand withhotsock.channelStorageGetset— write values withhotsock.channelStorageSetstore— TTL in seconds for entries written by this connectionemitPubSubEvent— trigger ahotsock.channelStorageUpdatedpub/sub event to SNS/EventBridge when a value changes
Writing and reading storage
Clients interact with storage using hotsock.channelStorageSet and hotsock.channelStorageGet messages on the WebSocket, or via the Client HTTP API:
> {"event":"hotsock.channelStorageSet", "channel":"game.lobby", "key":"settings", "data":{"maxPlayers":4}}
> {"event":"hotsock.channelStorageGet", "channel":"game.lobby", "key":"settings"}
< {"event":"hotsock.channelStorageData","channel":"game.lobby","key":"settings","data":{"maxPlayers":4},"meta":{"uid":"host","umd":null}}
Writes that don't change the value are detected automatically and skip subscriber fan-out entirely, so you don't need to worry about deduplication on the client side. Setting data to null or {} clears the entry.
For client-initiated writes, storage entries track the uid and umd of the last writer in meta, so observers know who set a value.
Real-time sync on subscribe
When a connection subscribes to a channel, all storage entries matching their observe patterns are delivered as hotsock.channelStorageUpdated messages immediately after the hotsock.subscribed message. This means a new subscriber gets the current state without any additional requests — they're caught up the moment they join.
Scheduled storage writes
Storage writes support scheduling for future delivery using scheduleExpression, just like scheduled messages. This is useful for things like expiring a game round, resetting a status after a timeout, or setting up state transitions at known times. Client-initiated scheduled writes require the scheduleBefore permission on the matching storage key.
Server-side storage writes
Storage entries can also be set from the server side using the existing Lambda or HTTP publish APIs by specifying "event": "hotsock.channelStorageSet" with a key field. Server-side writes bypass client permission checks, so they're always authorized. This is handy for initializing channel state from your backend before any clients connect.
For a full walkthrough of permissions, TTL behavior, and all the ways to interact with storage, see the channel storage documentation.
Live user metadata updates
Previously, the only way to change a connection's umd was to disconnect and reconnect with a new token, or unsubscribe and resubscribe with a new subscribe token. Now clients can update their umd in place using hotsock.umdUpdate.
This works at two levels:
Per-channel updates
Update umd on a specific channel subscription by sending hotsock.umdUpdate with a channel and a umd-scoped token that has the umdUpdate channel directive:
{
"exp": 1743580800,
"scope": "umd",
"uid": "Dwight",
"umd": { "status": "away" },
"channels": {
"presence.chat": {
"umdUpdate": true
}
}
}
Then send the signed token on the WebSocket:
> {"event":"hotsock.umdUpdate", "channel":"presence.chat", "data":{"token":"eyJ..."}}
On presence channels, this triggers a new hotsock.memberUpdated event delivered to all members (including the initiator), so everyone sees the change immediately:
< {"event":"hotsock.memberUpdated","channel":"presence.chat","data":{"member":{"uid":"Dwight","umd":{"status":"away"}},"members":[{"uid":"Jim","umd":null},{"uid":"Dwight","umd":{"status":"away"}}]}}
This is great for status indicators, typing states, or any per-user metadata that changes during a session.
Connection-level updates
Update the connection's default umd by sending hotsock.umdUpdate without a channel. This requires the top-level umdUpdate claim. When umdPropagate is also enabled, the updated metadata is propagated to all existing subscriptions on the connection, triggering hotsock.memberUpdated on any presence channels.
{
"exp": 1743580800,
"scope": "umd",
"uid": "Dwight",
"umd": { "status": "away" },
"umdUpdate": true,
"umdPropagate": true
}
> {"event":"hotsock.umdUpdate", "data":{"token":"eyJ..."}}
Future subscriptions that are authorized by the connect token (implicit subscriptions) will automatically inherit the updated metadata from the connection, so you don't need to include the new umd in every subsequent subscribe token.
Both paths are also available via the Client HTTP API at connection/umdUpdate.
New pub/sub event
A new hotsock.connectionUpdated pub/sub event is emitted to SNS/EventBridge when a connection's user metadata actually changes, so you can track user state changes on your backend.
Wrapping up
Existing installations with auto-update enabled are already running v1.12 and have access to these features today. Other installations can be manually updated at any time. A full changelog is available with the complete list of changes included in this release.
