How it works#

inspect-jitsi works by joining the room as a participant and inspecting who is there.

Jitsi's prosody deployment locks down disco#info on MUC rooms to occupants only (confirmed live: a bare disco#info query gets <error type="auth"><forbidden/></error>), so the usual XEP-0045 "peek without joining" trick doesn't work here. Instead, JitsiXmppConnection briefly joins the room as a real (if anonymous) occupant over an XMPP connection carried by WebSocket (the same wss://<domain>/xmpp-websocket endpoint the web client itself uses), reads the roster of <presence> stanzas the MUC sends back, then leaves - meaning the room briefly gains (and loses) one occupant, and other participants may see a transient join/leave notification.

No Python XMPP library (slixmpp, aioxmpp, …) supports the WebSocket transport Jitsi requires - they're TCP-only, and Jitsi deployments generally don't expose raw XMPP client-to-server (port 5222) publicly - so inspect_jitsi.xmpp.connection hand-rolls the small slice of RFC 6120 (stream/SASL/bind) and RFC 7395 (XMPP over WebSocket framing) needed to join a MUC room.

jicofo (the conference focus component) also joins every active Jitsi conference's MUC as a pseudo-participant nicknamed focus - that occupant is filtered out so participant counts/lists reflect only humans.

Deployments (e.g. docker-jitsi-meet) commonly use an internal XMPP domain (typically meet.jitsi) and MUC component (typically muc.meet.jitsi) that differ from the public hostname in the URL - the public web server proxies the WebSocket through, but the XMPP stream's to attribute and the MUC room JID must use the internal names. discover_hosts() figures these out automatically by reading the site's public /config.js (the same file the browser client itself relies on), rather than guessing.