{"result":{"depiction_url":null,"edges":{"hasreference":{"objects":[{"created":"2026-10-07T11:13:49Z","object_id":{"id":1539,"is_a":["text","documentation","developerguide"],"name":"doc_developerguide_wires","title":{"_type":"trans","tr":{"en":"Handle a browser event with a wire"}},"uri":"https:\/\/zotonic.com\/id\/1539"},"seq":1},{"created":"2026-10-07T11:13:49Z","object_id":{"id":2965,"is_a":["text","documentation","developerguide"],"name":"developer_browser_messaging","title":{"_type":"trans","tr":{"en":"Use Cotonic and MQTT for browser messaging"}},"uri":"https:\/\/zotonic.com\/id\/2965"},"seq":2},{"created":"2026-10-07T11:13:49Z","object_id":{"id":2966,"is_a":["text","documentation","developerguide"],"name":"developer_http_api","title":{"_type":"trans","tr":{"en":"Expose an operation through an API"}},"uri":"https:\/\/zotonic.com\/id\/2966"},"seq":3}],"predicate":{"id":2774,"is_a":["meta","predicate"],"name":"hasreference","title":{"_type":"trans","tr":{"en":"Documentation reference"}},"uri":"https:\/\/zotonic.com\/id\/hasreference"}},"references":{"objects":[{"created":"2020-05-30T05:47:56Z","object_id":{"id":1324,"is_a":["text","documentation","reference","module"],"name":"doc_module_mod_mqtt","title":"mod_mqtt","uri":"https:\/\/zotonic.com\/id\/1324"},"seq":1000000},{"created":"2020-05-30T05:47:56Z","object_id":{"id":1323,"is_a":["text","documentation","reference","template_scomp"],"name":"doc_template_scomp_scomp_live","title":"live","uri":"https:\/\/zotonic.com\/id\/1323"},"seq":1000000},{"created":"2020-05-30T05:47:56Z","object_id":{"id":1303,"is_a":["text","documentation","reference","module"],"name":"doc_module_mod_wires","title":"mod_wires","uri":"https:\/\/zotonic.com\/id\/1303"},"seq":1000000},{"created":"2020-05-30T05:47:56Z","object_id":{"id":1274,"is_a":["text","documentation","developerguide"],"name":"doc_developerguide_notifications","title":{"_type":"trans","tr":{"en":"Respond to a notification"}},"uri":"https:\/\/zotonic.com\/id\/1274"},"seq":1000000},{"created":"2020-05-30T05:47:56Z","object_id":{"id":1892,"is_a":["text","documentation","reference","controller"],"name":"doc_controller_controller_mqtt_transport","title":"controller_mqtt_transport","uri":"https:\/\/zotonic.com\/id\/1892"},"seq":1000000}],"predicate":{"id":332,"is_a":["meta","predicate"],"name":"references","title":{"_type":"trans","tr":{"en":"References"}},"uri":"https:\/\/zotonic.com\/id\/references"}},"refers":{"objects":[{"created":"2026-10-07T11:13:00Z","object_id":{"id":1327,"is_a":["text","documentation","reference","template_scomp"],"name":"doc_template_scomp_scomp_wire","title":"wire","uri":"https:\/\/zotonic.com\/id\/1327"},"seq":1000000},{"created":"2026-10-07T11:13:00Z","object_id":{"id":1536,"is_a":["text","documentation","developerguide"],"name":"doc_developerguide_access_control","title":{"_type":"trans","tr":{"en":"Keep permission checks at the boundary"}},"uri":"https:\/\/zotonic.com\/id\/1536"},"seq":1000000},{"created":"2026-10-07T11:13:00Z","object_id":{"id":1831,"is_a":["text","documentation","reference","module"],"name":"doc_module_mod_oauth2","title":"mod_oauth2","uri":"https:\/\/zotonic.com\/id\/1831"},"seq":1000000},{"created":"2026-10-07T11:13:00Z","object_id":{"id":1875,"is_a":["text","documentation","reference","controller"],"name":"doc_controller_controller_api","title":"controller_api","uri":"https:\/\/zotonic.com\/id\/1875"},"seq":1000000},{"created":"2026-10-07T11:13:00Z","object_id":{"id":2736,"is_a":["text","documentation","reference","cotonic_reference","cotonic_model"],"name":"doc_cotonic_model_location","title":"model\/location","uri":"https:\/\/zotonic.com\/id\/2736"},"seq":1000000},{"created":"2026-10-07T11:13:00Z","object_id":{"id":2960,"is_a":["text","documentation","developerguide"],"name":"developer_model_api","title":{"_type":"trans","tr":{"en":"Expose data through a model"}},"uri":"https:\/\/zotonic.com\/id\/2960"},"seq":1000000}],"predicate":{"id":2409,"is_a":["meta","predicate"],"name":"refers","title":{"_type":"trans","tr":{"en":"Refers"}},"uri":"https:\/\/zotonic.com\/id\/refers"}},"relation":{"objects":[{"created":"2020-05-30T05:47:56Z","object_id":{"id":1324,"is_a":["text","documentation","reference","module"],"name":"doc_module_mod_mqtt","title":"mod_mqtt","uri":"https:\/\/zotonic.com\/id\/1324"},"seq":1000000}],"predicate":{"id":303,"is_a":["meta","predicate"],"name":"relation","title":{"_type":"trans","tr":{"nl":"Relatie","en":"Relation"}},"uri":"http:\/\/purl.org\/dc\/terms\/relation"}},"subject":{"objects":[{"created":"2026-10-07T11:13:49Z","object_id":{"id":2554,"is_a":["categorization","keyword","keyword_information_type"],"name":"zotonic_topic_how_to_guide","title":"How-to guide","uri":"https:\/\/zotonic.com\/id\/2554"},"seq":1},{"created":"2026-10-07T11:13:49Z","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-07T11:13:49Z","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-07T11:13:49Z","object_id":{"id":2624,"is_a":["categorization","keyword","keyword_architecture"],"name":"zotonic_topic_wire_action","title":"Wire action","uri":"https:\/\/zotonic.com\/id\/2624"},"seq":4},{"created":"2026-10-07T11:13:49Z","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-07T11:13:49Z","object_id":{"id":2599,"is_a":["categorization","keyword","keyword_domain"],"name":"zotonic_topic_api_and_integration","title":"API and integration","uri":"https:\/\/zotonic.com\/id\/2599"},"seq":6}],"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":1302,"is_a":["text","documentation","developerguide"],"links":[{"rel":"self","target":"https:\/\/zotonic.com\/.zotonic\/websub\/topic\/1302"},{"rel":"hub","target":"https:\/\/zotonic.com\/.zotonic\/websub"}],"medium":null,"medium_url":null,"name":"doc_developerguide_server_browser_interaction","page_url":{"en":"https:\/\/zotonic.com\/docs\/1302\/handle-a-browser-event-with-a-wire","x-default":"https:\/\/zotonic.com\/docs\/1302\/handle-a-browser-event-with-a-wire"},"preview_url":null,"resource":{"body":{"_type":"trans","tr":{"en":"<p>Use <a href=\"\/id\/1327\" class=\"doc-reference doc-reference-scomp\"><code>scomp#wire<\/code><\/a> to connect a browser event to an action or a server postback. Give the target element a stable ID within the rendered page.<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-django\">&lt;button id=&quot;show-help&quot; type=&quot;button&quot;&gt;{_ Show help _}&lt;\/button&gt;\n&lt;div id=&quot;garden-help&quot; style=&quot;display:none&quot;&gt;{_ Choose a sunny spot. _}&lt;\/div&gt;\n{% wire id=&quot;show-help&quot; action={show target=&quot;garden-help&quot;} %}\n<\/code><\/pre>\n<p>Use a server postback when the action needs server data or writes content. A client-side action alone cannot authorize a write. Check the browser console and the server logs when an event appears to do nothing.<\/p>\n<p>Use a base template with the standard JavaScript includes and a final <code>{% script %}<\/code>; enable <code>mod_wires<\/code> on the site. Put the example inside its content block. Click <strong>Show help<\/strong> and expect the hidden text to appear without navigation. If this partial can appear twice, use generated template IDs such as <code>#show_help<\/code> rather than repeating the literal ID.<\/p>\n<h2>Use Cotonic and MQTT for browser messaging<\/h2>\n<p>Use the existing Cotonic browser models and Zotonic MQTT bridge when components need to communicate through topics. First identify whether the topic stays inside the browser or crosses to the server.<\/p>\n<p>Define a small payload and a clear reply contract. Subscribe before requesting data when the response can arrive immediately. Clean up component subscriptions when their lifetime ends, and handle reconnects without duplicating actions.<\/p>\n<p>Server-side topic access must follow the site&#39;s permission rules. A topic name is not a secret or an access check.<\/p>\n<p>With the greeting model from the model task active, try this read in the browser console:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-javascript\">cotonic.ready.then(() =&gt;\n    cotonic.broker.call(&quot;bridge\/origin\/model\/garden\/get\/greeting&quot;, {})\n).then(reply =&gt; console.log(reply.payload));\n<\/code><\/pre>\n<p>Inspect the reply&#39;s status and result; expect the greeting on success. An error or disconnected bridge is not an empty greeting. The <code>bridge\/origin\/<\/code> prefix crosses to the site&#39;s server model, while a browser-local model such as <code>model\/location<\/code> stays in the browser. Use <a href=\"\/id\/2736\" class=\"doc-reference doc-reference-cotonic\"><code>cotonic#location<\/code><\/a> for the latter&#39;s topic contract. Do not insert response text as HTML without escaping it.<\/p>\n<h2>Expose an operation through an API<\/h2>\n<p>Start from the site&#39;s existing model API or controller patterns. Specify the method, input fields, response shape, and errors before connecting a browser or external client.<\/p>\n<p>Use a read operation for retrieval and an appropriate write operation for changes. Apply authentication and authorization to each operation. Test malformed input and access denial as well as a successful response.<\/p>\n<p>Keep transport details out of shared domain functions so the same operation can serve a template, event handler, or API safely. See <a href=\"\/id\/1831\" class=\"doc-reference doc-reference-module\"><code>module#mod_oauth2<\/code><\/a>, <a href=\"\/id\/2960\">Expose data through a model<\/a>, and <a href=\"\/id\/1536\">Keep permission checks at the boundary<\/a>.<\/p>\n<p>The greeting model provides a read-only first check. On the site&#39;s hostname, request:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-text\">GET \/api\/model\/garden\/get\/greeting\n<\/code><\/pre>\n<p>Expect a JSON success response with the greeting as its result. Confirm the HTTP status and response body. Request an unknown path too; the model should return its <code>unknown_path<\/code> error. This uses the public example from the model task, so no token is required for that particular value.<\/p>\n<p>For protected operations, use the authentication mechanism supported by <a href=\"\/id\/1875\" class=\"doc-reference doc-reference-controller\"><code>controller#controller_api<\/code><\/a>, for example an appropriately scoped OAuth token. Authentication identifies the caller; the model still must authorize access. Keep tokens out of URLs and example files. Read the controller reference for response envelopes, HTTP methods and request-body handling before adding writes.<\/p>"}},"category_id":{"id":317,"is_a":["meta","category"],"name":"developerguide","title":"Developer guide","uri":"https:\/\/zotonic.com\/id\/developerguide"},"content_group_id":{"id":339,"is_a":["meta","content_group"],"name":"default_content_group","title":{"_type":"trans","tr":{"en":"Default Content Group"}},"uri":"https:\/\/zotonic.com\/id\/default_content_group"},"created":"2020-05-30T05:47:17Z","creator_id":{"id":336,"is_a":["person","robot"],"name":"gitbot","title":"Git","uri":"https:\/\/zotonic.com\/id\/336"},"doc_editorial_bundle":true,"doc_editorial_edges":{"hasreference":[1539,2965,2966],"subject":[2554,2563,2564,2598,2599,2624]},"github_url":"https:\/\/github.com\/zotonic\/zotonic\/tree\/master\/doc\/developer-guide\/server-browser-interaction.rst","is_authoritative":true,"is_dependent":false,"is_featured":false,"is_protected":false,"is_published":true,"is_unfindable":false,"language":["en"],"modified":"2026-10-07T11:14:02Z","modifier_id":{"id":1,"is_a":["person"],"name":"administrator","title":"Site Administrator","uri":"https:\/\/zotonic.com\/id\/1"},"name":"doc_developerguide_server_browser_interaction","pivot_geocode":null,"pivot_location_lat":null,"pivot_location_lng":null,"privacy":0,"publication_end":"9999-06-01T00:00:00Z","publication_start":"2022-02-15T10:01:20Z","slug":"handle-a-browser-event-with-a-wire","summary":{"_type":"trans","tr":{"en":"Use scomp#wire to connect a browser event to an action or a server postback. Give the target element a stable ID within the rendered page."}},"title":{"_type":"trans","tr":{"en":"Handle a browser event with a wire"}},"title_slug":{"_type":"trans","tr":{"en":"handle-a-browser-event-with-a-wire"}},"tz":"UTC","uri":null,"version":45,"visible_for":0},"uri":"https:\/\/zotonic.com\/id\/1302","uri_template":"https:\/\/zotonic.com\/id\/:id","websub":{"hub":"https:\/\/zotonic.com\/.zotonic\/websub","topic":"https:\/\/zotonic.com\/.zotonic\/websub\/topic\/1302"}},"status":"ok"}