How We Fixed Realtime Presence in the MyZubster Metaverse
We have completed an important infrastructure upgrade for MyZubster World, the community metaverse available inside the MyZubster ecosystem.
The goal was simple: let authenticated users enter the world with their verified character while keeping presence, movement, chat, and emotes synchronized reliably in production.
The original implementation worked locally, but production introduced a classic serverless problem.
The original problem
The first realtime architecture used:
- Server-Sent Events;
- in-memory JavaScript maps;
- one active stream for each connected player;
- local broadcasts for movement, chat, joins, and departures.
This worked when the backend ran as one persistent Node.js process.
MyZubster is deployed on Vercel, where different requests may be handled by different serverless instances. Memory is not shared between them.
A player could therefore:
- join through one serverless instance;
- open the event stream through another;
- send movement or chat through a third.
Each instance had a different view of the world. The interface could remain stuck on RECONNECTING, even when authentication and character creation had succeeded.
Moving realtime state to MongoDB
We replaced the instance-local source of truth with shared MongoDB collections.
The new presence model stores:
- session and world identifiers;
- character name and archetype;
- verified identity status;
- public GitHub profile;
- player coordinates;
- current emote;
- join and last-seen timestamps;
- automatic expiration time.
Presence records use a MongoDB TTL index, so abandoned sessions are removed automatically.
metaversePresenceSchema.index(
{ expiresAt: 1 },
{ expireAfterSeconds: 0 }
);
Recent chat messages are also shared between serverless instances and expire after a limited retention period.
No private keys, wallet credentials, or sensitive authentication data are stored in these public presence records.
Replacing fragile EventSource connections
The React frontend no longer depends on one long-lived EventSource connection.
It now calls a synchronization endpoint periodically:
export function syncMetaverse(sessionId, cursor = null) {
return jsonRequest('/api/metaverse/sync', {
method: 'POST',
body: JSON.stringify({ sessionId, cursor })
});
}
Every successful synchronization:
- refreshes the playerβs presence;
- returns the active player snapshot;
- delivers new chat messages;
- synchronizes movements and emotes;
- advances the message cursor;
- changes the interface status to
ONLINE.
If a request temporarily fails, the client displays RECONNECTING and retries automatically.
If the presence expires after a long offline period, the browser creates a fresh session using the server-owned character profile instead of remaining permanently disconnected.
Verified MyZubster characters
Authenticated players no longer enter with browser-generated identity claims.
The server reads the authenticated account and searches for its existing account-linked character.
For example, the verified character H4x0r is connected to:
- the corresponding MyZubster account;
- the public GitHub identity
@DanielIoni-creator; - an
account-linkedidentity status.
Client-supplied names or MYZ identifiers cannot override this verified identity.
Guests can still explore the world, but the interface clearly distinguishes:
-
MYZ VERIFIED; -
OSPITE.
Serverless-safe API flow
The production server now waits for MongoDB before serving every Metaverse API route, not only the initial join request.
The shared flow covers:
/api/metaverse/world/api/metaverse/join/api/metaverse/sync/api/metaverse/move/api/metaverse/chat/api/metaverse/emote/api/metaverse/leave
An in-memory fallback remains available for isolated local development and testing.
Validation
The upgrade was validated with:
- backend syntax checks;
- frontend JSX parsing;
- guest session tests;
- authenticated identity tests;
- movement boundary tests;
- shared chat synchronization tests;
- frontend transport checks.
The targeted test suite completed with:
Test Suites: 3 passed, 3 total
Tests: 11 passed, 11 total
Production verification confirmed:
- Vercel deployment ready;
- HTTP
200from the world endpoint; -
shared-pollingas the active transport; - the new synchronization endpoint inside the public frontend bundle;
- the old Metaverse EventSource removed from the frontend;
- verified characters loaded from MongoDB;
- automatic recovery from stale browser state.
Why polling?
WebSockets are usually the first choice for realtime applications, but they require infrastructure designed for persistent shared connections.
For the current MyZubster deployment, short synchronization requests provide a useful compromise:
- compatible with serverless execution;
- easy to monitor;
- resilient across multiple instances;
- no additional realtime provider;
- persistent shared state;
- automatic recovery after temporary failures.
The architecture can later evolve toward WebSockets, Redis, or a dedicated realtime service without changing the identity and persistence model introduced here.
Try MyZubster World
Explore the live Metaverse:
π https://www.myzubster.com/metaverse
Source commit:
π MyZubster realtime synchronization upgrade
MyZubster is being developed as an open-source ecosystem connecting community identity, environmental technology, robotics, digital collaboration, and transparent contribution systems.
Feedback and contributors are welcome.
Top comments (0)