> ## Documentation Index
> Fetch the complete documentation index at: https://ago.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Widget Metadata Communication

> Bidirectional communication between parent page and chat widget

The widget supports bidirectional communication between the parent page and the embedded chat iframe using the `postMessage` API. This enables rich integrations where the parent application can send context to the widget and receive events back.

## Overview

| Direction           | Use Case                                                        |
| ------------------- | --------------------------------------------------------------- |
| **Parent → Widget** | Send user context, session data, custom metadata                |
| **Widget → Parent** | Receive events like close requests, navigation, ticket creation |

## Features

* **Metadata Injection**: Parent page can send arbitrary metadata to the widget
* **Event Notification**: Widget notifies parent of user actions and state changes
* **Mobile State Detection**: Automatic detection and handling of mobile/desktop states
* **Widget Mode Detection**: Automatic detection when running in iframe vs standalone mode
* **Secure Communication**: Origin validation for all messages

***

## Parent to Widget Communication

### Window Configuration

When embedding the widget, configure it through the `window.AGO` object before loading the widget script. These options control authentication, appearance, and behavior.

```html theme={null}
<script>
    window.AGO = {
        basepath: "https://YOUR-DOMAIN.useago.com/",
        title: "Support Chat",
        prompt: "Hello, how can I help you?",
        colors: { button: "#0069ED" },
        icon: "https://example.com/chat-icon.png",
        jwt: "eyJhbGciOiJFUzI1NiIs...",
        authToken: "external-api-token",
        email: "user@example.com",
        permission: "premium-support",
        notifications: true,
        notificationMessage: "You have {{count}} unread messages",
        hideFooter: true
    };
</script>
<script async src="https://useago.github.io/widgetjs/frame.js"></script>
```

| Option                | Type    | Description                                                                                        |
| --------------------- | ------- | -------------------------------------------------------------------------------------------------- |
| `basepath`            | string  | Base URL of your AGO instance (required)                                                           |
| `title`               | string  | Title displayed in the chat header                                                                 |
| `prompt`              | string  | Welcome message shown to users                                                                     |
| `colors`              | object  | Color customization (e.g. `{ button: "#0069ED" }`)                                                 |
| `icon`                | string  | URL to a custom icon for the chat button                                                           |
| `jwt`                 | string  | JWT token for authenticated users (see [Widget Authentication](../security/widget-authentication)) |
| `authToken`           | string  | External auth token forwarded to agent tools via `X-Auth-Token` header                             |
| `email`               | string  | User email for identification                                                                      |
| `permission`          | string  | Permission name to override the default permission                                                 |
| `notifications`       | boolean | Enable unread message notifications (displays a red badge)                                         |
| `notificationMessage` | string  | Custom notification text (`{{count}}` is replaced with the unread count)                           |
| `hideFooter`          | boolean | Hide the "Powered by AGO" footer                                                                   |

### Updating JWT at Runtime

Use `sendJwtToAGO()` to update the JWT token after the widget has loaded. This is useful when the user logs in after the widget is already open, or when the JWT token is refreshed.

```javascript theme={null}
// Update JWT after user login or token refresh
sendJwtToAGO("eyJhbGciOiJFUzI1NiIs...");
```

This updates the JWT in both the chat iframe and the notification iframe, so unread counts are fetched with the correct identity.

### Updating Auth Token at Runtime

Use `sendAuthTokenToAGO()` to pass an external authentication token to the widget. This token is forwarded to agent tools (e.g., HTTP request tool) as the `X-Auth-Token` header, allowing agents to call your authenticated APIs on behalf of the user.

```javascript theme={null}
// Pass an external API token to agent tools
sendAuthTokenToAGO("your-external-api-token");
```

### Sending Metadata

Use the `sendMetadataToAGO` function to pass context from your application to the widget.

```javascript theme={null}
// Basic metadata
sendMetadataToAGO({
    userId: 'user-123',
    userEmail: 'user@example.com'
});

// Rich context with custom data
sendMetadataToAGO({
    userId: 'user-123',
    userEmail: 'user@example.com',
    userName: 'John Doe',
    orderId: 'order-456',
    plan: 'premium',
    customData: {
        lastPurchase: '2024-01-15',
        accountAge: 365,
        preferences: {
            language: 'en',
            timezone: 'America/New_York'
        }
    }
});
```

### Metadata Fields Reference

| Field      | Type   | Description                                       |
| ---------- | ------ | ------------------------------------------------- |
| userId     | string | Unique user identifier in your system             |
| userEmail  | string | User's email address                              |
| userName   | string | User's display name                               |
| orderId    | string | Current order/transaction ID                      |
| plan       | string | User's subscription plan                          |
| customData | object | Any additional context (nested objects supported) |

### Usage in React Native WebView

