-
Mo
chevron_right
Let's Talk About Spaces in XMPP
Timothée Jaussoin • pubsub.movim.eu / Movim • 1 day ago edit • 11 minutes
It looks like we're finally there!
Spaces in XMPP is now a thing and it's part of Movim, yay 🎉
In this article, I'll explain what Spaces are in XMPP, how Movim is implementing them, how you can deploy and host your own Spaces, and what still needs to be done.
tldr; Spaces in XMPP are implemented using Publish-Subscribe and Multi-User Chat, two XMPP extensions that are already available and largely implemented and are defined in details in XEP-0503 Spaces.
A Bit of XMPP History
There are basically two ways to send a message in XMPP: by sending a direct message to a contact, or by sending it in a chatroom.
Direct chat messages were defined in the core XMPP protocol in the late nineties. Since XMPP is an eXtensible Messaging and Presence Protocol, chatrooms were defined a few years later, in 2002, in one of the first fundamental extensions of the protocol: XEP-0045: Multi-User Chat (XEP stands for XMPP Extension Protocol, pretty self-explanatory 😛).
Also in 2002, a second fundamental extension was specified: PubSub, defined in XEP-0060. This extension defines a way to create "nodes" on the XMPP network where users can publish content and subscribe to it. Newly published, edited, or deleted content is then pushed to the node's subscribers in real time.
And this worked well for many years. Those two principles were implemented, improved, and extended over nearly two decades.
Movim was introduced in 2010 with the idea that, while being a web-based XMPP chat client, it could also make extensive use of PubSub to share social content and related features across the XMPP network. And that worked out really nicely, a PubSub node can be seen as a news feed where users can publish articles (defined in XEP-0472: Pubsub Social Feed) and, more recently, Stories (defined in XEP-0501: Pubsub Stories), and where other users can subscribe and be notified in real time about new content.
Bookmarking Things on XMPP
When you join a chatroom or subscribe to a PubSub node on the XMPP network, it's convenient to keep track of your subscriptions so that your XMPP clients can stay in sync. Just as browsers let you bookmark URLs to save websites you want to revisit, the bookmarks concept was introduced in XMPP.
For PubSub subscriptions, this was defined in 2013 in XEP-0330: Pubsub Subscription.
The following example is essentially a bookmark pointing to the Movim blog you're currently reading, stored on Salim's XMPP account.
<iq type='result'
from='salim@xmpp.ps'
to='salim@xmpp.ps/fairphone'
id='bget1234'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<items node='urn:xmpp:pubsub:subscription'>
<item id='0bc0e76cb803b3b107aa369169d8c0d45086f844'>
<subscription xmlns='urn:xmpp:pubsub:subscription:0' server='pubsub.movim.eu' node='Movim'>
<title>Movim Blog</title>
</subscription>
</item>
</publish>
</pubsub>
</iq>
Note that PubSub bookmark items are stored in a PubSub node hosted on your own account (here salim@xmpp.ps) 😸. This way, when a new bookmark is pushed by one client, all other connected clients for that account are notified in real time, and if they're offline, they simply fetch the list when they reconnect.
For chatrooms, things work similarly. The rooms you've joined are stored in a dedicated PubSub node on your own account, as defined in XEP-0402: PEP Native Bookmarks.
<iq type='result'
to='pooja@jabber.in/phone'
id='bget192121'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<items node='urn:xmpp:bookmarks:1'>
<item id='patel_family@conference.jabber.in'>
<conference xmlns='urn:xmpp:bookmarks:1'
name='Family Room'
autojoin='true'>
<nick>Pooka</nick>
</conference>
</item>
<item id='friends@conference.movim.eu'>
<conference xmlns='urn:xmpp:bookmarks:1'
name='Friends Group'
autojoin='true'>
<nick>PK</nick>
<extensions>
<pinned xmlns='urn:xmpp:bookmarks-pinning:0'/>
</extensions>
</conference>
</item>
</items>
</pubsub>
</iq>
As you can see, bookmarks can have extensions. Here, the second chatroom "Friends Group" is pinned, which means clients will display it at the top of the list.
Rooms and PubSub Affiliations
Both chatrooms and PubSub nodes use the concept of affiliations, essentially roles assigned to users once they join a chatroom or PubSub node, which determine what actions they are allowed or forbidden to perform.
In PubSub, affiliations are defined in section 4.1 Affiliations, and in Multi-User Chat in section 5.2 Affiliations. Those links contain the full details of each role's privileges.
The great thing is that these two affiliation systems are actually quite similar! Chatrooms have Owner, Admin, Member, and Outcast affiliations, while PubSub has Owner, Publisher, Publish-Only, Member, and Outcast. This will come in handy later, as you'll see 😽.
Introducing Spaces ✨
Over the last few years, a new way of organizing chatrooms has emerged, first introduced by Slack, then adopted by Discord, Mattermost, Matrix, and many other chat platforms.
As messaging grew more prominent, users needed more than a simple chatroom for sharing messages. They wanted to organize and categorize the content they were exchanging with others.
This is where the concept of Spaces came in. Called Servers (or Guilds) on Discord, Workspaces on Slack, or simply Spaces on Matrix, the general idea is to let users create a shared place, and invite people to it, where they'll find a collection of chatrooms grouped together with a unified moderation system and a coherent user interface.
This had been missing from XMPP for a long time.
In autumn 2025, I organized a hackathon with my friend nicoco from the Slidge project to tackle this problem. Slidge is a great tool for bridging XMPP with many other chat protocols. I wanted to add Spaces to Movim, and he wanted a proper way to map Discord Servers and similar concepts to XMPP.
After a few weeks of discussions, we published XEP-0503: Server-side Spaces, which was then presented at the XMPP Summit in Brussels in February 2026.
So What Exactly Is It in XMPP?
XMPP is all about reusability and extensibility. As the saying goes: "it's in old pots that we make the best jams."
If you understood the XMPP concepts introduced in the previous sections, you'll see that Spaces in XMPP simply reuse them, defining a way to combine existing building blocks in a coherent way.
Wait, is that all? Yes, pretty much 😸. XMPP already had most of the features needed for Spaces; we just needed some glue and careful thought to put the right pieces together.
So what is a Space? A Space is essentially a shared, mixed PubSub bookmark node.
Just as a user stores their own personal bookmarks on their own account, an XMPP user can create a "Space node" on a dedicated public PubSub server and invite others to it.
<iq type='result'
from='megacorp-pubsub.example.com'
to='emacs-user@megacorp.example.com/cool-client'
id='space-items'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<items node='dev'>
<item id='programming-socks@conference.megacorp.example.com'>
<conference xmlns='urn:xmpp:bookmarks:1'
name='Share your best programming socks deal HERE'>
<extensions>
<pinned xmlns='urn:xmpp:bookmarks-pinning:0'/>
</extensions>
</conference>
</item>
<item id='editors@conference.megacorp.example.com'>
<conference xmlns='urn:xmpp:bookmarks:1'
name='Settling the text editor wars'>
</conference>
</item>
<item id='some-hash'>
<subscription xmlns="urn:xmpp:pubsub:subscription:0"
server="megacorp-pubsub.example.com"
node="dev-announcements" />
</item>
<!-- other items -->
</items>
</pubsub>
</iq>
A PubSub node can have different access models. The Spaces XEP defines three of them: open, authorize, and whitelist.
open: anyone can discover, list, and subscribe to the Space.authorize: a user can request to join the Space.whitelist: a Space owner manually adds new users; join requests are not allowed.
For now, Movim only implements the authorize flow, which allows you to create private Spaces with an invitation "key" (essentially the URI of the Space on the XMPP network). The whitelist model, useful when you don't want to deal with join requests, should be implemented shortly after.
open Spaces will require a bit more work, as they may involve additional moderation features.
Let's start small and simple 😽
Another current limitation is XMPP server support. Prosody doesn't implement the authorize access model yet, so the Spaces feature is only fully working and tested with the ejabberd server. The Prosody developers are aware of this and are working on it 👀.
How to Create a Space in Movim?
To create a Space, Movim needs two things:
- An available chatroom service on your XMPP server. This is usually already present, as it's a widely deployed feature on the XMPP network.
- An available PubSub service on your XMPP server whose name starts with
spaces.(e.g.,spaces.movim.eu). Why this specific requirement? Because XEP-0462: PubSub Type Filtering, which would allow a client to filter PubSub service nodes by type, is not yet implemented. Without it, created Spaces would be mixed in with other PubSub nodes. Using a dedicated service keeps things clean and separate for now.
If you need to set up your own Spaces PubSub service on your XMPP server (ejabberd only for now, though this may change), we've documented the required configuration on the Movim Wiki.
Once Movim detects both of these, you'll be able to create a new Space from the user interface 😸!
How to Join a Space in Movim?
To join a Space in Movim, one of the Space's owners or members shares the Space "key" with a contact. A key looks like this:
xmpp:spaces.movim.eu?;node=6mUb3XUw
It's an XMPP URI where the first part is the XMPP service hosting the Space, and the node part is the Space's identifier.
The contact then opens the New Space form in the Movim sidebar and pastes the key. This is very similar to the Discord invitation link flow.

