Display modes
One script, five ways to appear. The mode decides where the chat lives on the page and how visitors get to it:
| Mode | Looks like | Needs a container? |
|---|---|---|
| default | Inline embed inside your page | Yes |
| popup | Floating window with a toggle button | No |
| drawer | Panel sliding in from the side | No |
| full | Takes over the whole viewport | No |
| core | Stripped-down UI for embedding | Yes |
Default
What it does. Embeds the chat directly into a container on your page. The SDK mounts an iframe that fills the container's box, with a splash screen covering the load. There's no button and nothing hidden: the chat is part of the layout, always visible. Its size is entirely yours: the iframe fills 100% of the container's width and height, so you set the dimensions once on the container.
Where to use it.
- Dashboards and web apps where the chat is a permanent panel alongside your content
- Product pages where trying the chat is the point: a hero-section demo, a "talk to the assistant" block
- Help centers and docs sites that want a chat section rather than a floating widget
If your page is text-heavy and the chat is secondary, popup or drawer usually fits better.
<div id="chat-container" style="width: 100%; height: 600px;"></div>
const chat = new Chatoshi({
partnerKey: 'your-partner-key',
container: '#chat-container',
mode: 'default'
});
Style the container with containerStyle and containerClass:
containerStyle: {
borderRadius: '12px',
boxShadow: '0 4px 12px rgba(0,0,0,0.1)'
}
Popup
What it does. Adds a floating button pinned to a corner of the page, bottom-right by default. Clicking it opens a chat window anchored to that corner; clicking again dismisses it. The window defaults to 400×600 pixels, and the size, the corner, and the button itself are all configurable. You can also drive it from code with open(), close(), and toggle().
Where to use it.
- Marketing sites, blogs, and shops, where the chat should stay one click away without competing with the content
- Adding chat to an existing site without touching its layout: one snippet on every page
- Cases where visitors already expect a chat bubble in the corner
const chat = new Chatoshi({
partnerKey: 'your-partner-key',
mode: 'popup',
popupOptions: {
width: '400px',
height: '600px',
position: 'bottom-right'
}
});
position is one of bottom-right (default), bottom-left, top-right, top-left.
Use your own button instead of the built-in toggle:
popupOptions: {
customToggleButton: '#help-button'
}
Control it programmatically:
chat.open();
chat.close();
chat.toggle();
const popup = chat.getPopup();
if (popup && popup.isOpen()) {
console.log('Popup is open');
}
Drawer
What it does. A full-height panel that slides in from the left or right edge, over a dimmed overlay that keeps the page visible behind it. There's no built-in toggle button, so you open the drawer from your own UI with chat.open(). Visitors close it with the close button, a click on the overlay, or the Escape key, and the page behind doesn't scroll while it's open. Drawers are resizable by default: users drag the edge to adjust the width, and the width they choose is remembered for their next visit.
Where to use it.
- Mobile layouts: full height with no zooming, and on narrow screens you can make it span the whole width
- SaaS apps and member areas, where support chat sits beside the main interface instead of floating over it
- Long conversations, since a full-height thread gives messages room to breathe
const chat = new Chatoshi({
partnerKey: 'your-partner-key',
mode: 'drawer',
drawerOptions: {
width: '400px',
position: 'right'
}
});
position is 'right' (default) or 'left'. On mobile, a full-width drawer usually works best:
drawerOptions: {
width: window.innerWidth <= 768 ? '100%' : '400px',
position: 'right'
}
Resizing is on by default. Adjust the drag limits, or turn it off with resizable: false:
drawerOptions: {
width: '350px',
position: 'right',
resizeOptions: { minWidth: 300, maxWidth: 600 }
}
Programmatic control is the same as popup: chat.open(), chat.close(), chat.toggle(), chat.getDrawer().isOpen(). When the user finishes resizing, the SDK emits a drawer:resize event with the new width.
Full
What it does. The chat fills the entire browser window from the moment it initializes. No container, no button, nothing to click first. It's built for pages where the chat is the destination, not an add-on.
Where to use it.
- A dedicated
/chatroute, linked from your navigation as "Ask Chatoshi" - Webviews inside mobile apps, where the chat is the whole screen
- Kiosk and standalone-demo setups
const chat = new Chatoshi({
partnerKey: 'your-partner-key',
mode: 'full',
theme: 'dark'
});
Core
What it does. Core mode strips the chat down to the conversation itself. The header, sidebar, onboarding, logo, and limit banner are all gone. What remains is a plain chat surface you can build your own interface around. It exists for two jobs: making the chat look native inside your application shell, and white-label integrations.
Where to use it.
- Chat embedded inside your own app, wrapped in your header, navigation, and styling
- White-label products where the interface should carry your brand, not Chatoshi's chrome
- Fully custom UI wrappers, via direct iframe embedding and the postMessage protocol
What it removes:
| Removed or hidden | Notes |
|---|---|
| Header | No top navigation bar |
| Sidebar | Hidden; can be toggled via the layout:sidebar event |
| First-run content | No onboarding, logo, or suggested questions |
| Logo | Not displayed |
| Message limit banner | Suppressed |
Via the SDK
const chat = new Chatoshi({
partnerKey: 'your-partner-key',
mode: 'core',
container: '#chat-container'
});
You get the same SDK API as any other mode: on(), sendMessage(), newConversation(), and the rest.
Direct iframe embedding
For full control, skip the SDK and embed the chat app directly:
<iframe
id="chatoshi"
src="https://aichat.chatoshi.ai/?embed_mode=core&intent_id=widget-001"
style="width: 100%; height: 600px; border: none;"
></iframe>
Required URL parameters:
embed_mode=coreintent_id: a unique ID for this embed instance
Optional: partner_key, embed_mode_theme (light, dark, system), embed_mode_colors (JSON-encoded color scheme).
You then talk to the iframe via postMessage:
const iframe = document.getElementById('chatoshi');
iframe.contentWindow.postMessage({
source: 'chatoshi-sdk',
intentId: 'widget-001',
eventName: 'session:new',
data: { message: 'Hello!' }
}, '*');
And listen for events coming back:
window.addEventListener('message', (event) => {
if (event.data?.source !== 'aptachat') return;
if (event.data.eventName === 'app:ready') {
console.log('Chat is ready');
}
});
The full event protocol (inputs, outputs, payloads) is covered in Event handling.
Picking a mode
- default: the chat is part of the page layout
- popup: the chat is on demand; the page is the product
- drawer: mobile, or side-by-side with a main interface
- full: a dedicated chat page
- core: embedding into your own app shell with your own chrome
Choosing a mode at runtime
You can decide the mode when the page loads. Keep a single instance and destroy it before creating a new one:
let chat;
function initChat() {
chat?.destroy();
const isMobile = window.innerWidth <= 768;
chat = new Chatoshi({
partnerKey: 'your-partner-key',
mode: isMobile ? 'drawer' : 'default',
container: '#chat-container'
});
}
initChat();