Skip to main content

AI chat widget

Screenshot of the Squid AI chat widget

Why Use the AI Chat Widget

You want users to chat with an AI agent on your site. The agent should know about your business, follow your security model, look like your brand, and ideally support voice input, predefined prompts, and chain-of-thought visualization.

Building this from scratch means writing a chat UI, wiring up streaming, handling history, integrating auth, and styling. The Squid AI chat widget gives you all of that as a single web component:

Client code
<script async src="https://widget.squid.cloud/widget.umd.js"></script>

<squid-chat-widget-with-fab-button
squid-app-id="YOUR_APP_ID"
squid-region="us-east-1.aws"
squid-environment-id="prod"
squid-ai-agent-id="YOUR_AGENT_ID"
></squid-chat-widget-with-fab-button>

That's a full AI chat experience: input box, history, streaming responses, and a floating action button (FAB) to open and close it.

You can play with this widget right now via the FAB in the bottom-right corner of the page.

Overview

The Squid AI chat widget is a self-contained web component that talks to a Squid AI agent (or directly to a Squid database integration via Query with AI; see the example below). It is shipped as a single UMD bundle hosted at https://widget.squid.cloud/widget.umd.js and rendered into Shadow DOM, so it does not collide with your site's styles.

Two element variants

ElementBehavior
<squid-chat-widget>Inline chat block. Renders wherever you place it in the document. You control sizing and layout.
<squid-chat-widget-with-fab-button>Floating action button (FAB) in the bottom-right corner. Click to toggle the chat open or closed.

Both elements accept the same set of attributes.

When to use the chat widget

Use CaseRecommendation
Add an AI assistant to a marketing site or web appThe chat widget
Build a fully custom chat UIUse the AI agent SDK directly
Embed a chat that asks questions about a specific databaseThe chat widget with squid-ai-query="true" and squid-ai-integration-id
Run programmatic AI calls without a UIsquid.ai().agent() or executeAiQuery

Quick Start

Prerequisites

  • A Squid application created in the Squid Console
  • An AI agent created in the Agent Studio tab of your application
  • The agent's ID, your Squid app ID, and the region (all available in Backend Project under Show env vars in the Squid Console)

Step 1: Create an AI agent

  1. In the Squid Console, open your application and click the Agent Studio tab
  2. Click Create New Agent
  3. Provide an Agent ID (this cannot be changed later) and a description
  4. Click Create

After the agent is created, add Instructions (rules for how the agent responds) and Knowledge base items (background context). You can test the agent right away with the Test chat button.

note

Squid provides separate dev and prod environments. AI agents are not shared between them. Make sure the squid-environment-id attribute on the widget matches the environment your agent was created in. See environments.

Step 2: Load the widget script

Add the widget script tag to the <head> or <body> of your HTML:

Client code
<script async src="https://widget.squid.cloud/widget.umd.js"></script>

Step 3: Render the widget

Client code
<squid-chat-widget-with-fab-button
squid-app-id="YOUR_APP_ID"
squid-region="us-east-1.aws"
squid-environment-id="prod"
squid-ai-agent-id="YOUR_AGENT_ID"
header-title="Acme Assistant"
intro-text="Hi! Ask me anything about Acme."
></squid-chat-widget-with-fab-button>

Replace YOUR_APP_ID, us-east-1.aws, and YOUR_AGENT_ID with your application's values.

Authentication and Configuration

Public vs private agents

An agent can be set to public or private in the Agent Studio (Agent Settings, scroll to Public agent).

  • Public agents can be accessed by anyone. The widget needs no auth credentials.
  • Private agents require an auth provider so Squid can verify the caller.

Securing a private agent

  1. Connect an auth provider to Squid
  2. Pass the integrationId of the auth provider and the user's auth token via the squid-auth-provider attribute:
Client code
<squid-chat-widget
squid-app-id="YOUR_APP_ID"
squid-region="us-east-1.aws"
squid-environment-id="prod"
squid-ai-agent-id="YOUR_AGENT_ID"
squid-auth-provider='{"integrationId": "AUTH_INTEGRATION_ID", "token": "AUTH_TOKEN"}'
></squid-chat-widget>
  1. Add a @secureAiAgent rule on the backend to control who can chat:
Backend code
@secureAiAgent('chat')
allowAccessToAgent(): boolean {
return this.isAuthenticated();
}
note

A public agent bypasses @secureAiAgent rules entirely. Auth credentials are still made available to AI functions, so you can still gate specific function calls inside a public agent. See AI functions.

See more

For conditional checks, agent-scoped rules, and Agent API Keys, see Securing AI agents and Agent API Keys.

For more details on the authentication flow, see authentication.

Enabling custom HTML elements in your framework

Some frontend frameworks need extra setup to allow custom HTML elements.

React (src/declarations.d.ts):

Client code
declare namespace JSX {
interface IntrinsicElements {
'squid-chat-widget': any;
'squid-chat-widget-with-fab-button': any;
}
}

Angular (src/app/app.module.ts):

Client code
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';

@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}

For other frameworks, see your framework's documentation on enabling custom elements.

Core Concepts

Connection attributes

These attributes tell the widget how to reach Squid and which agent or integration to talk to.

AttributeTypeRequiredDescription
squid-app-idstringYes (unless using squid-ai-custom-api-url)Your Squid application ID
squid-regionstringYes (unless using squid-ai-custom-api-url)AWS region for your application (e.g. us-east-1.aws)
squid-environment-idstringNo (defaults to prod)dev or prod. Must match the environment the agent lives in.
squid-developer-idstringNoDeveloper ID. Required only when running the backend locally.
squid-api-keystringNoSquid API key. Use only on trusted surfaces, never in user-facing pages.
squid-ai-agent-idstringYes (unless squid-ai-query="true" or using squid-ai-custom-api-url)The agent ID to chat with
squid-ai-profile-idstringNo (deprecated)Old name for squid-ai-agent-id. Logs a deprecation warning. Use squid-ai-agent-id instead.
squid-ai-integration-idstringYes when squid-ai-query="true"The database integration ID to query when running in Query with AI mode
squid-ai-querybooleanNoWhen true, the widget runs against a database integration via Query with AI instead of an agent
squid-auth-providerJSONNo{ "integrationId": "...", "token": "..." }. Required for private agents.
squid-ai-custom-api-urlstringNoA custom HTTP endpoint that handles chat requests instead of going through Squid
squid-ai-custom-api-headersJSONNoExtra headers sent with custom API URL requests

Chat behavior attributes

AttributeTypeDescription
squid-ai-functionsstringComma-separated list of AI function names to enable
squid-ai-functions-jsonJSONArray of function objects with optional name, context, and predefinedParameters
squid-ai-temperaturenumberTemperature in [0, 1]. Lower is more deterministic.
squid-ai-max-tokensnumberMaximum number of tokens for the LLM response
squid-ai-override-modelstringOverride the model the agent uses (e.g. gpt-4o)
squid-ai-context-metadata-filterJSONMetadata filter applied to knowledge base lookups. See filtering context.
squid-ai-instructionsstringInstructions appended to the agent's system prompt for this widget instance
squid-ai-connected-agentsJSONArray of { agentId, description } for connected agents the agent can delegate to
squid-ai-agent-chat-optionsJSONAdvanced chat options object. See Advanced chat options below.
squid-ai-enable-raw-resultsbooleanWhen using squid-ai-query="true", request raw query result files
squid-ai-enable-code-interpreterbooleanWhen using squid-ai-query="true", enable the Python code interpreter for charts and analysis
disable-historybooleanDisable conversation memory across messages
chain-of-thoughtbooleanShow the agent's reasoning steps (tool calls, queries, function executions)
show-status-tagsbooleanShow tag labels on chain-of-thought status updates
observe-statusbooleanObserve live status updates from the backend
include-referencebooleanShow source references (citations) in agent responses
enable-transcriptionbooleanShow a microphone button so users can speak their prompts
predefined-promptsstringSuggested prompts shown to the user. Comma- or newline-separated, or a JSON-stringified array.
enable-debug-logsbooleanPrint debug logs to the browser console