Movim then does two things:
- Adds the Space bookmark to the user's personal Spaces bookmarks node. This new private bookmark node is not yet standardized (it's currently located at
{https://movim.eu}spaces_subscriptions_node), but it will be added to the Spaces XEP (or a related one) soon. - Sends a subscription request to the PubSub node.
The Spaces PubSub service then returns a pending message.
<iq xml:lang='en' to='pooja@jabber.in/Movim' from='spaces.movim.eu' type='result' id='t1Os56cXzKmW'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<subscription subscription='pending' node='6mUb3XUw' jid='pooja@jabber.in'/>
</pubsub>
</iq>
In the meantime, a private message is sent to all Space owners, who can then accept or deny the request.

The Space will appear as locked 🔒 in the navigation bar until the request is approved.
Once approved, Movim receives a notification and discovers all the Space's content, including related rooms, and connects to them.

Trickle-Down Affiliations
While trickle-down theory doesn't hold up in economics, it turns out to be quite useful for synchronizing affiliations between Spaces and their rooms.
When an owner adds a new room to a Space, Movim lists all Space members and owners and sets them as members and owners of the new room respectively.
Similarly, when a new member is added, or when an owner promotes another user to owner, Movim propagates that change across all rooms in the Space.
This is currently handled by Movim itself, but one could imagine a dedicated Space module on the server side that enforces this and prevents client-side synchronization errors, while also reducing the number of small queries required to keep things in sync.
What About Notifications?
XEP-0492 defines a bookmark extension that allows clients to manage notification settings for incoming room messages. Movim already implements this. It defines three global states: never, on-mention, and always.
Since Spaces are stored as PubSub node bookmarks, this extension can be reused to define a global notification setting per Space!

XMPP is always about recycling features to build new ones ♻️!
What's Next?
The current implementation is basic but it works! Over the coming weeks and months, many features will be added and refined to deliver a more fluid and stable user experience.
As mentioned above, there are plans to flesh out access model management and affiliations further, and to support public Spaces soon-ish 😽.
Most of the existing features are already standardized, but a few smaller details and flows will be written up in new XEPs or completed in existing ones.
Issues will also be filed with various XMPP server projects to ensure that most XMPP servers can host and manage Spaces in the future. And it would obviously be great to see other XMPP clients implement the feature too 👀.
In Movim, the Next Big Thing™️ will be to (finally) add dedicated audio rooms, and maybe video later, to Spaces, so that members can talk to each other with a single click.
Fund the Next Awesome Movim Features 🫶
All the work on Spaces was done in my free time over the course of a couple of weeks. I'd love to free up more time to keep fixing bugs and adding exciting new features to Movim.
If you'd like to support Movim and help accelerate the project's development, I've launched the "Fund Movim for 2026" campaign on the main website.
A huge thank you to all existing supporters, I hope you enjoy all these new features, and the ones still to come ✨
That's all, folks!




