{"result":{"depiction_url":null,"edges":{"observes":{"objects":[{"created":"2026-10-22T10:25:08Z","object_id":{"id":1468,"is_a":["text","documentation","reference","notification"],"name":"doc_notification_acl_is_allowed","title":"observe_acl_is_allowed\/2","uri":"https:\/\/zotonic.com\/id\/1468"},"seq":1}],"predicate":{"id":2550,"is_a":["meta","predicate"],"name":"observes","title":{"_type":"trans","tr":{"en":"Observes"}},"uri":"https:\/\/zotonic.com\/id\/observes"}},"subject":{"objects":[{"created":"2026-10-22T10:25:08Z","object_id":{"id":2555,"is_a":["categorization","keyword","keyword_information_type"],"name":"zotonic_topic_reference","title":"Reference","uri":"https:\/\/zotonic.com\/id\/2555"},"seq":1},{"created":"2026-10-22T10:25:08Z","object_id":{"id":2563,"is_a":["categorization","keyword","keyword_audience"],"name":"zotonic_topic_frontend_developer","title":"Frontend developer","uri":"https:\/\/zotonic.com\/id\/2563"},"seq":2},{"created":"2026-10-22T10:25:08Z","object_id":{"id":2564,"is_a":["categorization","keyword","keyword_audience"],"name":"zotonic_topic_backend_developer","title":"Backend developer","uri":"https:\/\/zotonic.com\/id\/2564"},"seq":3},{"created":"2026-10-22T10:25:08Z","object_id":{"id":2592,"is_a":["categorization","keyword","keyword_domain"],"name":"zotonic_topic_authorization_and_access_control","title":"Authorization and access control","uri":"https:\/\/zotonic.com\/id\/2592"},"seq":4},{"created":"2026-10-22T10:25:08Z","object_id":{"id":2598,"is_a":["categorization","keyword","keyword_domain"],"name":"zotonic_topic_messaging_and_pubsub","title":"Messaging and publish-subscribe","uri":"https:\/\/zotonic.com\/id\/2598"},"seq":5},{"created":"2026-10-22T10:25:08Z","object_id":{"id":2635,"is_a":["categorization","keyword","keyword_architecture"],"name":"zotonic_topic_module","title":"Module","uri":"https:\/\/zotonic.com\/id\/2635"},"seq":6},{"created":"2026-10-22T10:25:08Z","object_id":{"id":2677,"is_a":["categorization","keyword","keyword_technology"],"name":"zotonic_topic_mqtt","title":"MQTT","uri":"https:\/\/zotonic.com\/id\/2677"},"seq":7},{"created":"2026-10-22T10:25:08Z","object_id":{"id":2715,"is_a":["categorization","keyword","keyword_domain"],"name":"zotonic_topic_page_lifecycle","title":"Page lifecycle","uri":"https:\/\/zotonic.com\/id\/2715"},"seq":8}],"predicate":{"id":308,"is_a":["meta","predicate"],"name":"subject","title":{"_type":"trans","tr":{"en":"Keyword"}},"uri":"http:\/\/purl.org\/dc\/elements\/1.1\/subject"}}},"id":3104,"is_a":["text","documentation","reference","module"],"links":[{"rel":"self","target":"https:\/\/zotonic.com\/.zotonic\/websub\/topic\/3104"},{"rel":"hub","target":"https:\/\/zotonic.com\/.zotonic\/websub"}],"medium":null,"medium_url":null,"name":"doc_external_8_mod_presence","page_url":{"en":"https:\/\/zotonic.com\/docs\/3104\/mod_presence","x-default":"https:\/\/zotonic.com\/docs\/3104\/mod_presence"},"preview_url":null,"resource":{"version":19,"pivot_location_lat":null,"title":"mod_presence","is_authoritative":true,"body":"<p>Show who is viewing a shared location using browser presence messages. Enable\n<code>mod_presence<\/code> on the site; no module configuration keys are required.\nThe widgets use Zotonic&#39;s widget initialization and Cotonic broker bridge.<\/p>\n<h2>Template usage<\/h2>\n<p>Load the widgets and give both widgets the same location identifier:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-django\">{% lib &quot;js\/modules\/z.presence.js&quot; &quot;js\/modules\/z.presenceview.js&quot; %}\n&lt;span class=&quot;do_presence do_presenceview&quot; data-presence-where=&quot;foo&quot;&gt;&lt;\/span&gt;\n<\/code><\/pre>\n<p><code>do_presence<\/code> publishes the current browser&#39;s status. <code>do_presenceview<\/code>\ndisplays the users at that location and can be used on its own. The viewer\nalso accepts <code>data-presenceview-where<\/code>. Locations are client-chosen strings.\nThe module includes the scripts in the admin and adds presence indicators\nfor resource editing and overview lists using <code>mod_admin\/&lt;resource-id&gt;<\/code>.\nOverride <code>_presence_user.tpl<\/code> to customize the user-name fragment.<\/p>\n<h2>Messages and display<\/h2>\n<p>The publisher sends QoS 0 messages on\n<code>bridge\/origin\/presence\/status\/&lt;where&gt;<\/code> with <code>user_id<\/code>, a browser-widget\n<code>unique_id<\/code>, <code>where<\/code> and numeric <code>status<\/code>. Viewers request an update on\n<code>bridge\/origin\/presence\/request\/&lt;where&gt;<\/code>. The publisher checks activity each\nsecond and sends on changes or when more than seven seconds have elapsed.<\/p>\n<p>Status codes are <code>0<\/code> gone, <code>1<\/code> away, <code>2<\/code> idle, <code>3<\/code> present and <code>4<\/code> active.\nActivity ages through thresholds of 10, 60 and 300 seconds; page lifecycle\nand element removal also feed status changes. Viewers sort by status, hide\ngone entries and combine multiple entries for the same user. Present and\nactive users use <code>label-success<\/code>, idle users <code>label-info<\/code>, and away users\n<code>label-default<\/code>. This is transient browser state, not a stored attendance log.<\/p>\n<h2>Topic permissions<\/h2>\n<p>The ACL observer handles non-wildcard topics starting with <code>presence<\/code>.\nFor <code>presence\/&lt;kind&gt;\/mod_&lt;name&gt;\/...<\/code>, it checks <code>use<\/code> permission for that\nmodule; an unknown module atom is denied. Other non-wildcard presence topics\nrequire authentication. These rules apply regardless of the MQTT action.\nWildcard topics and unrelated ACL requests return <code>undefined<\/code> for other ACL\nhandlers to decide. Presence payloads are supplied by clients; this observer\nchecks topic access, not the identity fields in those payloads.<\/p>","slug":"mod_presence","doc_module_config":[],"is_protected":false,"visible_for":0,"tz":"UTC","language":["en"],"doc_source_hash":"6dd8c5b80963b42c14dfc8b697ea76fbed59aa31011dc05e8d5b0c2597bf7786","doc_module_observers":[{"name":"acl_is_allowed","page_name":"doc_notification_acl_is_allowed"}],"is_featured":false,"content_group_id":{"id":2551,"is_a":["meta","content_group"],"name":"content_group_imported_docs","title":"Imported documentation","uri":"https:\/\/zotonic.com\/id\/content_group_imported_docs"},"external_module_id":{"id":8,"is_a":[],"name":null,"title":null,"uri":"https:\/\/zotonic.com\/id\/8"},"git_url":"https:\/\/github.com\/zotonic\/zotonic_mod_presence.git","category_id":{"id":320,"is_a":["meta","category"],"name":"module","title":"Modules","uri":"https:\/\/test.zotonic.com\/id\/320"},"doc_source_path":".\/src\/mod_presence.erl","publication_start":"2026-10-22T10:25:08Z","github_url":"https:\/\/github.com\/zotonic\/zotonic_mod_presence.git","pivot_location_lng":null,"doc_source_kind":"external","name":"doc_external_8_mod_presence","is_unfindable":false,"is_published":true,"pivot_geocode":null,"external_module_title":"Presence","created":"2026-10-22T10:25:08Z","uri":null,"doc_status":"current","is_dependent":false,"is_external_module":true,"publication_end":"9999-06-01T00:00:00Z","modifier_id":{"id":1,"is_a":["person"],"name":"administrator","title":"Site Administrator","uri":"https:\/\/zotonic.com\/id\/1"},"privacy":0,"doc_source_commit":"5807920f894b819284bea078272f0c67a6753b7d","creator_id":{"id":1,"is_a":["person"],"name":"administrator","title":"Site Administrator","uri":"https:\/\/zotonic.com\/id\/1"},"modified":"2026-10-22T10:25:09Z","title_slug":"mod_presence"},"uri":"https:\/\/zotonic.com\/id\/3104","uri_template":"https:\/\/zotonic.com\/id\/:id","websub":{"hub":"https:\/\/zotonic.com\/.zotonic\/websub","topic":"https:\/\/zotonic.com\/.zotonic\/websub\/topic\/3104"}},"status":"ok"}