Display and customization attributes

AttributeTypeDescription
header-titlestringTitle text in the chat header. Defaults to SquidAI Chat.
intro-textstringFirst message shown to the user when the chat opens
avatar-image-urlstringURL of the avatar image shown next to AI messages
chat-icon-urlstringCustom icon for the floating action button
widget-widthstringCSS width value (e.g. 400px)
widget-heightstringCSS height value (e.g. 600px)
themestringlight or dark. Defaults to light.
rtl-modebooleanEnable right-to-left layout for languages like Arabic and Hebrew
use-maximize-buttonbooleanShow a maximize/minimize button. Only meaningful in FAB mode.
open-on-loadbooleanAuto-open the FAB widget when the page loads
powered-by-textstringOverride the "Powered by Squid" footer text
menu-items-jsonJSONArray of { title, slotName } objects defining custom menu items. See Custom menu items.
base-stylesheet-urlstringOverride the base CSS file. Defaults to https://widget.squid.cloud/style.css.
stylesheet-urlstringAdditional CSS file loaded on top of the base stylesheet
error-formatterstring or function'generic-error', 'original-error' (default), or a JS function (error) => string

Localization attributes

The widget exposes a set of attributes for replacing built-in UI strings:

AttributeDefault
text-placeholder"Type here and press enter..."
text-thinking"Thinking..."
text-thought-for"Thought for"
text-suggested-prompts"Suggested Prompts"
text-suggested-prompts-description"Explore what this agent can do with a few examples."
text-milliseconds"milliseconds"
text-seconds"seconds"
text-minutes"minutes"

Advanced chat options

squid-ai-agent-chat-options accepts a JSON object that maps to the agent chat options interface. Common fields:

FieldDescription
agentContextAn object passed to every AI function call. See passing context to AI functions.
instructionsA string appended to the agent's system instructions for this widget instance
contextMetadataFilterForKnowledgeBaseAn object that restricts which knowledge base entries are used. See filtering context.
functionsAn array of function descriptors with optional predefinedParameters and per-function context
memoryOptionsConversation memory configuration: memoryId, memoryMode
temperatureSampling temperature
modelOverride the model used by this widget instance

Example:

Client code
<squid-chat-widget
squid-app-id="YOUR_APP_ID"
squid-region="us-east-1.aws"
squid-ai-agent-id="YOUR_AGENT_ID"
squid-ai-agent-chat-options='{
"agentContext": { "tenantId": "acme" },
"instructions": "Always reply in Spanish.",
"contextMetadataFilterForKnowledgeBase": {
"product-docs": { "version": "v2" }
},
"memoryOptions": { "memoryMode": "read-write", "memoryId": "session-123" }
}'
></squid-chat-widget>

Custom menu items

menu-items-json defines extra entries in the chat header menu. Each entry has a title and a slotName. Provide content for each slot using the standard slot= attribute on a child element.

Client code
<squid-chat-widget
squid-app-id="YOUR_APP_ID"
squid-region="us-east-1.aws"
squid-ai-agent-id="YOUR_AGENT_ID"
menu-items-json='[
{ "title": "Documentation", "slotName": "docs" },
{ "title": "Contact us", "slotName": "contact" }
]'
>
<div slot="docs">
<h3>Documentation</h3>
<p>Read our docs at <a href="https://docs.example.com">docs.example.com</a>.</p>
</div>
<div slot="contact">
<h3>Contact us</h3>
<p>Email <a href="mailto:hello@example.com">hello@example.com</a></p>
</div>
</squid-chat-widget>

CSS variables

The widget renders inside Shadow DOM. Override its appearance by setting CSS custom properties on the host element. Each variable falls back to the widget's default theme.

