# Widgets

> Add an iframe agents can open from the Kustomer navigation rail on any page, with per-org URLs, sizing, browser permissions and background loading.

Source: https://developer.kustomer.com/docs/apps/widgets

A **widget** is a page you host that agents open from the navigation rail, whatever they're looking at. Use one for tools agents need alongside every conversation: a softphone, an order lookup, a knowledge tool, a portal into another system. Unlike a [KView](https://developer.kustomer.com/docs/apps/kviews), a widget isn't tied to a record. It stays open as the agent moves around, and receives context updates through the Cards SDK.

If an org has one widget, its icon sits directly in the rail. With several, they're grouped under a widgets menu.

## Define a widget

```json title="widgets (excerpt)"
{
  "settings": {
    "default": {
      "storeDomain": { "type": "string", "defaultValue": "", "required": true }
    }
  },
  "widgets": [
    {
      "name": "order-lookup",
      "title": "Acme lookup",
      "url": "https://kustomer.acme.example/widget?store={{{settings.default.storeDomain}}}",
      "icon": "https://kustomer.acme.example/widget-icon.png",
      "width": "24vw",
      "height": "60vh",
      "iframePermissions": "microphone *; autoplay *;",
      "backgroundLoad": false
    }
  ]
}
```

**Widget**

> **Sizing:** Agents use Kustomer on everything from laptops to ultra-wide monitors. Prefer viewport units (`vw`, `vh`) or `calc()` with a pixel minimum over fixed pixel sizes.

## Talk to Kustomer from the widget

A widget page loads the same [Cards SDK](https://developer.kustomer.com/docs/apps/kviews#the-cards-sdk) as an embedded KView:

```html title="widget.html"
<script src="https://cdn.kustomerapp.com/card-js/latest/kustomer-card.min.js"></script>
<script>
  Kustomer.initialize((context) => {
    showFor(context)
  })

  // Fires when the context changes, including when the agent opens or closes the widget.
  Kustomer.on('context', (context) => {
    if (context.widget && !context.widget.isOpen && hasUnsavedWork()) {
      Kustomer.open() // reopen so the agent can finish
      return
    }
    showFor(context)
  })
</script>
```

The widget context has `type: "widget"` and `widget.isOpen`, so your page can react when the agent opens or closes it. From there you can:

- Read and write Kustomer data with `Kustomer.request` (as the agent).
- Call your own API with credentials kept server-side through [commands](https://developer.kustomer.com/docs/apps/kviews#call-apis-with-commands).
- Send the agent to a customer with `Kustomer.openCustomer(id)` or `Kustomer.openCustomerEvent(customerId, eventId)`.
- Open the widget with `Kustomer.open()`, for example on an incoming call.

### Voice and presence events

Softphone widgets can subscribe to telephony and routing events:

| Event                   | Fires when                                                    |
| ----------------------- | ------------------------------------------------------------- |
| `number-dialed`         | An agent clicks a phone number in Kustomer to dial it         |
| `routing-status-change` | The agent's routing status changes, such as available to busy |

```js
Kustomer.on('number-dialed', (payload) => softphone.dial(payload))
```

## Background loading

`backgroundLoad: true` loads your page for every agent in the org as soon as Kustomer opens. Keep that cheap:

- Load under 1 MB of assets before the agent interacts.
- Keep `console` output to a minimum.
- Don't open the widget automatically unless something needs the agent, like an incoming call. Several auto-opening widgets competing for attention frustrate agents.

## Design checklist

- [ ] Works at the smallest width you set, and at 2× that.
- [ ] Uses the theme's [CSS variables](https://developer.kustomer.com/docs/apps/kviews#support-dark-mode) so it's readable in dark mode.
- [ ] Handles [masked fields](https://developer.kustomer.com/docs/apps/kviews#handle-masked-data) in context data.
- [ ] Shows a useful state when settings are missing, instead of a blank frame.
- [ ] Served over HTTPS and allows framing by Kustomer (no `X-Frame-Options: DENY`, and a `frame-ancestors` policy that includes your customers' Kustomer domains).
