Who we are

Our Technologies

Our Company

Saturday, February 7, 2026

Introducing Spaces: Live Audio Rooms on Mention

Introducing Spaces: Live Audio Rooms on Mention

Introducing Spaces: Live Audio Rooms on Mention

The Biggest Feature Drop in Mention History

Today we are incredibly excited to announce Spaces — live audio rooms built directly into Mention. This is the single largest feature we have ever shipped, and it fundamentally changes what Mention is: from a social platform where you read and write, to one where you can talk and listen in real-time.

Spaces lets any user create a live audio room, invite speakers, and broadcast to an unlimited audience of listeners. Think of it as your own podcast studio, town hall, or casual hangout — all inside the app you already use every day.

We did not take shortcuts. We built this on top of WebRTC with a self-hosted Selective Forwarding Unit (SFU), running on our own infrastructure. No third-party audio APIs. No usage-based pricing that would force us to limit your conversations. Just raw, low-latency, high-quality audio — from our servers to your ears.

Let us dive into everything.

What Are Spaces?

A Space is a live audio room hosted by a Mention user. When you create a Space, you become the host. You give it a title, optionally a topic and description, and then you go live. That is it — you are broadcasting.

Other users can join your Space as listeners. They hear everything the speakers say in real-time, with sub-second latency. If a listener wants to speak, they can raise their hand (request to speak), and the host can approve or deny the request.

Once approved, a listener becomes a speaker. Speakers can unmute their microphone and talk to the entire room. The host can also remove speakers at any time, returning them to listener status.

The entire flow is designed to feel natural and effortless:

  1. Create — Tap the "+" button on the Spaces screen. Give your Space a title and topic.

  2. Go Live — Hit "Start Now" and you are broadcasting. A LiveKit room is created on our SFU, and your audio session begins.

  3. Invite and Share — Share your Space. It appears in the Spaces directory for anyone to join.

  4. Manage — Approve or deny speaker requests. Mute yourself. Remove speakers. You are in full control.

  5. End — When you are done, end the Space. The LiveKit room is torn down, Redis state is cleaned up, and the Space is archived.

How It Works Under the Hood

This is where it gets interesting. We built Spaces with a dual-layer architecture that separates the control plane from the media plane.

Layer 1: Socket.IO — The Control Plane

Socket.IO handles everything that is not audio. When you join a Space, your client establishes a WebSocket connection to our backend through the /spaces Socket.IO namespace. This connection manages:

  • Participant tracking — Who is in the room, their roles (host, speaker, listener), and their mute state

  • Speaker requests — The raise-hand, approve/deny, role-change flow

  • Space lifecycle — Start, end, and participant join/leave events

  • Real-time UI updates — Mute indicators, participant count, speaker list changes

All room state is persisted in Redis, not in-memory. This means if our backend process restarts, your Space survives. It also means we can scale horizontally — multiple backend instances can serve the same Space through Redis pub/sub.

Layer 2: LiveKit SFU — The Media Plane

Audio is handled entirely by LiveKit, an open-source WebRTC Selective Forwarding Unit that we self-host on our own DigitalOcean infrastructure.

When a Space goes live, our backend creates a LiveKit room via the Room Service API. When a client joins, it requests a LiveKit access token from our backend (POST /api/spaces/:id/token). The token encodes the user identity, the room name, and their permissions — can they publish audio? Can they subscribe?

The client then connects directly to the LiveKit SFU over WebRTC. Audio tracks flow peer-to-SFU, not peer-to-peer. This is critical for scalability — in a peer-to-peer model, a room with 50 listeners would require the speaker to upload 50 separate audio streams. With an SFU, the speaker uploads once, and LiveKit distributes to all subscribers.