VariableControls
--squid-widget-header-background-colorHeader background
--squid-widget-header-title-colorHeader title text color
--squid-widget-header-menu-button-background-colorMenu button background
--squid-widget-header-menu-button-icon-urlMenu button icon image URL
--squid-widget-header-menu-item-colorMenu item text color
--squid-widget-header-menu-item-hover-background-colorMenu item hover background
--squid-widget-menu-item-back-icon-urlBack button icon for sub-menus
--squid-widget-body-background-colorChat body background
--squid-widget-ai-message-background-colorAI message bubble background
--squid-widget-ai-message-text-colorAI message text color
--squid-widget-user-message-background-colorUser message bubble background
--squid-widget-user-message-colorUser message text color
--squid-widget-textarea-background-colorInput textarea background
--squid-widget-textarea-border-colorInput textarea border
--squid-widget-textarea-text-colorInput textarea text color
--squid-widget-textarea-submit-image-urlSubmit button icon image URL
--squid-widget-inline-code-background-colorInline code block background
--squid-widget-inline-code-border-colorInline code block border
--squid-widget-link-colorHyperlink color
--squid-widget-powered-by-color"Powered by" footer text color
--squid-widget-fab-background-colorFAB button background
--squid-widget-fab-image-urlFAB button icon (closed state)
--squid-widget-fab-close-image-urlFAB button icon (open state)

Example using inline style:

Client code
<squid-chat-widget
squid-app-id="YOUR_APP_ID"
squid-region="us-east-1.aws"
squid-ai-agent-id="YOUR_AGENT_ID"
style="
--squid-widget-header-background-color: #1a73e8;
--squid-widget-ai-message-background-color: #e8f0fe;
--squid-widget-user-message-background-color: #1a73e8;
--squid-widget-user-message-color: #ffffff;
"
></squid-chat-widget>

You can also use the class attribute to apply your own external stylesheet rules.

Listening for events

The widget dispatches a change CustomEvent whenever the chat history or status updates change. Two payload shapes are supported:

Client code
const widget = document.querySelector('squid-chat-widget')!;

widget.addEventListener('change', (event: CustomEvent) => {
if (event.detail.type === 'history') {
// event.detail.history is an array of ChatMessage objects
console.log('History updated:', event.detail.history);
} else if (event.detail.type === 'status') {
// event.detail.status is an array of AiStatusMessage objects
console.log('Status updated:', event.detail.status);
}
});

In React, pass an onChange callback prop instead:

Client code
<SquidChatWidgetWithFabButtonEntryPoint
squidAppId="YOUR_APP_ID"
squidRegion="us-east-1.aws"
squidAiAgentId="YOUR_AGENT_ID"
onChange={(event) => {
console.log(event.detail);
}}
/>

Code Examples

Override parameters on an AI function

When you want certain parameters fixed and not chosen by the AI, use predefinedParameters via squid-ai-functions-json. See overriding parameter values for the matching backend pattern.

Client code
<squid-chat-widget
squid-app-id="YOUR_APP_ID"
squid-region="us-east-1.aws"
squid-ai-agent-id="YOUR_AGENT_ID"
squid-ai-functions-json='[
{ "name": "saveSection", "predefinedParameters": { "sectionId": "introduction" } }
]'
></squid-chat-widget>

Pass agent context to backend functions

Use the agentContext field of squid-ai-agent-chat-options to attach values that every AI function call can read on the backend. The companion backend pattern is documented in passing context to AI functions.

Client code
<squid-chat-widget
squid-app-id="YOUR_APP_ID"
squid-region="us-east-1.aws"
squid-ai-agent-id="YOUR_AGENT_ID"
squid-ai-agent-chat-options='{
"agentContext": { "documentId": "doc-42" },
"functions": [
{ "name": "saveSection", "context": { "codenameList": ["LITANIA", "LEOPARD"] } }
]
}'
></squid-chat-widget>

Chat against a database with Query with AI

Set squid-ai-query="true" and provide a database integration ID instead of an agent ID. See Query with AI for the underlying feature.

Client code
<squid-chat-widget
squid-app-id="YOUR_APP_ID"
squid-region="us-east-1.aws"
squid-ai-query="true"
squid-ai-integration-id="postgres"
squid-ai-enable-code-interpreter="true"
predefined-prompts='[
"How many users signed up last week?",
"Show me a chart of orders per region.",
"Which products had no sales this month?"
]'
></squid-chat-widget>

