HTML Embed Builder
The /ui endpoint returns HTML that ZenEdge renders in a sandboxed iframe on the guest's magic link page.
How It Works
- Guest opens their magic link
- For each adapter with
html_embed: true, ZenEdge callsGET /ui?device_id=xxx - The returned HTML is rendered in a sandboxed iframe
- Guest interacts with the device tile (e.g., "Unlock Door" button)
Requirements
- Return valid HTML with
Content-Type: text/html - Self-contained — all CSS and JS inline or bundled
- Responsive — works on mobile and tablet screens
- Actions communicate via
postMessageto the parent frame
Security Model
The iframe is sandboxed with these restrictions:
sandbox="allow-scripts allow-same-origin"- No access to parent page DOM
- Communication only via
postMessage
Example
<!DOCTYPE html>
<html>
<head>
<style>
.tile { padding: 16px; font-family: sans-serif; text-align: center; }
.btn { padding: 12px 24px; background: #4CAF50; color: white; border: none; border-radius: 8px; font-size: 16px; cursor: pointer; }
.btn:hover { background: #45a049; }
</style>
</head>
<body>
<div class="tile">
<h3>Door Lock</h3>
<p id="status">Locked</p>
<button class="btn" onclick="unlock()">Unlock Door</button>
</div>
<script>
async function unlock() {
const res = await fetch('/action?device_id=ada-xxx', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'x-api-key': 'KEY' },
body: JSON.stringify({ action: 'unlock', params: { duration_seconds: 5 } })
});
if (res.ok) {
document.getElementById('status').textContent = 'Unlocked (5s)';
}
}
</script>
</body>
</html>
Next Steps
- Webhook Registration — Push events
- HMAC Signature Verification — Security