Implementing LiveChat using Iframe
Simple Implementation
Hoory Live Chat can be embedded on any website with a single iframe. This is the easiest way to add Hoory to your website.
<iframe src="https://app.hoory.com/widget?website_token=YOUR_WEBSITE_TOKEN&showUnreadBubble=0">
<p>Your browser does not support iframes.</p>
</iframe>
When the widget runs inside an iframe, it waits for a config-set message from the parent page before it finishes initializing. Without it, the widget does not load previous conversations or available agents, does not apply your locale and appearance settings, and does not load the contact. It also does not keep the user's chat history between visits.
For a fully working setup, use the implementation with history below.
URL parameters
| Parameter | Description |
|---|---|
website_token | Required. The website token of your Live Chat channel. |
cw_conversation | The conversation token returned by the widget. Pass it to restore the user's chat history. |
showUnreadBubble | Set to 0 to disable the unread messages popup view inside the iframe. |
Implementation with History
To keep the user's chat history, store the conversation token the widget returns when it loads, and pass it back in the iframe URL on the next visit.
<script>
/**
* Set cookie value by name (you can use your own pkg for this)
* @param cname
* @param cvalue
* @param exdays
*/
function setCookie(cname, cvalue, exdays) {
const d = new Date();
d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
let expires = "expires="+d.toUTCString();
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}
/**
* A simple function to get cookie value by name (you can use your own pkg for this)
* @param cname
* @returns {string}
*/
function getCookie(cname) {
let name = cname + '=';
let ca = document.cookie.split(';');
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) === ' ') {
c = c.substring(1);
}
if (c.indexOf(name) === 0) {
return c.substring(name.length, c.length);
}
}
return '';
}
/**
* Send a message to the iframe
*/
const loadEventPrefix = 'hoory-widget:';
function sendMessageToIframe(key, value) {
document
.getElementById('chat-iframe')
.contentWindow.postMessage(
`${loadEventPrefix}${JSON.stringify({ event: key, ...value })}`,
'*'
);
}
/**
* Initialize the iframe
*/
const token = 'YOUR_WEBSITE_TOKEN';
const iframe = document.createElement('iframe');
iframe.id = 'chat-iframe';
iframe.setAttribute(
'src',
`https://app.hoory.com/widget?website_token=${token}&cw_conversation=${getCookie(
'cw_conversation'
)}&showUnreadBubble=0`
);
iframe.style.width = '640px';
iframe.style.height = '100vh';
document.body.appendChild(iframe);
/**
* Listen to the load message from the iframe
*/
window.addEventListener('message', (msg) => {
if (typeof msg?.data !== 'string' || !msg.data.startsWith(loadEventPrefix)) {
return;
}
let data;
try {
data = JSON.parse(msg.data.replace(loadEventPrefix, ''));
} catch (e) {
return; // Ignore messages that are not valid JSON
}
if (data.event === 'loaded') {
// Conversation token used to restore the chat history on the next visit
const conversationToken = data.config.authToken;
setCookie('cw_conversation', conversationToken, 365);
sendMessageToIframe('config-set', {
locale: 'en', // Language to be set https://docs.hoory.com/product/channels/live-chat/sdk/setup#possible-language-values
darkMode: 'auto', // [light, auto, dark]
});
// The embedded widget is always visible, so mark it as open.
// This is required for read receipts and "last seen" updates.
sendMessageToIframe('toggle-open', { isOpen: true });
}
});
</script>
The loaded event contains:
config.authToken— the conversation token. Store it and pass it ascw_conversationto restore the chat history.config.channelConfig— the Live Chat channel configuration (widget color, avatar URL, etc.).
config-set options
Besides locale and darkMode, the config-set message accepts the following options:
| Option | Values | Description |
|---|---|---|
locale | See possible language values | Widget language. |
darkMode | light (default), auto, dark | Widget color scheme. auto follows the user's OS setting. |
widgetStyle | standard, flat | Widget design. See Widget Designs. |
showPopoutButton | true, false | Show the button that opens the chat in a new window. |
allowWidgetMaximize | enabled, disabled | Allow the user to maximize the widget. |
Sending Data to the Widget
After the widget has loaded, you can use the same sendMessageToIframe helper to send more data to it. These messages work like the matching SDK methods.
// Set the user
sendMessageToIframe('set-user', {
identifier: 'user-unique-id',
user: {
email: '[email protected]',
name: 'John Doe',
},
});
// Set or delete contact custom attributes
sendMessageToIframe('set-custom-attributes', {
customAttributes: { plan: 'premium' },
});
sendMessageToIframe('delete-custom-attribute', { customAttribute: 'plan' });
// Set or delete conversation custom attributes
sendMessageToIframe('set-conversation-custom-attributes', {
customAttributes: { orderId: '12345' },
});
sendMessageToIframe('delete-conversation-custom-attribute', {
customAttribute: 'orderId',
});
// Add or remove a conversation label
sendMessageToIframe('set-label', { label: 'support' });
sendMessageToIframe('remove-label', { label: 'support' });
// Change the widget language
sendMessageToIframe('set-locale', { locale: 'fr' });
Clearing the Chat History
To clear the user's chat history (for example, when they log out of your app), delete the stored conversation token and reload the iframe without it:
setCookie('cw_conversation', '', -1);
document.getElementById('chat-iframe').src =
`https://app.hoory.com/widget?website_token=${token}&showUnreadBubble=0`;
Not in a Web Environment?
If you want to embed Hoory outside a web environment, use a different storage mechanism to store the conversation token and pass it to the iframe URL as cw_conversation.
Instead of an iframe, you can use a webview, which is available on almost every platform, and apply the same approach. For React Native apps, see the React Native integration.