Here is what LiveKit handles for us:

  • WebRTC negotiation — ICE candidates, DTLS handshake, codec selection

  • Echo cancellation and noise suppression — Built into the WebRTC stack

  • Adaptive bitrate — Audio quality adjusts based on network conditions

  • Track publish/subscribe — Speakers publish their mic track; listeners subscribe automatically

  • Bandwidth management — Dynacast ensures we only forward tracks that participants are actually consuming

Why Self-Hosted?

We could have used LiveKit Cloud or another hosted WebRTC service. We chose to self-host for three reasons:

  1. Cost control — Hosted WebRTC services charge per-participant-minute. For a social platform where Spaces can run for hours with dozens of participants, costs would escalate quickly. Our self-hosted LiveKit instance runs on a single DigitalOcean droplet.

  2. Data sovereignty — Audio streams never leave our infrastructure. They flow from clients to our SFU and back. No third-party processors in the middle.

  3. Full control — We configure everything: room timeouts, codec preferences, port ranges, TLS termination. If we need to tune performance, we change a config file, not a support ticket.

Our LiveKit instance runs as a Docker container behind Caddy (for automatic TLS via Let us Encrypt) on a dedicated droplet at livekit.mention.earth. UDP ports 50000-50200 are open for WebRTC media transport, with TCP fallback through the TURN server.

Role-Based Permissions

Spaces has a layered permission system that works across both Socket.IO and LiveKit:

Host

The Space creator. Has full control: can start/end the Space, approve/deny speaker requests, remove speakers, and of course speak. Their LiveKit token grants canPublish: true with canPublishSources: [MICROPHONE].

Speaker

A participant promoted by the host. Can unmute and publish audio. When the host approves a speaker request, two things happen simultaneously:

  1. Socket.IO broadcasts the role change to all participants (UI update)

  2. Our backend calls updateParticipantPermissions() on LiveKit Room Service API, granting the user publish rights in the LiveKit room

This dual update ensures the UI and the media layer stay in sync. The speaker can immediately unmute and start talking.

Listener

The default role. Can hear all speakers but cannot publish audio. Their LiveKit token has canPublish: false. Even if they tried to publish a track client-side, LiveKit would reject it at the server level. Security is enforced server-side, not just in the UI.

Speaker Permission Modes

When creating a Space, the host can choose who is allowed to request to speak:

  • Everyone — Any participant can raise their hand

  • Followers — Only users who follow the host can request

  • Invited Only — Only users explicitly invited by the host can speak

Spaces in Your Feed

Spaces are not isolated in a separate tab. They are woven into the fabric of Mention. When you create a Space, you can attach it to a post — just like you would attach an image, poll, or article.

Your followers will see a Space card in their feed. If the Space is live, the card pulses with a live indicator. Tapping the card joins the Space immediately. If it is scheduled, the card shows the scheduled time.

This was a deliberate design decision. We did not want Spaces to be a feature you have to go looking for. We wanted them to surface naturally in the content you are already browsing. A live Space from someone you follow should feel as natural as seeing their latest post.

The post attachment system supports the full Space lifecycle:

  • Scheduled — Card shows date/time, acts as an announcement

  • Live — Card shows participant count, pulsing indicator, "Join" action

  • Ended — Card shows it has ended (future: will link to recording)

Cross-Platform from Day One

Spaces works on web, iOS, and Android from launch. The LiveKit client SDK handles platform differences:

  • Web — Uses the browser WebRTC implementation. Remote audio tracks are attached to audio DOM elements for playback. We handle autoplay policies and element cleanup.

  • iOS and Android — Uses @livekit/react-native with react-native-webrtc under the hood. Audio session management is handled natively — we start the audio session when connecting and stop it on disconnect.

The UI is the same bottom sheet experience across all platforms, built with our existing sheet system. Open a Space, see the speakers, see the listeners, tap to mute, tap to raise your hand. It just works.

Redis-Backed State

In the early prototype, room state lived in a JavaScript Map in the backend process. If the process restarted, all active Spaces lost their participant lists. Not acceptable for production.