Custom backend webhook

Route the chat through your own backend with squid-ai-custom-api-url. The widget posts the prompt to that URL; you handle the response.

Client code
<squid-chat-widget
squid-ai-custom-api-url="https://YOUR_APP-prod.us-east-1.aws.squid.cloud/webhooks/chat?projectId=YOUR_PROJECT_ID"
></squid-chat-widget>
Backend code
import { webhook, SquidService, WebhookRequest } from '@squidcloud/backend';

interface ChatRequest {
prompt: string;
}

interface ChatResponse {
response: string;
}

export class ChatService extends SquidService {
@webhook('chat')
async chat(request: WebhookRequest<ChatRequest>): Promise<ChatResponse> {
const userPrompt = request.body.prompt;
const projectId = request.queryParams['projectId'];

// Custom logic to handle the user prompt and project ID.
return { response: `Echo: ${userPrompt}` };
}
}

Programmatic creation in JavaScript

Client code
const widget = document.createElement('squid-chat-widget');
widget.setAttribute('squid-app-id', 'YOUR_APP_ID');
widget.setAttribute('squid-region', 'us-east-1.aws');
widget.setAttribute('squid-ai-agent-id', 'YOUR_AGENT_ID');
widget.setAttribute('header-title', 'Acme Assistant');
widget.setAttribute('squid-ai-agent-chat-options', JSON.stringify({ memoryOptions: { memoryMode: 'read-write', memoryId: 'session-1' } }));

// Function-typed props are set as DOM properties, not attributes.
(widget as any)['error-formatter'] = (error: unknown) => `Something went wrong: ${error}`;

document.body.appendChild(widget);

Error Handling

Common errors

ErrorCauseSolution
squid-app-id must be specifiedMissing squid-app-id attributeAdd squid-app-id (or use squid-ai-custom-api-url)
squid-region must be specifiedMissing squid-region attributeAdd squid-region
squid-ai-agent-id must be specified or squid-ai-query must be trueNo agent ID and not running in query modeAdd squid-ai-agent-id, or set squid-ai-query="true" plus squid-ai-integration-id
squid-ai-integration-id must be specified when using squid-ai-querysquid-ai-query="true" without an integration IDAdd squid-ai-integration-id
squid-ai-profile-id is deprecated, use squid-ai-agent-id insteadUsing the legacy attribute nameRename to squid-ai-agent-id
UNAUTHORIZED from the backendPrivate agent, no auth provider, or @secureAiAgent deniedSet squid-auth-provider and verify the @secureAiAgent rule
Custom HTML element not recognizedFramework needs custom element registrationSee Enabling custom HTML elements in your framework

Use enable-debug-logs="true" to print extra information to the browser console while diagnosing issues.

Customize error display

Use error-formatter to control how errors are shown to the user. The built-in values are 'generic-error' (a single shared message) and 'original-error' (the actual error message, default). You can also pass a function:

Client code
const widget = document.querySelector('squid-chat-widget')!;
(widget as any)['error-formatter'] = (error: unknown) => {
if (error instanceof Error) return error.message;
return 'Something went wrong. Please try again.';
};

Best Practices

  1. Keep squid-app-id and squid-region in HTML, never API keys. The chat widget runs in the browser. Anything you put in squid-api-key is visible to anyone viewing the page. For private agents, use squid-auth-provider and @secureAiAgent instead.
  2. Use squid-ai-agent-id, not squid-ai-profile-id. The latter is deprecated and logs a warning.
  3. Match squid-environment-id to the agent's environment. Agents created in dev are not visible in prod and vice versa.
  4. Apply security rules on the backend even when the agent is public. Public agents skip @secureAiAgent, but @secureAiQuery and AI function auth checks still run.
  5. Set chain-of-thought="true" during development to see exactly what the agent is doing. Turn it off (or leave it on with show-status-tags="false") for end users.
  6. Cache CSS overrides in your own stylesheet rather than inlining them with style=, so multiple widget instances stay in sync.
  7. Listen to change events if you want to persist conversation history outside the widget or feed it into product analytics.

See Also