The @livekit/components-react web SDK has a built-in useChat hook that sends and receives chat messages over the lk-chat data channel topic using a specific JSON protocol:
The Flutter SDK has no equivalent built-in chat implementation. When Flutter clients need to send chat messages, they must publish raw data manually — either as plain text or custom JSON — on the same lk-chat topic. This creates two incompatibilities:
1. Flutter → Web: participant name lost
When a Flutter client publishes a message on lk-chat, the web useChat hook either ignores it (if it doesn’t match the expected schema) or renders it without the correct sender name. The web DataReceived handler receives the participant object, but since the message bypasses useChat internals, name resolution has to be done manually via room.remoteParticipants — which is fragile and breaks in edge cases (e.g. when the sender is the local participant).
2. Web dual-send echo causes ghost messages
As a workaround, web clients intercept publishData on the lk-chat topic and send two copies — the original JSON (for useChat) and a plain-text copy (for Flutter). The plain-text copy arrives back at other web participants’ DataReceived handlers, where it bypasses useChat and gets injected into the chat DOM via manual DOM manipulation, appearing with no sender name or as 'Mobile User'.
Root cause
There is no standardised cross-platform chat protocol across LiveKit SDKs. The lk-chat topic and its JSON schema exist only in @livekit/components-react and are undocumented as a cross-SDK contract. Flutter has no useChat equivalent, so cross-platform chat requires fragile workarounds.
Expected behaviour
Either:
The Flutter SDK provides a built-in chat API (useChat equivalent) that publishes messages in the same { id, message, timestamp } format on the lk-chat topic, OR
The lk-chat protocol is formally documented as a cross-SDK standard so third-party implementations (Flutter, Unity, etc.) can be compatible by default
Workaround currently in use
We are intercepting publishData on the web side to dual-send messages, and using MutationObserver + manual DOM injection to render Flutter messages inside the LiveKit chat UI. This is brittle and breaks whenever the LiveKit chat DOM structure changes.
Questions
Is there a recommended approach for cross-platform chat between Flutter and web clients in the same room?
Are there plans to add a built-in chat API to the Flutter SDK?
Should lk-chat be treated as a stable cross-SDK protocol contract?
There is currently no clearly documented cross-SDK room-chat contract between React and Flutter clients.
The React SDK provides a built-in chat abstraction through @livekit/components-react, while Flutter does not provide an equivalent room-level chat API. As a result, developers building multi-platform apps are forced into custom and brittle workarounds.
Web and Flutter clients connected to the same LiveKit room.
► Web: Next.js + @livekit/components-react
► Mobile: Flutter on Android and iOS
► Backend: LiveKit Cloud
The React side has a built-in chat path. Flutter requires manual message transport and message parsing. This creates several interoperability failures:
► Flutter to Web (Messages from Flutter do not integrate cleanly with React chat abstraction which requires custom handling.)
► Web to Flutter (Messages from React chat do not appear to be a stable cross-SDK contracts, Flutter implementations requires reverse-engineering it’s behavior.)
Workaround complexity
To bridge the two, you must intercept publish/send, duplicate messages (in multiple formats) and manually render non-native messages in the web UI. This causes multiple issues like:
There does not appear to be any documented, stable, shared room-chat protocol across SDKs that is true. Maybe because React exposes a higher-level chat abstraction. And Flutter exposes lower-level messaging primitives. So Without a common functioning and well documented contracts then interoperability becomes app-specific.
One of the following would resolve this cleanly:
Either a Document and stable cross-SDK room-chat contract is designed with:
Or Flutter can develop and provide a first-class Flutter room-chat API that is the equivalent in purpose to the React room chat abstraction or interoperable by default with web clients.
Else they can Officially recommend text streams for cross-platform chat and provide a reference schema, provide examples for React + Flutter interoperability and clarify whether the React built-in chat abstraction is intended only for React-to-React usage.
The best move is to stop trying to make Flutter impersonate React useChat.
Build one shared app-level chat protocol on text stream and use it on both platforms.
► one protocol
► one topic
► no dual-send
► no DOM injection
► works the same on web and Flutter
► sender identity is explicit
► you are no longer dependent on undocumented internal chat behavior
Recommended message model (Use this model everywhere):
► use one topic only, like app.chat.v1
► use one JSON schema on all platforms
► include senderId and senderName
► dedupe on id
► optimistically add local messages after send
► render from your own message list, not LiveKit’s internal chat DOM
Do not do these:
► do not dual-send
► do not mix plain text and JSON for the same chat feature
► do not inject messages into the built-in React chat DOM
► do not rely on lk-chat or lk.chat unless LiveKit officially documents that contract
Migration path off your workaround:
Create a brand-new topic:
app.chat.v1
Implement the shared JSON model on both sides.
Stop intercepting web publish/send behavior.
Replace React useChat UI with your own AppChatPanel.
Remove MutationObserver and DOM injection.
Once both clients use the new topic, delete all old bridge code.
Completely retire the current useChat bridge and switch the room chat feature to:
► custom React chat UI
► Flutter chat using sendText
► shared topic app.chat.v1
► shared JSON schema
► no fallback plain-text path at all