We migrated all room state to Redis, which we already use for Socket.IO adapter (multi-instance pub/sub) and caching. The key schema is clean:

  • space:room:{spaceId} — Room metadata (host, creation time)

  • space:room:{spaceId}:participants — Hash of userId to role, mute state, join time

  • space:room:{spaceId}:requests — Hash of pending speaker requests

This gives us atomic operations on participant state, automatic expiry capabilities, and the ability to inspect live room state with redis-cli for debugging. It also means our backend can scale horizontally — any instance can serve any Space.

The Architecture at a Glance

Here is the full picture of how everything fits together:

  • DigitalOcean Droplet — Runs LiveKit SFU in Docker, with Caddy for TLS. Handles all WebRTC audio transport.

  • Mention Backend (App Platform) — Token generation, room lifecycle, speaker management, Socket.IO /spaces namespace.

  • Redis — Room state persistence, Socket.IO adapter for multi-instance support.

  • Clients (Expo React Native + Web) — Dual connection: Socket.IO for control events, LiveKit SDK for audio tracks.

The separation of concerns is clean. Socket.IO never touches audio data. LiveKit never touches application logic. Redis bridges them by storing the authoritative room state that both layers reference.

What We Are Building Next

Spaces is launching today, but we are just getting started. Here is what is on our roadmap:

  • Recording and Playback — Record your Space and let people listen later. LiveKit supports egress (recording) natively, and we plan to integrate it so hosts can opt into recording. Imagine turning every Space into an on-demand podcast episode.

  • Live Captions — Real-time transcription powered by AI. Follow along with text even when you cannot listen with audio. This will make Spaces accessible to deaf and hard-of-hearing users, and useful in noise-sensitive environments.

  • Co-hosting — Invite another user as a co-host who can manage speakers and moderate the room alongside you. Essential for larger Spaces where a single host cannot manage everything alone.

  • Reactions — Listeners can send emoji reactions that float across the screen. A lightweight way to participate without speaking. Think applause, laughter, and raised hands — all animated in real-time.

  • Scheduled Spaces with Reminders — Schedule a Space for the future and let your followers set reminders so they do not miss it. We will send push notifications when the Space goes live.

  • Space Analytics — Detailed stats for hosts: peak listeners, total joins, average listen duration, engagement over time. Understand your audience and optimize your content.

  • Clips — Highlight and share short audio clips from Spaces. Let your best moments live beyond the live session.

Try It Now

Spaces is available today on mention.earth and in the Mention mobile app. Create your first Space, go live, and start talking. We can not wait to hear what you build with it.

If you are a developer interested in how we built this, check out the Oxy ecosystem at oxy.so — all of our infrastructure is built in-house, from the backend services to the real-time audio pipeline.

Welcome to the future of conversation on Mention. Welcome to Spaces.

The Biggest Feature Drop in Mention History

Today we are incredibly excited to announce Spaces — live audio rooms built directly into Mention. This is the single largest feature we have ever shipped, and it fundamentally changes what Mention is: from a social platform where you read and write, to one where you can talk and listen in real-time.

Spaces lets any user create a live audio room, invite speakers, and broadcast to an unlimited audience of listeners. Think of it as your own podcast studio, town hall, or casual hangout — all inside the app you already use every day.

We did not take shortcuts. We built this on top of WebRTC with a self-hosted Selective Forwarding Unit (SFU), running on our own infrastructure. No third-party audio APIs. No usage-based pricing that would force us to limit your conversations. Just raw, low-latency, high-quality audio — from our servers to your ears.

Let us dive into everything.

What Are Spaces?

A Space is a live audio room hosted by a Mention user. When you create a Space, you become the host. You give it a title, optionally a topic and description, and then you go live. That is it — you are broadcasting.

Other users can join your Space as listeners. They hear everything the speakers say in real-time, with sub-second latency. If a listener wants to speak, they can raise their hand (request to speak), and the host can approve or deny the request.