```javascript theme={null}
// In React Native, inject JavaScript to set metadata
webViewRef.current.injectJavaScript(`
  sendMetadataToAGO({
    userId: '${userId}',
    userEmail: '${userEmail}',
    sessionData: ${JSON.stringify(sessionData)}
  });
  true; // Required for iOS
`);
```

***

## Widget to Parent Communication

### Setting Up the Event Listener

The parent page should listen for messages from the widget:

```javascript theme={null}
window.addEventListener('message', (event) => {
    // Validate origin for security
    if (event.origin !== 'https://your-ago-domain.com') {
        return;
    }

    // Handle different message types
    switch (event.data.type) {
        case 'CLOSE_CHAT':
            handleCloseChat();
            break;
        case 'THREAD_CREATED':
            handleThreadCreated(event.data.data);
            break;
        case 'TICKET_CREATED':
            handleTicketCreated(event.data.data);
            break;
        case 'NAVIGATE':
            handleNavigation(event.data.data);
            break;
        case 'UNREAD_STAFF_COUNT':
            handleUnreadCount(event.data.count);
            break;
    }
});
```

### Built-in Message Types

#### CLOSE\_CHAT

Sent when the user clicks the close button or requests to minimize the widget.

```javascript theme={null}
{
    type: 'CLOSE_CHAT'
}
```

**Use Case**: Hide the widget container or minimize to a button.

```javascript theme={null}
function handleCloseChat() {
    document.getElementById('widget-container').style.display = 'none';
    document.getElementById('chat-button').style.display = 'block';
}
```

#### THREAD\_CREATED

Sent when a new conversation thread is started.

```javascript theme={null}
{
    type: 'THREAD_CREATED',
    data: {
        threadId: 'thread-uuid',
        agentId: 'agent-uuid',
        agentName: 'Support Agent'
    }
}
```

**Use Case**: Track conversation starts in your analytics.

```javascript theme={null}
function handleThreadCreated(data) {
    analytics.track('Chat Started', {
        threadId: data.threadId,
        agent: data.agentName
    });
}
```

#### TICKET\_CREATED

Sent when a support ticket is created from the conversation.

```javascript theme={null}
{
    type: 'TICKET_CREATED',
    data: {
        ticketId: 'ticket-123',
        threadId: 'thread-uuid',
        externalId: 'helpscout-ticket-id'
    }
}
```

**Use Case**: Show confirmation or update your ticket tracking.

```javascript theme={null}
function handleTicketCreated(data) {
    showNotification(`Ticket #${data.ticketId} created`);
    updateTicketList(data.ticketId);
}
```

#### NAVIGATE

Sent when the widget requests navigation to a specific page.

```javascript theme={null}
{
    type: 'NAVIGATE',
    data: {
        url: '/account/settings',
        target: '_self'
    }
}
```

**Use Case**: Handle in-app navigation from agent responses.

```javascript theme={null}
function handleNavigation(data) {
    if (data.target === '_blank') {
        window.open(data.url, '_blank');
    } else {
        router.push(data.url);
    }
}
```

#### UNREAD\_STAFF\_COUNT

Sent periodically (every 30 seconds) by the notification frame to inform the parent page of unread staff messages. The notification frame is a hidden iframe that polls for unread messages. It only reports counts for users who have an existing widget session (i.e., a widget ID in localStorage from a previous chat interaction) — new visitors with no prior conversations will not trigger any polls.

**Enabling notifications**: Set `notifications: true` in the `window.AGO` configuration object:

```html theme={null}
<script>
    window.AGO = {
        basepath: "https://YOUR-DOMAIN.useago.com/",
        notifications: true
    };
</script>
<script async src="https://useago.github.io/widgetjs/frame.js"></script>
```

When enabled, the standard widget automatically displays a red badge on the chat button. If you build a custom integration, listen for the event yourself:

```javascript theme={null}
{
    type: 'UNREAD_STAFF_COUNT',
    count: 3
}
```

**Use Case**: Display an unread message badge on your chat button.

```javascript theme={null}
function handleUnreadCount(count) {
    const badge = document.getElementById('chat-badge');
    if (count > 0) {
        badge.textContent = count;
        badge.style.display = 'block';
    } else {
        badge.style.display = 'none';
    }
}
```

**JWT authentication**: If your widget uses JWT authentication, call `sendJwtToAGO(token)` whenever the token is refreshed. This updates both the chat iframe and the notification frame so that unread counts are fetched with the correct identity.

***

## Complete Integration Examples

### Basic Web Integration

```html theme={null}
<!DOCTYPE html>
<html>
<head>
    <title>My App with AGO Widget</title>
</head>
<body>
<h1>My Application</h1>

<div id="chat-button" onclick="openWidget()">Chat with us</div>
<div id="widget-container" style="display: none;">
    <!-- Widget will be injected here -->
</div>

