Realtime Store - Flutter
The Realtime Store allows you to store, update, retrieve, and observe custom key-value data within a room — in real time. It acts as a shared data layer across all connected participants, ensuring synchronized states throughout the session.
This is particularly useful for collaborative or stateful room experiences such as:
- Pinned messages and flags
- Moderation data (e.g., blocked users)
- Collaborative notes or polls
Every RealtimeStore method needs a joined room, so call them from your Events.roomJoined handler or later. Called before the room is joined, they throw a VideoSDKError with code 3035. When the SDK refuses a call, it throws a VideoSDKError. Wrap each call in try/catch.
setValue()
The setValue() method is used to store or update data in the RealtimeStore. If a key already exists, it will be overwritten with the new value. Passing null as the value deletes the key.
Key Notes
- Supports String values only.
- Each key can store up to 1 KB of data (1024 bytes of UTF-8).
- A maximum of 100 keys are allowed per session.
- Deletion is performed by setting the value to
null. - Throws a
VideoSDKErrorif:- The key is empty or only whitespace (
3073). - The value is empty or only whitespace (
3073). Usenullto delete a key. - The value is larger than 1 KB (
3072). - The room has not been joined yet. This throws a
VideoSDKErrorwith code3035. - The request fails. This throws a
VideoSDKError, for example4045(FAILED_TO_SET_VALUE), or3065(ERROR_ROOM_RECONNECTING) while the room reconnects. - The session exceeds the 100-key limit.
- The key is empty or only whitespace (
Parameters
-
key(String)
The unique key to store the data under. -
value(String?)
The string value to be stored. Passnullto delete the key.
Example
import 'package:flutter/material.dart';
import 'package:videosdk/videosdk.dart';
class RoomScreen extends StatefulWidget {
//Existing configuration
}
class _RoomScreenState extends State<RoomScreen> {
late Room _room;
@override
void initState() {
super.initState();
_room = VideoSDK.createRoom(
roomId: widget.roomId,
token: widget.token,
participantName: "User1",
micEnabled: true,
camEnabled: true,
defaultCamera: FacingMode.FRONT,
multiStream: true,
mode: Mode.SEND_AND_RECV,
);
_joinRoom();
}
Future<void> _joinRoom() async {
try {
await _room.join();
} on VideoSDKError catch (e) {
print("Join failed: ${e.code} ${e.name}");
}
}
@override
void dispose() {
// Leave the room when the screen closes. The room releases itself.
_room.leave().catchError((Object e) => print("Leave failed: $e"));
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(children: [
ElevatedButton(
onPressed: () async {
String key = "BLOCK_CHAT";
String value = "true";
try {
await _room.realtimeStore.setValue(key, value);
} catch (e) {
print("Error:$e");
}
},
child: const Text("Realtime Store Set Value"),
),
]);
}
}
getValue()
The getValue() method retrieves the current value associated with a given key.
Key Notes
- Returns the current string value for the given key, or
nullwhen the server answers with no value. A key that is not set throws4046. - Useful for fetching shared state when joining a room or reloading a view.
- Throws a
VideoSDKError:3073for an empty key,3035if the room has not been joined yet,4046(FAILED_TO_GET_VALUE) when the key is not set or was cleared, or another code if the request fails.
Parameters
key(String)
The key whose value you want to retrieve. It must not be empty.
Example
import 'package:flutter/material.dart';
import 'package:videosdk/videosdk.dart';
class RoomScreen extends StatefulWidget {
//Existing configuration
}
class _RoomScreenState extends State<RoomScreen> {
late Room _room;
String? _response;
@override
void initState() {
super.initState();
_room = VideoSDK.createRoom(
roomId: widget.roomId,
token: widget.token,
participantName: "User1",
micEnabled: true,
camEnabled: true,
defaultCamera: FacingMode.FRONT,
multiStream: true,
mode: Mode.SEND_AND_RECV,
);
_joinRoom();
}
Future<void> _joinRoom() async {
try {
await _room.join();
} on VideoSDKError catch (e) {
print("Join failed: ${e.code} ${e.name}");
}
}
@override
void dispose() {
// Leave the room when the screen closes. The room releases itself.
_room.leave().catchError((Object e) => print("Leave failed: $e"));
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(children: [
ElevatedButton(
onPressed: () async {
String key = "BLOCK_CHAT";
try {
String? response = await _room.realtimeStore.getValue(key);
setState(() => _response = response);
} catch (e) {
print("Error:$e"); // 4046 when the key is not set
}
},
child: Text("Realtime Store Get Value: $_response"),
),
]);
}
}
observe()
The observe() method subscribes a listener to real-time updates for a given key. When the key’s value changes, your listener runs for every participant observing that key.
Key Notes
- Returns nothing. The listener itself identifies the observation: pass the same function to
stopObserving(). - The listener receives the new value and information about who updated it.
- Observing a key subscribes to it on the server, so every change, from any participant, reaches your listener until you stop observing.
- Ideal for syncing live data like timers, shared notes, or agendas.
- Throws a
VideoSDKError:3035if the room has not been joined yet, or another code if the request fails.
Parameters
-
key(String)
The key to observe. An empty key observes nothing. -
listener(void Function(String? value, Participant? updatedBy)) Function triggered on each update. Receives:value(String?) → Updated value ornullif deletedupdatedBy(Participant?) → Object of participant who made the update, ornullif that participant is no longer in the room
Example
import 'package:flutter/material.dart';
import 'package:videosdk/videosdk.dart';
class RoomScreen extends StatefulWidget {
//Existing configuration
}
class _RoomScreenState extends State<RoomScreen> {
late Room _room;
@override
void initState() {
super.initState();
_room = VideoSDK.createRoom(
roomId: widget.roomId,
token: widget.token,
participantName: "User1",
micEnabled: true,
camEnabled: true,
defaultCamera: FacingMode.FRONT,
multiStream: true,
mode: Mode.SEND_AND_RECV,
);
_joinRoom();
}
Future<void> _joinRoom() async {
try {
await _room.join();
} on VideoSDKError catch (e) {
print("Join failed: ${e.code} ${e.name}");
}
}
@override
void dispose() {
// Leave the room when the screen closes. The room releases itself.
_room.leave().catchError((Object e) => print("Leave failed: $e"));
super.dispose();
}
// Keep the listener in a field: stopObserving() takes the same function.
void _onBlockChat(String? value, Participant? updatedBy) {
print("New value: $value, updated by: ${updatedBy?.id}");
}
@override
Widget build(BuildContext context) {
return Column(children: [
ElevatedButton(
onPressed: () async {
String key = "BLOCK_CHAT";
try {
await _room.realtimeStore.observe(key, _onBlockChat);
} catch (e) {
print("Error:$e");
}
},
child: const Text("Realtime Store Observe"),
),
]);
}
}
stopObserving()
Stops receiving updates for a specific key and listener combination.
Key Notes
- Should be called when the listener is no longer needed (e.g., component unmount).
- The listener stops at once. When it was the key's last listener, the SDK also stops observing the key, which needs a joined room. Once
Events.roomLefthas fired, the listener is still removed, but the call throws aVideoSDKErrorwith code3035.
Parameters
-
key(String) The key you passed toobserve(). -
listener(void Function(String? value, Participant? updatedBy)) The same function you passed toobserve().
Example
import 'package:flutter/material.dart';
import 'package:videosdk/videosdk.dart';
class RoomScreen extends StatefulWidget {
//Existing configuration
}
class _RoomScreenState extends State<RoomScreen> {
late Room _room;
@override
void initState() {
super.initState();
_room = VideoSDK.createRoom(
roomId: widget.roomId,
token: widget.token,
participantName: "User1",
micEnabled: true,
camEnabled: true,
defaultCamera: FacingMode.FRONT,
multiStream: true,
mode: Mode.SEND_AND_RECV,
);
_joinRoom();
}
Future<void> _joinRoom() async {
try {
await _room.join();
} on VideoSDKError catch (e) {
print("Join failed: ${e.code} ${e.name}");
}
}
@override
void dispose() {
// Leave the room when the screen closes. The room releases itself.
_room.leave().catchError((Object e) => print("Leave failed: $e"));
super.dispose();
}
void _onBlockChat(String? value, Participant? updatedBy) {
print("New value: $value, updated by: ${updatedBy?.id}");
}
@override
Widget build(BuildContext context) {
return Column(children: [
ElevatedButton(
onPressed: () async {
try {
// The same key and function you passed to observe()
await _room.realtimeStore.stopObserving("BLOCK_CHAT", _onBlockChat);
} catch (e) {
print("Error:$e");
}
},
child: const Text("Realtime Store Stop Observing"),
),
]);
}
}
Error Handling & Constraints
| Property | Description |
|---|---|
| Error Handling | Every method returns a Future. Await it inside try/catch: a call made before join throws a VideoSDKError with code 3035, and a failed request throws a VideoSDKError. |
| Payload Size | Maximum 1 KB per key. |
| Supported Type | Only String values are supported. Use null to delete key. |
| Concurrency | The latest write overwrites previous values (last write wins) |
| Key Limit | A maximum of 100 keys are allowed in a single session. |
API Reference
The API references for this page are provided below.
Got a Question? Ask us on discord