Once approved, a listener becomes a speaker. Speakers can unmute their microphone and talk to the entire room. The host can also remove speakers at any time, returning them to listener status.

The entire flow is designed to feel natural and effortless:

  1. Create — Tap the "+" button on the Spaces screen. Give your Space a title and topic.

  2. Go Live — Hit "Start Now" and you are broadcasting. A LiveKit room is created on our SFU, and your audio session begins.

  3. Invite and Share — Share your Space. It appears in the Spaces directory for anyone to join.

  4. Manage — Approve or deny speaker requests. Mute yourself. Remove speakers. You are in full control.

  5. End — When you are done, end the Space. The LiveKit room is torn down, Redis state is cleaned up, and the Space is archived.

How It Works Under the Hood

This is where it gets interesting. We built Spaces with a dual-layer architecture that separates the control plane from the media plane.

Layer 1: Socket.IO — The Control Plane

Socket.IO handles everything that is not audio. When you join a Space, your client establishes a WebSocket connection to our backend through the /spaces Socket.IO namespace. This connection manages:

  • Participant tracking — Who is in the room, their roles (host, speaker, listener), and their mute state

  • Speaker requests — The raise-hand, approve/deny, role-change flow

  • Space lifecycle — Start, end, and participant join/leave events

  • Real-time UI updates — Mute indicators, participant count, speaker list changes

All room state is persisted in Redis, not in-memory. This means if our backend process restarts, your Space survives. It also means we can scale horizontally — multiple backend instances can serve the same Space through Redis pub/sub.

Layer 2: LiveKit SFU — The Media Plane

Audio is handled entirely by LiveKit, an open-source WebRTC Selective Forwarding Unit that we self-host on our own DigitalOcean infrastructure.

When a Space goes live, our backend creates a LiveKit room via the Room Service API. When a client joins, it requests a LiveKit access token from our backend (POST /api/spaces/:id/token). The token encodes the user identity, the room name, and their permissions — can they publish audio? Can they subscribe?

The client then connects directly to the LiveKit SFU over WebRTC. Audio tracks flow peer-to-SFU, not peer-to-peer. This is critical for scalability — in a peer-to-peer model, a room with 50 listeners would require the speaker to upload 50 separate audio streams. With an SFU, the speaker uploads once, and LiveKit distributes to all subscribers.

Here is what LiveKit handles for us:

  • WebRTC negotiation — ICE candidates, DTLS handshake, codec selection

  • Echo cancellation and noise suppression — Built into the WebRTC stack

  • Adaptive bitrate — Audio quality adjusts based on network conditions

  • Track publish/subscribe — Speakers publish their mic track; listeners subscribe automatically

  • Bandwidth management — Dynacast ensures we only forward tracks that participants are actually consuming

Why Self-Hosted?

We could have used LiveKit Cloud or another hosted WebRTC service. We chose to self-host for three reasons:

  1. Cost control — Hosted WebRTC services charge per-participant-minute. For a social platform where Spaces can run for hours with dozens of participants, costs would escalate quickly. Our self-hosted LiveKit instance runs on a single DigitalOcean droplet.

  2. Data sovereignty — Audio streams never leave our infrastructure. They flow from clients to our SFU and back. No third-party processors in the middle.

  3. Full control — We configure everything: room timeouts, codec preferences, port ranges, TLS termination. If we need to tune performance, we change a config file, not a support ticket.

Our LiveKit instance runs as a Docker container behind Caddy (for automatic TLS via Let us Encrypt) on a dedicated droplet at livekit.mention.earth. UDP ports 50000-50200 are open for WebRTC media transport, with TCP fallback through the TURN server.

Role-Based Permissions

Spaces has a layered permission system that works across both Socket.IO and LiveKit:

Host

The Space creator. Has full control: can start/end the Space, approve/deny speaker requests, remove speakers, and of course speak. Their LiveKit token grants canPublish: true with canPublishSources: [MICROPHONE].

