diff --git a/packages/moxxmpp/lib/moxxmpp.dart b/packages/moxxmpp/lib/moxxmpp.dart
index 92cd8f5..10cbb94 100644
--- a/packages/moxxmpp/lib/moxxmpp.dart
+++ b/packages/moxxmpp/lib/moxxmpp.dart
@@ -85,6 +85,7 @@ export 'package:moxxmpp/src/xeps/xep_0388/errors.dart';
export 'package:moxxmpp/src/xeps/xep_0388/negotiators.dart';
export 'package:moxxmpp/src/xeps/xep_0388/user_agent.dart';
export 'package:moxxmpp/src/xeps/xep_0388/xep_0388.dart';
+export 'package:moxxmpp/src/xeps/xep_0421.dart';
export 'package:moxxmpp/src/xeps/xep_0424.dart';
export 'package:moxxmpp/src/xeps/xep_0444.dart';
export 'package:moxxmpp/src/xeps/xep_0446.dart';
diff --git a/packages/moxxmpp/lib/src/managers/namespaces.dart b/packages/moxxmpp/lib/src/managers/namespaces.dart
index 713493d..bb2d241 100644
--- a/packages/moxxmpp/lib/src/managers/namespaces.dart
+++ b/packages/moxxmpp/lib/src/managers/namespaces.dart
@@ -32,3 +32,4 @@ const messageReactionsManager = 'org.moxxmpp.messagereactionsmanager';
const stickersManager = 'org.moxxmpp.stickersmanager';
const entityCapabilitiesManager = 'org.moxxmpp.entitycapabilities';
const messageProcessingHintManager = 'org.moxxmpp.messageprocessinghint';
+const occupantIdManager = 'org.moxxmpp.occupantidmanager';
diff --git a/packages/moxxmpp/lib/src/namespaces.dart b/packages/moxxmpp/lib/src/namespaces.dart
index d5bd41f..e23e962 100644
--- a/packages/moxxmpp/lib/src/namespaces.dart
+++ b/packages/moxxmpp/lib/src/namespaces.dart
@@ -123,6 +123,9 @@ const sasl2Xmlns = 'urn:xmpp:sasl:2';
// XEP-0420
const sceXmlns = 'urn:xmpp:sce:1';
+// XEP-0421
+const occupantIdXmlns = 'urn:xmpp:occupant-id:0';
+
// XEP-0422
const fasteningXmlns = 'urn:xmpp:fasten:0';
diff --git a/packages/moxxmpp/lib/src/xeps/xep_0421.dart b/packages/moxxmpp/lib/src/xeps/xep_0421.dart
new file mode 100644
index 0000000..311fd5b
--- /dev/null
+++ b/packages/moxxmpp/lib/src/xeps/xep_0421.dart
@@ -0,0 +1,66 @@
+import 'dart:async';
+import 'package:moxxmpp/src/managers/base.dart';
+import 'package:moxxmpp/src/managers/data.dart';
+import 'package:moxxmpp/src/managers/handlers.dart';
+import 'package:moxxmpp/src/managers/namespaces.dart';
+import 'package:moxxmpp/src/namespaces.dart';
+import 'package:moxxmpp/src/stanza.dart';
+import 'package:moxxmpp/src/stringxml.dart';
+
+/// Representation of a element.
+class OccupantIdData implements StanzaHandlerExtension {
+ const OccupantIdData(
+ this.id,
+ );
+
+ /// The unique occupant id.
+ final String id;
+
+ XMLNode toXML() {
+ return XMLNode.xmlns(
+ tag: 'occupant-id',
+ xmlns: occupantIdXmlns,
+ attributes: {
+ 'id': id,
+ },
+ );
+ }
+}
+
+class OccupantIdManager extends XmppManagerBase {
+ OccupantIdManager() : super(occupantIdManager);
+
+ @override
+ List getDiscoFeatures() => [
+ occupantIdXmlns,
+ ];
+
+ @override
+ List getIncomingStanzaHandlers() => [
+ StanzaHandler(
+ stanzaTag: 'message',
+ callback: _onMessage,
+ // Before the MessageManager
+ priority: -99,
+ ),
+ ];
+
+ @override
+ Future isSupported() async => true;
+
+ Future _onMessage(
+ Stanza stanza,
+ StanzaHandlerData state,
+ ) async {
+ OccupantIdData? occupantId;
+ final occupantIdElement =
+ stanza.firstTag('occupant-id', xmlns: occupantIdXmlns);
+ // Process the occupant id
+ if (occupantIdElement != null) {
+ occupantId =
+ OccupantIdData(occupantIdElement.attributes['id']! as String);
+ state.extensions.set(occupantId);
+ }
+ return state;
+ }
+}