UNITHdocs
Sign inarrow_forward
warning_amber

The documentation listed here is subject to change.

🧠 How to Embed and Control the Unith Widget

This guide explains how to embed the Unith Digital Human (Stream) widget into any website or web app — and how to send messages to it programmatically from external scripts.

info

You can embed the UNITH stream url as an iframe. This documentation is to give users more control.


1️⃣ Basic Embed Setup

The Unith widget is distributed as a Custom Web Component (<unith-widget>) that you can use in any HTML, React, or Next.js project.

Example (Plain HTML)

code
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Unith Widget Example</title>

  <script src="https://embedded-stream.unith.ai/index.js" defer></script>
</head>
<body>
  <div style="width: 400px; height: 500px; border-radius: 16px; overflow: hidden;">
    <unith-widget
      head_id="Public_head-ID"
      org_id="YourPublicOrg-ID"
      api_key="YOUR_API_KEY_HERE"
      username="USER_SPEAKING_TO_DH">
    </unith-widget>
  </div>
</body>
</html>

2️⃣ Styling the Widget

The <unith-widget> element uses a Shadow DOM, so normal CSS cannot reach inside. You can style around it using a wrapper container.

code
.unith-container {
  width: 400px;
  height: 500px;
  border-radius: 16px;
  overflow: hidden;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
  background: #fff;
}

💡 If you’re using the floating “chat bubble” version, use:

code
<unith-widget
....
  variant="widget"
  placement="bottom-right">
</unith-widget>

3️⃣ Sending External Messages to the Chat

Sometimes you may want to programmatically send a message into the chat (e.g. when a user performs an action elsewhere in your app).

The Unith widget doesn’t expose a public JS API yet, but since it uses an open Shadow DOM, you can access its input field and simulate a send.

Full Example

code
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Unith Chat Message Test</title>
  <script src="https://embedded-stream.unith.ai/index.js" defer></script>
  <style>
    .unith-container { width: 420px; height: 520px; border-radius: 16px; overflow: hidden; box-shadow: 0 8px 30px rgba(0,0,0,0.12); background: #fff; }
    .controls { margin-top: 1rem; }
    button { padding: 0.6rem 1rem; border: none; border-radius: 8px; background: #4a90e2; color: white; cursor: pointer; }
  </style>
</head>
<body>
  <h2>Send Message to Unith Widget</h2>

  <div class="unith-container">
    <unith-widget
      id="unith"
      head_id="name-17493"
      org_id="orgname-id"
      api_key="YOUR_API_KEY_HERE">
    </unith-widget>
  </div>

  <div class="controls">
    <button id="send">Send "Hello Samantha"</button>
  </div>

  <script>
    // Utility: wait until input exists
    const waitForInput = async (widget, retries = 30) => {
      for (let i = 0; i < retries; i++) {
        if (widget.shadowRoot) {
          const input = widget.shadowRoot.querySelector('input[type="text"]');
          if (input) return input;
        }
        await new Promise(r => setTimeout(r, 300));
      }
      throw new Error("Chat input not found");
    };

    async function sendMessageToWidget(text) {
      const widget = document.getElementById("unith");
      const input = await waitForInput(widget);

      input.focus();
      input.value = text;

      // Trigger the input event so the component updates its state
      input.dispatchEvent(new InputEvent("input", {
        bubbles: true, cancelable: true, composed: true,
        data: text, inputType: "insertText"
      }));

      // Simulate Enter keypress
      ["keydown", "keypress", "keyup"].forEach(type =>
        input.dispatchEvent(new KeyboardEvent(type, {
          key: "Enter", code: "Enter", keyCode: 13, which: 13,
          bubbles: true, cancelable: true, composed: true
        }))
      );

      // Try clicking send button if it exists
      const btn = widget.shadowRoot.querySelector("button");
      if (btn) btn.click();
    }

    document.getElementById("send").addEventListener("click", () => {
      sendMessageToWidget("Hello Samantha");
    });
  </script>
</body>
</html>

How it works

  1. Waits for the widget to load.
  2. Accesses its Shadow DOM input.
  3. Sets the message text.
  4. Dispatches an input + Enter sequence to mimic user typing.
  5. Falls back to clicking a visible send button if found.

4️⃣ Two-Way Event Communication (Optional)

You can also listen for events or messages coming from the widget:

code
const widget = document.getElementById('unith');

widget.addEventListener('message', (e) => {
  console.log('Widget event:', e.detail);
});

// Example of sending a custom event to the widget
widget.dispatchEvent(new CustomEvent('externalCommand', {
  detail: { command: 'sayHello', payload: { text: 'Hi there!' } }
}));

Or if the widget runs inside an iframe internally, you can communicate via window.postMessage:

code
window.addEventListener('message', (event) => {
  console.log('Received postMessage from Unith:', event.data);
});

5️⃣ Troubleshooting

IssueLikely CauseFix
Input not foundWidget not fully loaded yetWait longer before accessing shadowRoot
Text appears but doesn’t sendFramework ignores synthetic key eventsUse InputEvent + click the send button
No access to shadowRootWidget uses mode: "closed"Use official Unith API when available
Style changes don’t applyCSS isolationWrap widget in a container and style that

For production use:

  • Wrap all widget control logic in a ready or loaded event listener.
  • Keep all direct DOM manipulation in a utility like sendMessageToWidget(text).
  • Avoid tight loops; give the widget a small delay to initialize.
  • Prefer official APIs once released.

Example Structure Summary

code
<script src="https://embedded-stream.unith.ai/index.js" defer></script>
<div class="unith-container">
  <unith-widget head_id="..." org_id="..." api_key="..."></unith-widget>
</div>

<script>
  // your custom integration logic here
</script>
scheduleLast updated Feb 18, 2026
Embedding Streaming Digital Humans (alpha version) · UNITH Docs