Speaker

A participant promoted by the host. Can unmute and publish audio. When the host approves a speaker request, two things happen simultaneously:

  1. Socket.IO broadcasts the role change to all participants (UI update)

  2. Our backend calls updateParticipantPermissions() on LiveKit Room Service API, granting the user publish rights in the LiveKit room

This dual update ensures the UI and the media layer stay in sync. The speaker can immediately unmute and start talking.

Listener

The default role. Can hear all speakers but cannot publish audio. Their LiveKit token has canPublish: false. Even if they tried to publish a track client-side, LiveKit would reject it at the server level. Security is enforced server-side, not just in the UI.

Speaker Permission Modes

When creating a Space, the host can choose who is allowed to request to speak:

  • Everyone — Any participant can raise their hand

  • Followers — Only users who follow the host can request

  • Invited Only — Only users explicitly invited by the host can speak

Spaces in Your Feed

Spaces are not isolated in a separate tab. They are woven into the fabric of Mention. When you create a Space, you can attach it to a post — just like you would attach an image, poll, or article.

Your followers will see a Space card in their feed. If the Space is live, the card pulses with a live indicator. Tapping the card joins the Space immediately. If it is scheduled, the card shows the scheduled time.

This was a deliberate design decision. We did not want Spaces to be a feature you have to go looking for. We wanted them to surface naturally in the content you are already browsing. A live Space from someone you follow should feel as natural as seeing their latest post.

The post attachment system supports the full Space lifecycle:

  • Scheduled — Card shows date/time, acts as an announcement

  • Live — Card shows participant count, pulsing indicator, "Join" action

  • Ended — Card shows it has ended (future: will link to recording)

Cross-Platform from Day One

Spaces works on web, iOS, and Android from launch. The LiveKit client SDK handles platform differences:

  • Web — Uses the browser WebRTC implementation. Remote audio tracks are attached to audio DOM elements for playback. We handle autoplay policies and element cleanup.

  • iOS and Android — Uses @livekit/react-native with react-native-webrtc under the hood. Audio session management is handled natively — we start the audio session when connecting and stop it on disconnect.

The UI is the same bottom sheet experience across all platforms, built with our existing sheet system. Open a Space, see the speakers, see the listeners, tap to mute, tap to raise your hand. It just works.

Redis-Backed State

In the early prototype, room state lived in a JavaScript Map in the backend process. If the process restarted, all active Spaces lost their participant lists. Not acceptable for production.

We migrated all room state to Redis, which we already use for Socket.IO adapter (multi-instance pub/sub) and caching. The key schema is clean:

  • space:room:{spaceId} — Room metadata (host, creation time)

  • space:room:{spaceId}:participants — Hash of userId to role, mute state, join time

  • space:room:{spaceId}:requests — Hash of pending speaker requests

This gives us atomic operations on participant state, automatic expiry capabilities, and the ability to inspect live room state with redis-cli for debugging. It also means our backend can scale horizontally — any instance can serve any Space.

The Architecture at a Glance

Here is the full picture of how everything fits together:

  • DigitalOcean Droplet — Runs LiveKit SFU in Docker, with Caddy for TLS. Handles all WebRTC audio transport.

  • Mention Backend (App Platform) — Token generation, room lifecycle, speaker management, Socket.IO /spaces namespace.

  • Redis — Room state persistence, Socket.IO adapter for multi-instance support.

  • Clients (Expo React Native + Web) — Dual connection: Socket.IO for control events, LiveKit SDK for audio tracks.

The separation of concerns is clean. Socket.IO never touches audio data. LiveKit never touches application logic. Redis bridges them by storing the authoritative room state that both layers reference.

What We Are Building Next