<script src="https://useago.github.io/widgetjs/frame.js"></script>
<script>
    // Configure widget
    window.AGO = {
        basepath: 'https://your-ago-domain.com/',
        email: 'user@example.com'
    };

    // Set up event listener
    window.addEventListener('message', (event) => {
        if (event.data.type === 'CLOSE_CHAT') {
            closeWidget();
        }
        if (event.data.type === 'TICKET_CREATED') {
            console.log('Ticket created:', event.data.data.ticketId);
        }
    });

    function openWidget() {
        document.getElementById('widget-container').style.display = 'block';
        document.getElementById('chat-button').style.display = 'none';

        // Send current context
        sendMetadataToAGO({
            userId: getCurrentUserId(),
            currentPage: window.location.pathname,
            cartItems: getCartItems()
        });
    }

    function closeWidget() {
        document.getElementById('widget-container').style.display = 'none';
        document.getElementById('chat-button').style.display = 'block';
    }
</script>
</body>
</html>
```

### React Integration

```jsx theme={null}
import { useEffect, useCallback } from 'react';

function ChatWidget({ user, isOpen, onClose }) {
    const handleMessage = useCallback((event) => {
        // Validate origin
        if (event.origin !== process.env.REACT_APP_AGO_DOMAIN) return;

        switch (event.data.type) {
            case 'CLOSE_CHAT':
                onClose();
                break;
            case 'TICKET_CREATED':
                toast.success(`Ticket ${event.data.data.ticketId} created`);
                break;
            case 'NAVIGATE':
                navigate(event.data.data.url);
                break;
        }
    }, [onClose]);

    useEffect(() => {
        window.addEventListener('message', handleMessage);
        return () => window.removeEventListener('message', handleMessage);
    }, [handleMessage]);

    useEffect(() => {
        if (isOpen && user) {
            window.sendMetadataToAGO({
                userId: user.id,
                userEmail: user.email,
                userName: user.name,
                plan: user.subscription?.plan
            });
        }
    }, [isOpen, user]);

    if (!isOpen) return null;

    return (
        <div className="widget-container">
            <iframe
                id="ago-widget-iframe"
                src={`${process.env.REACT_APP_AGO_DOMAIN}/widget`}
                title="Chat Widget"
            />
        </div>
    );
}
```

***

## Ticket Integration

When tickets are created from conversations, metadata is automatically included and formatted for support agents.

### HelpScout Integration

Metadata appears as formatted JSON in private comments:

```
You can find the full conversation here: https://app.com/chat/thread-123

Metadata:
{
  "userId": "user-123",
  "orderId": "order-456",
  "sessionId": "session-789",
  "customData": {
    "plan": "premium",
    "region": "us-east"
  }
}
```

### Zendesk Integration

Metadata is added to custom ticket fields and internal notes, providing support agents with comprehensive context.

***

## Security Considerations

### Origin Validation

Always validate the message origin:

```javascript theme={null}
window.addEventListener('message', (event) => {
    const allowedOrigins = [
        'https://your-ago-domain.com',
        'https://widget.useago.com'
    ];

    if (!allowedOrigins.includes(event.origin)) {
        console.warn('Message from unauthorized origin:', event.origin);
        return;
    }

    // Process message...
});
```

### Sensitive Data

* **Do not send**: Passwords, API keys, tokens, credit card numbers
* **Safe to send**: User IDs, order IDs, plan names, page context, preferences

### Content Security Policy

If using CSP, ensure your policy allows communication with the widget:

```html theme={null}
<meta http-equiv="Content-Security-Policy"
      content="frame-src https://your-ago-domain.com;
               script-src 'self' https://useago.github.io;">
```

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="Widget Not Receiving Metadata">
    1. Ensure the widget script has finished loading before calling `sendMetadataToAGO`
    2. Check browser console for errors
    3. Verify `sendMetadataToAGO` is available globally (it is defined by `frame.js`)
  </Accordion>

  <Accordion title="Messages Not Being Received">
    1. Check origin validation in your event listener
    2. Ensure widget domain is correct
    3. Check browser console for blocked cross-origin messages
  </Accordion>

  <Accordion title="Metadata Not Appearing in Tickets">
    1. Verify metadata was sent before ticket creation
    2. Check that metadata format is valid JSON
    3. Ensure ticketing integration is properly configured

    ***
  </Accordion>
</AccordionGroup>

## Browser Compatibility

The `postMessage` API is supported in all modern browsers:

| Browser        | Minimum Version |
| -------------- | --------------- |
| Chrome         | 1+              |
| Firefox        | 3+              |
| Safari         | 4+              |
| Edge           | 12+             |
| iOS Safari     | 3.2+            |
| Android Chrome | 18+             |

No polyfills required.

***

## Related Documentation

* [Widget Authentication](../security/widget-authentication) - Configure widget security
* [Widget Configuration](../features/widget-configuration-admin) - Widget appearance and behavior
* [Ticketing Tool](../tools/ticketing-tool) - Ticket creation from conversations
* [Mobile Authentication](./mobile-auth) - Mobile SDK authentication
