Add an Embedded App
Embed an external app or webpage directly into the agent's workspace as an iframe
An embedded app widget displays your own webpage or application inside the agent's workspace as an iframe. Glassix passes the open ticket's details to the widget, so the widget can display information about the customer the agent is currently speaking with.
This page covers embedded app widgets: iframes that appear inside the agent's workspace.
Overview
Embedded app widgets make it easy for agents to see the right information and take quick actions to support your users or convert your leads. They're great for streamlining existing workflows and enabling new ones by bringing other services into the Inbox.
Let's say your agents use a knowledge base or an external CRM while they're chatting. Instead of opening it in a separate window, you can add a widget that displays the CRM within the conversation details in your workspace, allowing agents to quickly view and use the information they need at any time.
Widget Types
When you create a widget, you choose where it appears in the workspace. The location you pick is passed to your iframe as the type query string parameter.
| Type | type parameter | Where it appears |
|---|---|---|
| Ticket Details Panel | TicketDetailsPanel | In the ticket details panel, alongside an open conversation. |
| Chat Widget Welcome Screen | ChatWidgetWelcomeScreen | On the chat widget's welcome screen. |
Create an Embedded App Widget
- Go to Settings.
Click on the symbol in the agent dashboard.
- Click Developers → Embedded App Widget.
- Click New App.
- In the URL text box, type the URL.
- In the Name text box, type a name of your choice.
- In the Height scroll bar, set the height of your widget in pixels. Valid values are 50–450 px. Anything outside that range falls back to 200 px.
- Click Save.
Once saved, each widget has the following properties:
- Name — the name of the widget app.
- URL — the webpage or external application you want to display inside the widget.
- Height — the default height of the widget, in pixels.
- Widget App Id — the widget's unique identifier, passed to your iframe as
applicationId. - Secret — used to verify the token Glassix sends to your iframe. See Verify the Token.
- Type — where the widget appears. See Widget Types.
How Glassix Calls Your Iframe
Widgets are iframes shown in the agent's workspace. In each ticket, an iframe appears with the source of the URL you defined, plus these query string parameters:
| Name | Description |
|---|---|
applicationId | UUID of your app widget. |
departmentId | Uniqlu ID specific to the department. |
ticketId | The ID of the ticket the agent currently has open. |
locale | en, es, or he. |
userName | The user name of the logged-in agent. |
type | Where the widget is displayed: TicketDetailsPanel or ChatWidgetWelcomeScreen. See Widget Types. |
token | JWT token (HMAC SHA-512) signed with your app secret. The token contains the applicationId, departmentId, and ticketId as claims. Use it to verify the request is legitimate. |
Example
Here's an example of an iframe source with all the parameters:
https://www.example.com/your-iframe.html?applicationId=a5db986f-dad8-4170-b7e4-3c453a50c887&departmentId=eea74d6e-da20-4d0c-a9ce-ed164e31b5d1&locale=en&ticketId=733393&token=eyJhbGciOiJodHRwOi8vd3d3LnczLm9yZy8y&type=TicketDetailsPanel&[email protected]
Verify the Token
Anyone can put together a URL with the right query string. Treat the raw parameters as untrusted, and verify the signed token on your backend before you act on any of them. The signing key is the Secret shown in your widget's settings in Glassix.
// On YOUR backend. Never trust the raw query params alone.
const jwt = require("jsonwebtoken");
function verifyGlassixToken(token) {
// Secret = the widget Secret shown in the Glassix widget settings.
const payload = jwt.verify(token, process.env.GLASSIX_WIDGET_SECRET, {
algorithms: ["HS512"],
});
// Trust these (signed) claims, not the URL query string:
return {
applicationId: payload.applicationId,
departmentId: payload.departmentId,
ticketId: payload.ticketId,
};
}
Note:Keep your Secret on your server. Don't ship it in client-side JavaScript, where anyone loading your page can read it.
Receive Ticket Data
Add the following script to your HTML document body. Any time an agent switches between tickets, the ticket's details are automatically sent to you. This means you don't need to send a GET ticket request every time the agent switches tickets.
Note:You must also add the
embedded-app-iframe.jsscript to your HTML for this to work. See Styling and Auto-Height.
<script>
window.onTicketLoaded = function (ticket) {
}
</script>The Ticket Object
onTicketLoaded receives the ticket in this shape:
// ticket passed to window.onTicketLoaded(ticket)
{
"id": 733393,
"departmentId": "eea74d6e-...",
"field1": "...", "field2": "...", // ... through field10 (custom fields)
"culture": "en-US",
"ticketType": 0,
"tags": ["vip"],
"owner": { },
"state": "Open",
"open": "2026-06-30T10:00:00Z", // opened-on timestamp (string)
"lastActivity": "2026-06-30T10:05:00Z",
"uniqueArgument": "...",
"primaryProtocolType": "Mail", // channel, e.g. Mail / WhatsApp / SMS
"details": { },
"participants": [
{
"id": "...",
"name": "...",
"displayName": "...",
"protocolType": "Mail",
"subProtocolType": "...",
"identifier": "[email protected]", // <-- customer email / phone / channel id
"type": 1,
"userName": "...",
"contactId": "..."
}
],
"transactions": null // not included in onTicketLoaded
}Two things to watch for:
- There's no dedicated email field. The customer's email address or phone number is in
participant.identifier, and which one it is depends on the channel. transactionsis alwaysnullhere. It's intentionally excluded fromonTicketLoaded. If you need the conversation's messages, fetch them with the API get ticket endpoint.
Styling and Auto-Height
Add the following script to your HTML document header. It handles the iframe styling and automatic height resizing based on your content.
<script src="https://cdn.glassix.com/clients/embedded-app-iframe.js"></script>The font family, font size, and more should match the styling of the agent's workspace, and this script takes care of that for you.
An iframe's height isn't dynamic according to its content, so without this script, the iframe stays at the fixed default height you set when you created the widget. embedded-app-iframe.js detects height changes and notifies the parent window. The panel still caps the rendered height.
The script calls this function when it has finished loading all the resources:
<script>
window.onDoneLoadingResources = function () {
}
</script>Requirements and Troubleshooting
- Your iframe must be served over HTTPS. Glassix runs on HTTPS, so mixed content is blocked.
- Do not set the X-Frame-Options header on your page. If you use a Content Security Policy, allow framing by Glassix with a
frame-ancestorsdirective. - Set the widget Height between 50 and 450 px. Values outside that range default to 200 px.
- Include
embedded-app-iframe.jsfor styling and automatic height resizing. Without it, the iframe stays at its fixed default height. - If your widget loads but doesn't respond when the agent switches tickets, check that
embedded-app-iframe.jsis present,onTicketLoadeddoesn't fire without it.
Full Example
This example shows the three things that matter: reading the parameters, implementing onTicketLoaded, and including the client script. Plug your own logic into onTicketLoaded.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script src="https://cdn.glassix.com/clients/embedded-app-iframe.js"></script>
</head>
<body>
<h3>Customer info</h3>
<div id="info">Loading ticket...</div>
<script>
// 1) Params Glassix adds to your URL (verify `token` on your server - see "Verify the token")
const params = new URLSearchParams(location.search);
// 2) Called every time the agent opens/switches a ticket
window.onTicketLoaded = function (ticket) {
const customer = (ticket.participants || [])[0] || {};
document.getElementById("info").innerText =
"Ticket #" + ticket.id + " - " + (customer.identifier || "unknown");
// -> here you would call YOUR system using customer.identifier
};
</script>
</body>
</html>Updated 9 days ago