Spaces is launching today, but we are just getting started. Here is what is on our roadmap:

  • Recording and Playback — Record your Space and let people listen later. LiveKit supports egress (recording) natively, and we plan to integrate it so hosts can opt into recording. Imagine turning every Space into an on-demand podcast episode.

  • Live Captions — Real-time transcription powered by AI. Follow along with text even when you cannot listen with audio. This will make Spaces accessible to deaf and hard-of-hearing users, and useful in noise-sensitive environments.

  • Co-hosting — Invite another user as a co-host who can manage speakers and moderate the room alongside you. Essential for larger Spaces where a single host cannot manage everything alone.

  • Reactions — Listeners can send emoji reactions that float across the screen. A lightweight way to participate without speaking. Think applause, laughter, and raised hands — all animated in real-time.

  • Scheduled Spaces with Reminders — Schedule a Space for the future and let your followers set reminders so they do not miss it. We will send push notifications when the Space goes live.

  • Space Analytics — Detailed stats for hosts: peak listeners, total joins, average listen duration, engagement over time. Understand your audience and optimize your content.

  • Clips — Highlight and share short audio clips from Spaces. Let your best moments live beyond the live session.

Try It Now

Spaces is available today on mention.earth and in the Mention mobile app. Create your first Space, go live, and start talking. We can not wait to hear what you build with it.

If you are a developer interested in how we built this, check out the Oxy ecosystem at oxy.so — all of our infrastructure is built in-house, from the backend services to the real-time audio pipeline.

Welcome to the future of conversation on Mention. Welcome to Spaces.

The Biggest Feature Drop in Mention History

Today we are incredibly excited to announce Spaces — live audio rooms built directly into Mention. This is the single largest feature we have ever shipped, and it fundamentally changes what Mention is: from a social platform where you read and write, to one where you can talk and listen in real-time.

Spaces lets any user create a live audio room, invite speakers, and broadcast to an unlimited audience of listeners. Think of it as your own podcast studio, town hall, or casual hangout — all inside the app you already use every day.

We did not take shortcuts. We built this on top of WebRTC with a self-hosted Selective Forwarding Unit (SFU), running on our own infrastructure. No third-party audio APIs. No usage-based pricing that would force us to limit your conversations. Just raw, low-latency, high-quality audio — from our servers to your ears.

Let us dive into everything.

What Are Spaces?

A Space is a live audio room hosted by a Mention user. When you create a Space, you become the host. You give it a title, optionally a topic and description, and then you go live. That is it — you are broadcasting.

Other users can join your Space as listeners. They hear everything the speakers say in real-time, with sub-second latency. If a listener wants to speak, they can raise their hand (request to speak), and the host can approve or deny the request.

Once approved, a listener becomes a speaker. Speakers can unmute their microphone and talk to the entire room. The host can also remove speakers at any time, returning them to listener status.

The entire flow is designed to feel natural and effortless:

  1. Create — Tap the "+" button on the Spaces screen. Give your Space a title and topic.

  2. Go Live — Hit "Start Now" and you are broadcasting. A LiveKit room is created on our SFU, and your audio session begins.

  3. Invite and Share — Share your Space. It appears in the Spaces directory for anyone to join.

  4. Manage — Approve or deny speaker requests. Mute yourself. Remove speakers. You are in full control.

  5. End — When you are done, end the Space. The LiveKit room is torn down, Redis state is cleaned up, and the Space is archived.

How It Works Under the Hood

This is where it gets interesting. We built Spaces with a dual-layer architecture that separates the control plane from the media plane.

Layer 1: Socket.IO — The Control Plane

Socket.IO handles everything that is not audio. When you join a Space, your client establishes a WebSocket connection to our backend through the /spaces Socket.IO namespace. This connection manages:

  • Participant tracking — Who is in the room, their roles (host, speaker, listener), and their mute state

  • Speaker requests — The raise-hand, approve/deny, role-change flow

  • Space lifecycle — Start, end, and participant join/leave events

  • Real-time UI updates — Mute indicators, participant count, speaker list changes

