> For the complete documentation index, see [llms.txt](https://docs.nerovasystems.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.nerovasystems.com/ui-components/embedded-widgets.md).

# Embedded status widgets

Widget components render Nerova-served read and status surfaces inline in the partner page. Unlike the popup-launching [WhatsApp connect](https://docs.nerovasystems.com/ui-components/whatsapp-connect) component, widgets are framed: they load from a dedicated widget route that explicitly permits embedding for allow-listed partner origins.

## Surfaces

Two widget surfaces exist, one shipped and one planned:

* **WhatsApp channel details (shipped).** The merchant-facing view of a connected WhatsApp channel: display name, number quality rating, messaging limits, and business verification status, kept in sync with Meta.
* **Business verification progress (planned).** A guided view of Meta's business verification steps, so merchants can see where they are in the process and what is still required, without leaving the host product.

Both render read-only provider state. Anything that mutates state or handles provider credentials stays on the hosted connection page and the popup path.

## Embedding mechanics

`app.nerovasystems.com` denies framing everywhere by design. The deliberate `X-Frame-Options: DENY` is documented in the [host UI integration law](https://docs.nerovasystems.com/documentation/guides/host-ui-integration). Widgets therefore do not frame the app. They load from a dedicated widget route whose responses carry a `Content-Security-Policy: frame-ancestors` allow-list scoped to the embedding partner's registered origins. Framing is an explicit per-partner grant, never a default.

Widgets take theme tokens from the embed configuration so the rendered surface matches the host product's branding.

## How embedding works (shipped v1)

The WhatsApp channel details surface is live. The flow mirrors the hosted connection session pattern:

1. The partner backend calls `POST /api/partner/v1/merchants/{merchantId}/widgets/sessions` with its API key (requires the `merchant:read` grant) and receives an `embedUrl` of the form `https://app.nerovasystems.com/widget/whatsapp-channel/{sessionId}#state={secret}` plus an `expiresAt` timestamp.
2. The partner page sets that URL as an iframe `src`. The secret travels in the URL fragment, so it never reaches server logs; the widget SPA submits it in a POST body to the inspect endpoint, and Nerova stores only its hash.
3. Sessions live for 15 minutes (fixed, no configuration knob) and are not single use, so iframe reloads keep working. Partners create a new session per page view.
4. The partner's registered embed origins are snapshotted onto the session at creation time and become the `frame-ancestors` value. Origin edits do not retro-apply to live sessions; the 15 minute TTL bounds that staleness.
5. Every inspect call re-authorizes the API key that created the session, so revoking a key cuts off live widgets immediately.

The inspect endpoint is the only endpoint a widget session can call. Any future widget surface that mutates state requires a new design ruling before it is built.

### Theme tokens (v1)

`theme` on the session-create request accepts `colorMode` (`light` or `dark`), `primaryColor` (six-digit hex), `radiusPx` (0 to 32), and `fontFamily` (fixed allowlist: `system-ui`, `inter`, `roboto`, `open-sans`, `georgia`). Values are sanitized on the server at creation time and again in the widget client before they become CSS variables; anything outside these shapes is rejected.

### Demo mode

`/widget/whatsapp-channel/demo` renders the surface with local fixtures and no authentication, so docs pages can live-embed it. The demo route answers only for origins listed in the `WIDGET_DEMO_ORIGINS` environment variable (comma separated), which also becomes its `frame-ancestors` allow-list; an empty value disables it. The docs origin is the intended production entry. Theme tokens are passed as query parameters on the demo route.

## Security posture

* Widget surfaces are read-only; no provider credential ever reaches the widget or the partner page.
* The frame-ancestors allow-list is per partner. An origin not on the partner's list cannot render the widget.
* Hosts that place widgets inside sandboxed iframes should read the [embedding security model](https://docs.nerovasystems.com/ui-components/security-model) for the required sandbox permissions.

Installation, configuration options, and the event surface are published with each widget when it ships.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.nerovasystems.com/ui-components/embedded-widgets.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
