This feature is available in SDK version 4.12.0 and later.
This feature works fully with DQL Strict Mode disabled.
DQL_STRICT_MODE=falseRead more about STRICT MODE and upcoming v5 behaviorsystem:data_sync_info collection provides real-time information about synchronization status between your device and other peers in the Ditto mesh network.
What You Can Monitor
- Connection status with peers and cloud servers
- Sync progress using commit IDs
- Last update timing from each peer
Document Structure
Each document insystem:data_sync_info represents one peer connection:
{
"_id": "peer-123",
"is_ditto_server": true,
"documents": {
"sync_session_status": "Connected",
"synced_up_to_local_commit_id": 1500,
"last_update_received_time": 1703123456
}
}
Key Fields
_id- Unique peer identifieris_ditto_server-truefor cloud servers,falsefor other devicessync_session_status-"Connected","Not Connected", or"Disabled"synced_up_to_local_commit_id- Latest commit ID synced to this peerlast_update_received_time- Unix timestamp of last data received
Basic Queries
The examples in this document assume DQL Strict Mode is disabled.If DQL Strict Mode is enabled the collection definition must be provided.
COLLECTION system:data_sync_info (documents MAP)Read more about STRICT MODE and upcoming v5 behaviorGet All Peers
SELECT * FROM system:data_sync_info
SELECT * FROM COLLECTION system:data_sync_info (documents MAP)
Get Only Cloud Servers
SELECT * FROM system:data_sync_info WHERE is_ditto_server = true
Get Connected Peers Only
SELECT * FROM system:data_sync_info WHERE documents.sync_session_status = 'Connected'
Get Specific Fields
SELECT _id, documents.sync_session_status, documents.synced_up_to_local_commit_id
FROM system:data_sync_info
Example in Code
// Get all sync info
let result = try await ditto.store.execute(
query: "SELECT * FROM system:data_sync_info"
)
result.items.forEach { item in
let peer = item.value
let status = (peer["documents"] as? [String: Any])?["sync_session_status"] as? String ?? "Unknown"
print("Peer \(peer["_id"] ?? ""): \(status)")
}
// Get all sync info.
ditto.store.execute("SELECT * FROM system:data_sync_info") { result ->
result.items.forEach { item ->
val peerId = item.value["_id"].stringOrNull ?: "unknown"
val status = item.value["documents"].dictionaryOrNull
?.let { it["sync_session_status"].stringOrNull }
?: "Unknown"
println("Peer $peerId: $status")
}
}
// Get all sync info
const result = await ditto.store.execute(
"SELECT * FROM system:data_sync_info"
);
result.items.forEach(item => {
const peer = item.value;
console.log(`Peer ${peer._id}: ${peer.documents.sync_session_status}`);
});
import { Ditto, QueryResult, QueryResultItem } from '@dittolive/ditto'
interface SyncDocuments {
sync_session_status: string
synced_up_to_local_commit_id: number
last_update_received_time: number
}
interface PeerSyncInfo {
_id: string
is_ditto_server: boolean
documents: SyncDocuments
}
// Get all sync info
const result: QueryResult = await ditto.store.execute(
"SELECT * FROM system:data_sync_info"
)
result.items.forEach((item: QueryResultItem) => {
const peer = item.value as PeerSyncInfo
console.log(`Peer ${peer._id}: ${peer.documents.sync_session_status}`)
})
// Get all sync info
final result = await ditto.store.execute(
"SELECT * FROM system:data_sync_info"
);
for (final item in result.items) {
final peer = item.value as Map<String, dynamic>;
final documents = peer["documents"] as Map<String, dynamic>;
print("Peer ${peer["_id"]}: ${documents["sync_session_status"]}");
}
// Get all sync info
try (DittoQueryResult result = ditto.store.execute(
"SELECT * FROM system:data_sync_info"
)) {
for (DittoQueryResultItem item : result.getItems()) {
Map<String, Object> peer = item.getValue();
Map<String, Object> documents = (Map<String, Object>) peer.get("documents");
String status = (String) documents.get("sync_session_status");
System.out.println("Peer " + peer.get("_id") + ": " + status);
}
}
// Get all sync info
using var result = await ditto.Store.ExecuteAsync(
"SELECT * FROM system:data_sync_info"
);
foreach (var item in result.Items) {
var peer = (Dictionary<string, object>)item.Value;
var documents = (Dictionary<string, object>)peer["documents"];
var status = (string)documents["sync_session_status"];
Console.WriteLine($"Peer {peer["_id"]}: {status}");
}
// Get all sync info
auto result = ditto.get_store().execute("SELECT * FROM system:data_sync_info");
for (const auto& item : result.items()) {
const auto& peer = item.value();
const auto& documents = peer.at("documents").get<std::map<std::string, std::any>>();
const auto& status = std::any_cast<std::string>(documents.at("sync_session_status"));
std::cout << "Peer " << std::any_cast<std::string>(peer.at("_id")) << ": " << status << std::endl;
}
// Get all sync info
let result = ditto.store().execute((
"SELECT * FROM system:data_sync_info",
serde_json::Value::Null
)).await?;
for item in result.iter() {
if let Some(peer) = item.value().as_object() {
if let Some(documents) = peer.get("documents").and_then(|d| d.as_object()) {
let status = documents.get("sync_session_status")
.and_then(|s| s.as_str())
.unwrap_or("Unknown");
let peer_id = peer.get("_id")
.and_then(|id| id.as_str())
.unwrap_or("");
println!("Peer {}: {}", peer_id, status);
}
}
}
// Get all sync info
result, err := dit.Store().Execute("SELECT * FROM system:data_sync_info")
if err != nil {
return err
}
defer result.Close() // cleanup
for _, item := range result.Items() {
peer := item.Value()
if documents, ok := peer["documents"].(map[string]any); ok {
if status, ok := documents["sync_session_status"].(string); ok {
if peerID, ok := peer["_id"].(string); ok {
fmt.Printf("Peer %s: %s\n", peerID, status)
}
}
}
}
Observing Changes
Observers on
system:data_sync_info trigger the callback on a fixed 500ms interval, regardless of whether the underlying data has changed.registerObserver to monitor sync status changes in real-time:
let observer = ditto.store.registerObserver(
query: "SELECT * FROM system:data_sync_info"
) { result in
result.items.forEach { item in
let peer = item.value
let status = (peer["documents"] as? [String: Any])?["sync_session_status"] as? String ?? "Unknown"
print("Peer \(peer["_id"] ?? ""): \(status)")
}
}
// The DittoQueryResult is owned by the observer — don't wrap it in `use { }`.
// Use typed accessors on item.value (DittoCborSerializable.Dictionary); do not
// cast to Map<String, Any>.
val observer = ditto.store.registerObserver(
"SELECT * FROM system:data_sync_info",
) { result ->
result.items.forEach { item ->
val peerId = item.value["_id"].stringOrNull ?: "unknown"
val status = item.value["documents"].dictionaryOrNull
?.let { it["sync_session_status"].stringOrNull }
?: "Unknown"
println("Peer $peerId: $status")
}
}
const observer = ditto.store.registerObserver(
"SELECT * FROM system:data_sync_info",
(result) => {
result.items.forEach(item => {
const peer = item.value;
console.log(`Peer ${peer._id}: ${peer.documents.sync_session_status}`);
});
}
);
import { Ditto, StoreObserver, QueryResult, QueryResultItem } from '@dittolive/ditto'
interface SyncDocuments {
sync_session_status: string
synced_up_to_local_commit_id: number
last_update_received_time: number
}
interface PeerSyncInfo {
_id: string
is_ditto_server: boolean
documents: SyncDocuments
}
const observer: StoreObserver = ditto.store.registerObserver(
"SELECT * FROM system:data_sync_info",
(result: QueryResult) => {
result.items.forEach((item: QueryResultItem) => {
const peer = item.value as PeerSyncInfo
console.log(`Peer ${peer._id}: ${peer.documents.sync_session_status}`)
})
}
)
final observer = ditto.store.registerObserver(
"SELECT * FROM system:data_sync_info",
(result) {
for (final item in result.items) {
final peer = item.value as Map<String, dynamic>;
final documents = peer["documents"] as Map<String, dynamic>;
print("Peer ${peer["_id"]}: ${documents["sync_session_status"]}");
}
}
);
DittoObserver observer = ditto.store.registerObserver(
"SELECT * FROM system:data_sync_info",
(result) -> {
try (result) {
for (DittoQueryResultItem item : result.getItems()) {
Map<String, Object> peer = item.getValue();
Map<String, Object> documents = (Map<String, Object>) peer.get("documents");
String status = (String) documents.get("sync_session_status");
System.out.println("Peer " + peer.get("_id") + ": " + status);
}
}
}
);
var observer = ditto.Store.RegisterObserver(
"SELECT * FROM system:data_sync_info",
(result) => {
using(result)
{
foreach (var item in result.Items) {
var peer = (Dictionary<string, object>)item.Value;
var documents = (Dictionary<string, object>)peer["documents"];
var status = (string)documents["sync_session_status"];
Console.WriteLine($"Peer {peer["_id"]}: {status}");
}
}
}
);
auto observer = store.register_observer(
"SELECT * FROM system:data_sync_info",
[](const auto& result) {
for (const auto& item : result.items()) {
const auto& peer = item.value();
const auto& documents = peer.at("documents").get<std::map<std::string, std::any>>();
const auto& status = std::any_cast<std::string>(documents.at("sync_session_status"));
std::cout << "Peer " << std::any_cast<std::string>(peer.at("_id")) << ": " << status << std::endl;
}
}
);
let observer = ditto.store().register_observer(
"SELECT * FROM system:data_sync_info",
move |result| {
for item in result.iter() {
if let Some(peer) = item.value().as_object() {
if let Some(documents) = peer.get("documents").and_then(|d| d.as_object()) {
let status = documents.get("sync_session_status")
.and_then(|s| s.as_str())
.unwrap_or("Unknown");
let peer_id = peer.get("_id")
.and_then(|id| id.as_str())
.unwrap_or("");
println!("Peer {}: {}", peer_id, status);
}
}
}
}
)?;
observer, err := dit.Store().RegisterObserver(
"SELECT * FROM system:data_sync_info",
nil, // no query arguments
func(result *ditto.QueryResult) {
defer result.Close() // cleanup
for _, item := range result.Items() {
peer := item.Value()
if documents, ok := peer["documents"].(map[string]any); ok {
if status, ok := documents["sync_session_status"].(string); ok {
if peerID, ok := peer["_id"].(string); ok {
fmt.Printf("Peer %s: %s\n", peerID, status)
}
}
}
}
}
)
if err != nil {
return err
}
Using Commit IDs
Every data modification returns a commit ID that you can use to track sync progress:// Every mutation returns a commit ID
let result = try await ditto.store.execute(
query: "UPDATE cars SET color = 'blue' WHERE _id = '123'"
)
print("Commit ID: \(result.commitID ?? -1)")
// Every mutation returns a commit ID — use the handler form of execute.
ditto.store.execute(
"UPDATE cars SET color = 'blue' WHERE _id = '123'",
) { result ->
println("Commit ID: ${result.commitId}")
}
// Every mutation returns a commit ID
const result = await ditto.store.execute(
"UPDATE cars SET color = 'blue' WHERE _id = '123'"
);
console.log('Commit ID:', result.commitID);
import { Ditto, QueryResult } from '@dittolive/ditto'
// Every mutation returns a commit ID
const result: QueryResult = await ditto.store.execute(
"UPDATE cars SET color = 'blue' WHERE _id = '123'"
)
const commitID: number | undefined = result.commitID
console.log('Commit ID:', commitID)
// Every mutation returns a commit ID
final result = await ditto.store.execute(
"UPDATE cars SET color = 'blue' WHERE _id = '123'"
);
print("Commit ID: ${result.commitID}");
// Every mutation returns a commit ID
try (DittoQueryResult result = ditto.store.execute(
"UPDATE cars SET color = 'blue' WHERE _id = '123'"
)) {
System.out.println("Commit ID: " + result.getCommitID());
}
// Every mutation returns a commit ID
using var result = await ditto.Store.ExecuteAsync(
"UPDATE cars SET color = 'blue' WHERE _id = '123'"
);
Console.WriteLine($"Commit ID: {result.CommitID}");
// Every mutation returns a commit ID
auto result = store.execute(
"UPDATE cars SET color = 'blue' WHERE _id = '123'"
);
std::cout << "Commit ID: " << result.commitID() << std::endl;
// Every mutation returns a commit ID
let result = ditto.store().execute((
"UPDATE cars SET color = 'blue' WHERE _id = '123'",
serde_json::Value::Null
)).await?;
println!("Commit ID: {:?}", result.commit_id());
// Every mutation returns a commit ID
result, err := dit.Store().Execute(
"UPDATE cars SET color = 'blue' WHERE _id = '123'")
if err != nil {
return err
}
defer result.Close() // cleanup
if commitID, ok := result.CommitID(); ok {
fmt.Printf("Commit ID: %v\n", commitID)
}
synced_up_to_local_commit_id to see if a peer has received your change.
Important Notes
Sync status information is local-only and never synchronizes between peers. Each peer maintains its own view of sync status.
- Commit IDs are monotonic (always increasing) but not necessarily sequential
- Multiple cloud servers may appear due to load balancing or failover
- Local-only data - this collection exists only on your device
- Minimal performance impact - observing sync status is lightweight
Supported APIs
| API/Feature | Index Support |
|---|---|
execute SDK API | ✅ Supported |
registerObserver SDK API | ✅ Supported |
registerSubscription SDK API | ❌ Not Supported |
| Big Peer HTTP API | ❌ Not Supported |
| SDKs with in-memory storage (e.g. web browser) | ❌ Not Supported |
Related Topics
- Track Ditto Cloud Sync Status - Monitor cloud synchronization specifically
- Managing Subscriptions - Configure what data syncs between peers