All room state is persisted in Redis, not in-memory. This means if our backend process restarts, your Space survives. It also means we can scale horizontally — multiple backend instances can serve the same Space through Redis pub/sub.

Layer 2: LiveKit SFU — The Media Plane

Audio is handled entirely by LiveKit, an open-source WebRTC Selective Forwarding Unit that we self-host on our own DigitalOcean infrastructure.

When a Space goes live, our backend creates a LiveKit room via the Room Service API. When a client joins, it requests a LiveKit access token from our backend (POST /api/spaces/:id/token). The token encodes the user identity, the room name, and their permissions — can they publish audio? Can they subscribe?

The client then connects directly to the LiveKit SFU over WebRTC. Audio tracks flow peer-to-SFU, not peer-to-peer. This is critical for scalability — in a peer-to-peer model, a room with 50 listeners would require the speaker to upload 50 separate audio streams. With an SFU, the speaker uploads once, and LiveKit distributes to all subscribers.

Here is what LiveKit handles for us:

  • WebRTC negotiation — ICE candidates, DTLS handshake, codec selection

  • Echo cancellation and noise suppression — Built into the WebRTC stack

  • Adaptive bitrate — Audio quality adjusts based on network conditions

  • Track publish/subscribe — Speakers publish their mic track; listeners subscribe automatically

  • Bandwidth management — Dynacast ensures we only forward tracks that participants are actually consuming

Why Self-Hosted?

We could have used LiveKit Cloud or another hosted WebRTC service. We chose to self-host for three reasons:

  1. Cost control — Hosted WebRTC services charge per-participant-minute. For a social platform where Spaces can run for hours with dozens of participants, costs would escalate quickly. Our self-hosted LiveKit instance runs on a single DigitalOcean droplet.

  2. Data sovereignty — Audio streams never leave our infrastructure. They flow from clients to our SFU and back. No third-party processors in the middle.

  3. Full control — We configure everything: room timeouts, codec preferences, port ranges, TLS termination. If we need to tune performance, we change a config file, not a support ticket.

Our LiveKit instance runs as a Docker container behind Caddy (for automatic TLS via Let us Encrypt) on a dedicated droplet at livekit.mention.earth. UDP ports 50000-50200 are open for WebRTC media transport, with TCP fallback through the TURN server.

Role-Based Permissions

Spaces has a layered permission system that works across both Socket.IO and LiveKit:

Host

The Space creator. Has full control: can start/end the Space, approve/deny speaker requests, remove speakers, and of course speak. Their LiveKit token grants canPublish: true with canPublishSources: [MICROPHONE].

Speaker

A participant promoted by the host. Can unmute and publish audio. When the host approves a speaker request, two things happen simultaneously:

  1. Socket.IO broadcasts the role change to all participants (UI update)

  2. Our backend calls updateParticipantPermissions() on LiveKit Room Service API, granting the user publish rights in the LiveKit room

This dual update ensures the UI and the media layer stay in sync. The speaker can immediately unmute and start talking.

Listener

The default role. Can hear all speakers but cannot publish audio. Their LiveKit token has canPublish: false. Even if they tried to publish a track client-side, LiveKit would reject it at the server level. Security is enforced server-side, not just in the UI.

Speaker Permission Modes

When creating a Space, the host can choose who is allowed to request to speak:

  • Everyone — Any participant can raise their hand

  • Followers — Only users who follow the host can request

  • Invited Only — Only users explicitly invited by the host can speak

Spaces in Your Feed

Spaces are not isolated in a separate tab. They are woven into the fabric of Mention. When you create a Space, you can attach it to a post — just like you would attach an image, poll, or article.

Your followers will see a Space card in their feed. If the Space is live, the card pulses with a live indicator. Tapping the card joins the Space immediately. If it is scheduled, the card shows the scheduled time.

This was a deliberate design decision. We did not want Spaces to be a feature you have to go looking for. We wanted them to surface naturally in the content you are already browsing. A live Space from someone you follow should feel as natural as seeing their latest post.

The post attachment system supports the full Space lifecycle:

  • Scheduled — Card shows date/time, acts as an announcement

  • Live — Card shows participant count, pulsing indicator, "Join" action

  • Ended — Card shows it has ended (future: will link to recording)

Cross-Platform from Day One

Spaces works on web, iOS, and Android from launch. The LiveKit client SDK handles platform differences:

  • Web — Uses the browser WebRTC implementation. Remote audio tracks are attached to audio DOM elements for playback. We handle autoplay policies and element cleanup.

  • iOS and Android — Uses @livekit/react-native with react-native-webrtc under the hood. Audio session management is handled natively — we start the audio session when connecting and stop it on disconnect.

The UI is the same bottom sheet experience across all platforms, built with our existing sheet system. Open a Space, see the speakers, see the listeners, tap to mute, tap to raise your hand. It just works.

Redis-Backed State

In the early prototype, room state lived in a JavaScript Map in the backend process. If the process restarted, all active Spaces lost their participant lists. Not acceptable for production.

We migrated all room state to Redis, which we already use for Socket.IO adapter (multi-instance pub/sub) and caching. The key schema is clean:

  • space:room:{spaceId} — Room metadata (host, creation time)

  • space:room:{spaceId}:participants — Hash of userId to role, mute state, join time

  • space:room:{spaceId}:requests — Hash of pending speaker requests

This gives us atomic operations on participant state, automatic expiry capabilities, and the ability to inspect live room state with redis-cli for debugging. It also means our backend can scale horizontally — any instance can serve any Space.

The Architecture at a Glance

Here is the full picture of how everything fits together:

  • DigitalOcean Droplet — Runs LiveKit SFU in Docker, with Caddy for TLS. Handles all WebRTC audio transport.

  • Mention Backend (App Platform) — Token generation, room lifecycle, speaker management, Socket.IO /spaces namespace.

  • Redis — Room state persistence, Socket.IO adapter for multi-instance support.

  • Clients (Expo React Native + Web) — Dual connection: Socket.IO for control events, LiveKit SDK for audio tracks.

The separation of concerns is clean. Socket.IO never touches audio data. LiveKit never touches application logic. Redis bridges them by storing the authoritative room state that both layers reference.

What We Are Building Next

Spaces is launching today, but we are just getting started. Here is what is on our roadmap:

  • Recording and Playback — Record your Space and let people listen later. LiveKit supports egress (recording) natively, and we plan to integrate it so hosts can opt into recording. Imagine turning every Space into an on-demand podcast episode.

  • Live Captions — Real-time transcription powered by AI. Follow along with text even when you cannot listen with audio. This will make Spaces accessible to deaf and hard-of-hearing users, and useful in noise-sensitive environments.

  • Co-hosting — Invite another user as a co-host who can manage speakers and moderate the room alongside you. Essential for larger Spaces where a single host cannot manage everything alone.

  • Reactions — Listeners can send emoji reactions that float across the screen. A lightweight way to participate without speaking. Think applause, laughter, and raised hands — all animated in real-time.

  • Scheduled Spaces with Reminders — Schedule a Space for the future and let your followers set reminders so they do not miss it. We will send push notifications when the Space goes live.

  • Space Analytics — Detailed stats for hosts: peak listeners, total joins, average listen duration, engagement over time. Understand your audience and optimize your content.

  • Clips — Highlight and share short audio clips from Spaces. Let your best moments live beyond the live session.

Try It Now

Spaces is available today on mention.earth and in the Mention mobile app. Create your first Space, go live, and start talking. We can not wait to hear what you build with it.

If you are a developer interested in how we built this, check out the Oxy ecosystem at oxy.so — all of our infrastructure is built in-house, from the backend services to the real-time audio pipeline.

Welcome to the future of conversation on Mention. Welcome to Spaces.

Latest news

Latest news

Latest news