Appearance
AI Chat Widget
The Bildhive AI Chat Widget allows you to embed an interactive AI sales and customer assistant on any website.
Bildhive provides three flexible approaches to integrate AI Chat:
- Method 1: Ready-Made Embed Code (Bildhive Admin): Use the visual customizer in the Bildhive Admin AI app to preview, brand, and generate a 1-click copy-paste code snippet.
- Method 2: Custom Element Embedding & HTML Attributes: Drop in the compiled Web Component (
<bildhive-chat-widget>) and customize appearance, copy, and behaviors directly via HTML attributes and JavaScript DOM properties. - Method 3: Building a Custom / Headless Widget with Bildhive APIs: Build your own bespoke chat UI from scratch by directly calling Bildhive's REST and streaming AI chat endpoints.
Technical Highlights
- Shadow DOM Encapsulation: Styles in
<bildhive-chat-widget>are fully insulated. The widget's CSS cannot leak out to affect your website, and your site's global styles cannot distort the widget's layout. - Zero Framework Lock-in: The host website does not need to use Vue or any specific JavaScript framework.
- Self-Contained Sizing: The web component manages its own
:hostdisplay dimensions dynamically (seamlessly transitioning between the floating launcher pill, circular trigger, lead registration form, active chat conversation, and full-screen maximize mode). No iframe resizer scripts or postMessage bridges are needed. - Real-Time Streaming: Leverages streaming AI responses for quick, interactive user feedback.
- Built-in Lead Capture & Anti-Spam: Includes lead registration, returning visitor detection via
localStorage, invisible honeypot spam protection, human submission speed validation, and phone number conflict resolution.
Prerequisites
To embed and use the AI Chat Widget or connect to the AI Chat APIs, you will need:
- Instance Token (
instance): Your unique Bildhive project instance token. - AI Agent ID (
agent-id): The identifier of the configured AI assistant agent from your Bildhive AI application. - API Add-on Enabled: The Bildhive project must have the API Add-on enabled on its subscription plan.
API Add-on Required: To enable the API add-on, navigate to your Bildhive project settings under Settings > Projects > Edit > Add-ons (or contact your project billing owner). If the API add-on is inactive, API requests will return an authorization error.
Method 1: Ready-Made Embed Code (Bildhive Admin)
The easiest way to get started is using the AI Chat Widget Customizer built directly into the Bildhive Admin AI application.
Accessing the Customizer
- Log into your Bildhive Admin portal.
- Open your project's AI App.
- Navigate to Settings > AI Chat Widget Customizer.
Bildhive Admin
└── AI App
└── Settings
└── AI Chat Widget CustomizerFeatures of the Visual Customizer
- Live Multi-State Preview: Preview how your widget looks and behaves across all 4 visitor states:
- First Visit (Expanded launcher pill with CTA copy)
- Returning Visitor (Compact circular launcher button)
- Lead Registration (Lead capture form with consent checkboxes and policy links)
- Chat Conversation (Active messaging interface with avatars, action buttons, and markdown styling)
- Branding & Smart Theming:
- Select your primary Brand Color (automatically applies to header banners, launchers, primary buttons, and visitor bubbles).
- Use the Invert Text Color switch if automatic contrast calculation needs manual adjustment.
- Set custom background and text colors for the AI Assistant Message Bubbles.
- Media Library Integration: Pick your Header Logo and AI Profile Image directly from your Bildhive media library or enter image URLs.
- Copy & Legal Customization: Update the welcome headline, introductory description, email/SMS consent disclaimers, and links to your Privacy Policy and Terms of Use.
- 1-Click Embed Code: Click Copy Embed Code to get a fully generated, ready-to-paste snippet.
Method 2: Custom Element Embedding
If you want to use the pre-built UI with custom attribute values in your codebase, follow these steps.
Step 1: Load the Widget Script
Include the compiled widget loader script in the <head> or before the closing </body> tag of your website:
html
<!-- Bildhive Chat Widget Script Loader -->
<script src="https://cdn.bildhive.com/scripts/CustomWebsiteWidgets/widgetLoader.js" async defer></script>Note for Development: If testing against Bildhive's development environment, use
https://cdn.bildhive.dev/scripts/CustomWebsiteWidgets/widgetLoader.js.
Step 2: Add the Custom Element Tag
Place the <bildhive-chat-widget> element in your HTML:
html
<bildhive-chat-widget
instance="YOUR_INSTANCE_TOKEN"
agent-id="YOUR_AI_AGENT_ID"
position="right"
offset="20px"
header-text="AI Sales Assistant"
banner-background="#f7941e"
button-background="#f7941e"
icon-background="#f7941e">
</bildhive-chat-widget>Complete Embed Example
Below is a complete HTML snippet demonstrating how to embed the Web Component, customize styling via HTML attributes, and pass complex object properties (logos, profile avatars, legal links) via JavaScript:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Website with AI Chat</title>
<!-- 1. Load the Bildhive Widget Script -->
<script src="https://cdn.bildhive.com/scripts/CustomWebsiteWidgets/widgetLoader.js" async defer></script>
</head>
<body>
<!-- 2. Declare the Custom Element with HTML Attributes -->
<bildhive-chat-widget
instance="634dd0254f594a11fca146b7"
agent-id="6a0b672ce473781dabff250a"
position="right"
offset="20px"
header-text="AI Sales Assistant"
header-text-size="medium"
ai-profile-name="Sarah - AI Assistant"
icon-button-text="Chat With AI"
banner-background="#0f766e"
button-background="#0f766e"
button-background-hover="#115e59"
icon-background="#0f766e"
user-text-bg-color="#0f766e"
user-text-color="#ffffff"
ai-text-bg-color="#f3f4f6"
ai-text-color="#1f2937"
border-radius="6"
border-thickness="1"
action-background="#0d5f58"
action-color="#ffffff"
action-border-radius="8"
welcome-heading="Welcome to Acme Homes!"
welcome-intro-text="I can help answer questions about our available communities, floor plans, and pricing."
email-consent-text="I consent to receive email updates regarding new releases and pricing."
sms-consent-text="I consent to receive SMS updates. Message and data rates may apply.">
</bildhive-chat-widget>
<!-- 3. Assign Complex Object Properties via JavaScript -->
<script>
customElements.whenDefined('bildhive-chat-widget').then(function () {
var widget = document.querySelector('bildhive-chat-widget');
if (!widget) return;
// Custom Header Logo
widget.headerLogo = {
url: 'https://example.com/assets/logo-white.svg'
};
// Custom AI Avatar Image
widget.aiProfileImage = {
url: 'https://example.com/assets/ai-avatar.png'
};
// Legal Links
widget.privacyPolicy = {
label: 'Privacy Policy',
link: 'https://example.com/privacy'
};
widget.termsOfUse = {
label: 'Terms of Use',
link: 'https://example.com/terms'
};
});
</script>
</body>
</html>Configuration & Attributes Reference
All attributes on <bildhive-chat-widget> use standard kebab-case naming in HTML.
Core Configuration
| Attribute | Type | Default | Description |
|---|---|---|---|
instance | string | Required | Your unique Bildhive project instance token. |
agent-id | string | Required | The ID of the AI Chat Agent to connect with. |
environment | string | production | Backend API environment (production or development). |
position | string | right | Docking edge on the screen: left or right. |
offset | string | 20px | Margin distance from screen edges (e.g. 20px, 1.5rem). |
Launcher & Trigger Button
| Attribute | Type | Default | Description |
|---|---|---|---|
icon-button-text | string | Chat With AI | Text label on the expanded trigger pill shown to first-time visitors. |
icon-background | string | #f7941e | Background color of the floating launcher button. |
icon-color | string | #ffffff | Icon and text color inside the launcher button. |
icon-size | number | 45 | Diameter of the circular launcher icon in pixels. |
icon-position | string | right | Alignment of the trigger icon: left or right. |
icon-position-offset | number | 5 | Offset spacing for the icon position in pixels. |
button-font | string | inherit | Font family for buttons and trigger labels. |
Header & Branding
| Attribute | Type | Default | Description |
|---|---|---|---|
header-text | string | AI Sales Assistant | Title displayed in the chat header banner. |
header-text-size | string | medium | Font size for header title: small, medium, or large. |
header-color | string | #ffffff | Text and icon color inside the header banner. |
banner-background | string | #f7941e | Background color of the header banner. |
ai-profile-name | string | AI Agent | Display name of the AI assistant shown in chat messages. |
ai-profile-type | string | image | Avatar type (image). |
ai-profile-color | string | #3a4b67 | Text/icon color for assistant profile badge fallback. |
ai-profile-bg-color | string | #f1f1f1 | Background color for assistant profile badge fallback. |
user-profile-color | string | #3a4b67 | Text/icon color for visitor profile badge. |
user-profile-bg-color | string | #f1f1f1 | Background color for visitor profile badge. |
Chat Bubbles
| Attribute | Type | Default | Description |
|---|---|---|---|
user-text-bg-color | string | #f7941e | Background color of visitor message bubbles. |
user-text-color | string | #ffffff | Text color of visitor message bubbles. |
ai-text-bg-color | string | #f1f1f1 | Background color of assistant message bubbles. |
ai-text-color | string | #3a4b67 | Text color of assistant message bubbles. |
Buttons, Inputs & Actions
| Attribute | Type | Default | Description |
|---|---|---|---|
button-background | string | #f7941e | Primary button background color. |
button-color | string | #ffffff | Primary button text color. |
button-border | string | #d9d9d9 | Primary button border color. |
button-background-hover | string | #e6821a | Button background color on hover. |
button-hover | string | #ffffff | Button text color on hover. |
button-border-hover | string | #d9d9d9 | Button border color on hover. |
border-radius | number | 4 | Corner radius in pixels for inputs and standard buttons. |
border-thickness | number | 1 | Border thickness in pixels for input fields. |
action-background | string | #98612b | Background color of header action buttons (History, New Chat). |
action-color | string | #ffffff | Icon color of header action buttons. |
action-background-hover | string | #774e2c | Background color of header action buttons on hover. |
action-color-hover | string | #ffffff | Icon color of header action buttons on hover. |
action-border-radius | number | 8 | Border radius in pixels for header action buttons. |
Lead Form Copy
| Attribute | Type | Default | Description |
|---|---|---|---|
welcome-heading | string | Hi there! | Headline displayed at the top of the registration screen. |
welcome-intro-text | string | "I'm here to help you understand..." | Subtext describing the assistant's capabilities. |
email-consent-text | string | "I consent to receive email communications..." | Disclaimer copy beside the email consent checkbox. |
sms-consent-text | string | "I consent to receive SMS communications..." | Disclaimer copy beside the SMS consent checkbox. |
Complex Object Properties (JavaScript)
Some properties are JavaScript objects that cannot be passed cleanly as HTML string attributes. You can set them directly on the DOM element once the custom element is defined:
javascript
customElements.whenDefined('bildhive-chat-widget').then(() => {
const widget = document.querySelector('bildhive-chat-widget');
if (!widget) return;
// Header Logo URL
widget.headerLogo = {
url: 'https://your-domain.com/assets/logo.svg'
};
// AI Profile Avatar Image URL
widget.aiProfileImage = {
url: 'https://your-domain.com/assets/assistant-avatar.png'
};
// Privacy Policy Link
widget.privacyPolicy = {
label: 'Privacy Policy',
link: 'https://your-domain.com/privacy-policy'
};
// Terms of Use Link
widget.termsOfUse = {
label: 'Terms of Use',
link: 'https://your-domain.com/terms-of-service'
};
});Method 3: Building a Custom / Headless Chat Widget with Bildhive APIs
If you want complete design freedom, need to integrate the chat directly into a mobile app, or want to create a bespoke conversational user interface, you can build a custom widget by calling the Bildhive REST and streaming APIs directly.
API Architecture & Endpoints
| Environment | Core API Base URL | AI Streaming Backend Base URL |
|---|---|---|
| Production | https://api.bildhive.com | https://ai-backend.bildhive.com |
| Development | https://api.bildhive.dev | https://ai-backend.bildhive.dev |
Authentication: Pass your project instance token in the query string
?token=YOUR_INSTANCE_TOKENfor all API requests.For interactive Swagger parameter specifications, request/response models, and status codes, refer to the Bildhive API Documentation (Contacts) and Bildhive API Documentation (AI Chat).
End-to-End Implementation Flow
1. Visitor Arrival
├── Check localStorage for 'lead_email'
└── IF email exists -> GET /v1/contacts (Verify returning contact)
└── IF valid -> Proceed to History / Chat Session
2. Lead Registration (First-Time Visitor)
├── (Optional) POST /v1/contacts/check-phone-duplicate
└── POST /v1/contacts (Create Contact -> Returns contactId)
└── Save email to localStorage ('lead_email')
3. Conversation History
└── GET /v1/ai-agent-conversations?contact={contactId}
└── Load previous sessions and messages
4. Real-Time Streaming Chat
└── POST /v1/ai-agent-conversations/{agentId}/chat (Header: X-Stream: true)
└── Stream SSE chunks (Text tokens, Tool Thinking, UI Elements, Finish, Handoff)Step 1: Check / Verify Returning Contact
When a visitor opens your custom chat UI, check if an email is stored in localStorage under lead_email. If found, verify their contact profile:
Request:
http
GET https://api.bildhive.com/v1/contacts?token=YOUR_INSTANCE_TOKEN&email=mark@bildhive.comResponse (200 OK):
json
{
"id": "687e488af4484e271a434bab",
"firstName": "Mark",
"lastName": "Evans",
"email": "mark@bildhive.com",
"phone": ""
}If the contact is returned, store contact.id as the active contactId and allow them to proceed straight to the chat or history screen.
Step 2: Lead Registration & Duplicate Phone Validation
For new visitors, display a registration form to collect their contact details before initiating chat sessions.
A. (Optional) Check Duplicate Phone Number
If the user provides a phone number, validate whether the phone number is already registered under a different email:
Request:
http
POST https://api.bildhive.com/v1/contacts/check-phone-duplicate?token=YOUR_INSTANCE_TOKEN
Content-Type: application/json
{
"email": "john.doe@example.com",
"phone": "+15551234567"
}Response:
- No conflict:
{ "success": true } - Conflict detected:jsonIf
{ "status": "phone_conflict", "requiresConfirmation": true, "message": "This phone number is already associated with an account. Would you like to continue?" }requiresConfirmationistrue, prompt the user to confirm before proceeding with registration.
B. Register Contact Profile
Submit the lead registration form to create the contact in your Bildhive CRM:
Request:
http
POST https://api.bildhive.com/v1/contacts?token=YOUR_INSTANCE_TOKEN
Content-Type: application/json
X-Timezone: America/New_York
{
"fullName": "John Doe",
"email": "john.doe@example.com",
"phone": "+15551234567",
"source": "AI CHAT BOT WIDGET",
"sourceUrl": "https://mywebsite.com/contact",
"consent": true,
"smsConsent": true,
"agentId": "YOUR_AI_AGENT_ID"
}Response (201 Created):
json
{
"id": "64fa821c9e42100018f98a21",
"fullName": "John Doe",
"email": "john.doe@example.com",
"createdAt": "2026-08-27T10:00:00.000Z"
}After successful registration, store data.email in localStorage.setItem('lead_email', data.email) and keep data.id as the current contactId.
Step 3: Fetching Conversation History
To allow returning users to review previous conversations or resume an earlier discussion, fetch their conversation sessions:
Request:
http
GET https://api.bildhive.com/v1/ai-agent-conversations?token=YOUR_INSTANCE_TOKEN&contact=687e488af4484e271a434bab&_limit=20&_start=0&_sort=updatedAt:descResponse (200 OK):
json
[
{
"id": "6a6b4b23a32ef33f9f183368",
"sessionId": "fabb5553-8e7b-4141-afde-da351a0993d1",
"conversationStartedAt": "2026-07-30T13:01:23.980Z",
"lastMessageAt": "2026-07-30T13:01:50.614Z",
"messages": [
{
"id": "9d7aeeb2-fda1-4caa-8db7-a793d9a9b1b2",
"type": "human",
"createdAt": "2026-07-30T13:01:17.905Z",
"data": {
"content": "Hi There"
}
},
{
"id": "06cee681-bbce-4a4d-8765-954a9f1504f6",
"type": "ai",
"createdAt": "2026-07-30T13:01:23.909Z",
"data": {
"content": "{\"output\":{\"text\":\"Hello! Welcome to Joey’s Cove. How can I assist you with your home search or any questions you have about the community today?\",\"ui_elements\":null}}"
}
}
],
"createdAt": "2026-07-30T13:01:23.912Z",
"updatedAt": "2026-07-30T13:13:21.154Z"
}
]When a user clicks an earlier conversation, set sessionId to chat.sessionId and render the past messages in your chat window.
Step 4: Real-Time Streaming Chat Endpoint
To send a message and stream AI responses in real-time, call the AI Backend streaming endpoint:
Request:
http
POST https://ai-backend.bildhive.com/v1/ai-agent-conversations/YOUR_AI_AGENT_ID/chat?token=YOUR_INSTANCE_TOKEN
Content-Type: application/json
X-Stream: true
{
"userInput": "Can you show me 4-bedroom floor plans?",
"sessionId": "sess_98234120938",
"contactId": "64fa821c9e42100018f98a21"
}Note: For a brand new conversation, omit
sessionId(or passnull). The streaming API will return a newsessionIdin the first event chunk.
Server-Sent Events (SSE) Stream Protocol
The server returns a continuous text stream formatted as standard SSE lines prefixed with data: :
txt
data: {"sessionId":"sess_98234120938","outputBlocks":[{"output":{"text":"Here are our available 4-bedroom floor plans:"}}]}
data: {"part":{"type":"tool-input-start"}}
data: {"part":{"type":"tool-result"}}
data: {"outputBlocks":[{"output":{"text":"Here are our available 4-bedroom floor plans:\n\n1. **The Oakridge** (2,850 sq ft)\n2. **The Hawthorne** (3,200 sq ft)","ui_elements":[{"type":"card","data":{"title":"The Oakridge","imageUrl":"https://...","price":"$650,000"}}]}}]}
data: {"type":"finish","sessionId":"sess_98234120938","outputBlocks":[{"output":{"text":"...","ui_elements":[...]}}]}
data: [DONE]Event Object Structure:
event.sessionId: The conversation session ID. Save this for subsequent user messages in the same thread.event.outputBlocks: Array of response blocks containing:block.output.text: Progressive markdown response text.block.output.ui_elements: Array of interactive cards or media cards returned by the AI agent.block.showStartNewChatButton: Boolean flag indicating if the agent suggests starting a fresh conversation.block.newChatTarget: Optional topic/handoff target data.
event.part.type === 'tool-input-start': Signals that the AI agent is currently executing a tool or querying live database records (show a "Thinking..." indicator).event.part.type === 'tool-result': Signals that tool execution is complete.event.type === 'finish': The response stream has completed.event.type === 'handoff': The conversation has been handed off to a live agent.event.type === 'error': Stream encountered an error.
Step 5: Complete Vanilla JavaScript Headless Client
Here is a lightweight, dependency-free JavaScript client that handles authentication, lead registration, history fetching, and streaming responses:
javascript
/**
* Bildhive AI Chat Headless Client
*/
class BildhiveAIChatClient {
constructor({ instance, agentId, environment = 'production' }) {
this.instance = instance;
this.agentId = agentId;
this.apiBase = environment === 'development'
? 'https://api.bildhive.dev'
: 'https://api.bildhive.com';
this.aiBase = environment === 'development'
? 'https://ai-backend.bildhive.dev'
: 'https://ai-backend.bildhive.com';
this.contact = null;
this.sessionId = null;
this.abortController = null;
}
// 1. Check returning contact from email
async checkReturningContact(email) {
const res = await fetch(`${this.apiBase}/v1/contacts?token=${this.instance}&email=${encodeURIComponent(email.toLowerCase())}`);
if (!res.ok) throw new Error('Contact lookup failed');
const contact = await res.json();
this.contact = contact;
return contact;
}
// 2. Register a new lead
async registerLead({ fullName, email, phone, consent = true, smsConsent = false }) {
const timeZone = Intl?.DateTimeFormat?.()?.resolvedOptions?.()?.timeZone;
const headers = { 'Content-Type': 'application/json' };
if (timeZone) headers['X-Timezone'] = timeZone;
const res = await fetch(`${this.apiBase}/v1/contacts?token=${this.instance}`, {
method: 'POST',
headers,
body: JSON.stringify({
fullName,
email: email.toLowerCase(),
phone: phone || undefined,
source: 'CUSTOM AI CHAT WIDGET',
sourceUrl: window.location.href,
consent,
smsConsent,
agentId: this.agentId
})
});
if (!res.ok) {
const err = await res.json();
throw new Error(err.message || 'Registration failed');
}
const contact = await res.json();
this.contact = contact;
window.localStorage.setItem('lead_email', contact.email || '');
return contact;
}
// 3. Fetch past conversation history
async getChatHistory(limit = 20, start = 0) {
if (!this.contact?.id) throw new Error('No active contact');
const query = new URLSearchParams({
token: this.instance,
contact: this.contact.id,
_limit: limit,
_start: start,
_sort: 'updatedAt:desc'
}).toString();
const res = await fetch(`${this.apiBase}/v1/ai-agent-conversations?${query}`);
if (!res.ok) throw new Error('Failed to load history');
return await res.json();
}
// 4. Send message and stream AI response
async sendMessage(userInput, { onToken, onThinking, onFinish, onError, onHandoff }) {
if (!this.contact?.id) throw new Error('Contact must be registered before chatting');
if (this.abortController) this.abortController.abort();
this.abortController = new AbortController();
const payload = {
userInput,
sessionId: this.sessionId,
contactId: this.contact.id
};
try {
const res = await fetch(`${this.aiBase}/v1/ai-agent-conversations/${this.agentId}/chat?token=${this.instance}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Stream': 'true'
},
body: JSON.stringify(payload),
signal: this.abortController.signal
});
if (!res.ok) throw new Error('Failed to initiate stream');
const reader = res.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop() || '';
for (const line of lines) {
const trimmed = line.trim();
if (!trimmed || !trimmed.startsWith('data:')) continue;
const dataPayload = trimmed.slice(5).trim();
if (dataPayload === '[DONE]') continue;
try {
const event = JSON.parse(dataPayload);
if (event.sessionId) this.sessionId = event.sessionId;
if (event.type === 'finish') {
if (onFinish) onFinish(event);
} else if (event.type === 'error') {
if (onError) onError(event.error || 'Stream error');
} else if (event.type === 'handoff') {
if (onHandoff) onHandoff(event.data);
} else {
if (event.part?.type === 'tool-input-start' && onThinking) onThinking(true);
if (event.part?.type === 'tool-result' && onThinking) onThinking(false);
if (event.outputBlocks && event.outputBlocks.length > 0) {
const text = event.outputBlocks.map(b => b.output?.text || '').join('\n\n');
const uiElements = event.outputBlocks.flatMap(b => b.output?.ui_elements || []);
if (onToken) onToken({ text, uiElements });
}
}
} catch (e) {
console.error('Error parsing SSE chunk:', e);
}
}
}
} catch (err) {
if (err.name === 'AbortError') {
console.log('Stream aborted by user');
} else {
if (onError) onError(err.message);
}
}
}
// 5. Cancel active stream
stopStreaming() {
if (this.abortController) {
this.abortController.abort();
this.abortController = null;
}
}
}Example Usage:
javascript
// Initialize Client
const chatClient = new BildhiveAIChatClient({
instance: '634dd0254f594a11fca146b7',
agentId: '6a0b672ce473781dabff250a'
});
// 1. Register or continue
await chatClient.registerLead({
fullName: 'Alice Walker',
email: 'alice@example.com',
phone: '555-987-6543'
});
// 2. Stream message
await chatClient.sendMessage('What communities have homes under $500k?', {
onToken: ({ text, uiElements }) => {
console.log('Streaming text:', text);
console.log('Cards / UI elements:', uiElements);
},
onThinking: (isThinking) => {
console.log('AI is searching records:', isThinking);
},
onFinish: (result) => {
console.log('Conversation complete:', result);
}
});Lead Capture, Security & User Lifecycle
1. Lead Registration Workflow
When a new visitor interacts with the widget, they are greeted with the registration screen before starting the conversation:
- Full Name (Required)
- Email Address (Required, validated)
- Phone Number (Optional)
- Email Consent Checkbox (Required)
- SMS Consent Checkbox (Optional if phone is provided)
- Terms & Privacy Checkbox (Required)
Upon submission, the lead is registered directly into your Bildhive project's contact CRM (/v1/contacts).
2. Returning User Experience
- When a lead successfully registers or logs in, their email is stored in
window.localStorageunder the keylead_email. - On subsequent visits to your website, the widget automatically recognizes the returning user and provides a streamlined "Welcome back" continuation screen, allowing them to jump straight into conversation or browse past chat history.
3. Built-In Spam & Bot Protection
The registration form contains automated safeguards against spam submissions:
- Honeypot Trap: An invisible dummy input field (
website) is included. Automated bots filling in all available fields are immediately blocked. - Human Speed Threshold: Submissions completed in under 6 seconds from form display are rejected with a warning prompt to prevent robotic form blasters.
4. Duplicate Phone Conflict Handling
If a visitor registers with a phone number that is already associated with an existing contact in your database, the widget displays a confirmation dialog asking them to confirm before linking their conversation, preventing accidental data collisions.
Framework Integration Recipes
Plain HTML / Static Sites / CMS (WordPress, Webflow, Squarespace)
Simply add the <script> tag before </body> and place <bildhive-chat-widget> anywhere on the page (e.g., in your global site footer or custom code injection settings).
React / Next.js (App Router & Pages Router)
In React or Next.js, declare the custom element inside a client component and use useEffect or next/script to load the loader script:
tsx
'use client';
import { useEffect, useRef } from 'react';
import Script from 'next/script';
export default function AIChatWidget() {
const widgetRef = useRef<HTMLElement | null>(null);
useEffect(() => {
if (typeof window === 'undefined') return;
customElements.whenDefined('bildhive-chat-widget').then(() => {
const widget = widgetRef.current as any;
if (!widget) return;
widget.headerLogo = { url: '/brand-logo.svg' };
widget.aiProfileImage = { url: '/ai-avatar.png' };
widget.privacyPolicy = { label: 'Privacy Policy', link: '/privacy' };
widget.termsOfUse = { label: 'Terms of Use', link: '/terms' };
});
}, []);
return (
<>
<Script
src="https://cdn.bildhive.com/scripts/CustomWebsiteWidgets/widgetLoader.js"
strategy="lazyOnload"
/>
{/* @ts-ignore custom element JSX tag */}
<bildhive-chat-widget
ref={widgetRef}
instance="YOUR_INSTANCE_TOKEN"
agent-id="YOUR_AI_AGENT_ID"
position="right"
offset="20px"
header-text="AI Sales Assistant"
banner-background="#0f766e"
button-background="#0f766e"
icon-background="#0f766e"
/>
</>
);
}Vue 3 / Vite
If using Vite and Vue 3, instruct the Vue compiler to treat <bildhive-chat-widget> as a custom Web Component rather than a Vue component:
javascript
// vite.config.js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [
vue({
template: {
compilerOptions: {
// Treat all tags starting with bildhive- as custom elements
isCustomElement: (tag) => tag.startsWith('bildhive-')
}
}
})
]
});Then in your Vue template:
vue
<template>
<bildhive-chat-widget
ref="widgetRef"
instance="YOUR_INSTANCE_TOKEN"
agent-id="YOUR_AI_AGENT_ID"
position="right"
offset="20px"
/>
</template>
<script setup>
import { ref, onMounted } from 'vue';
const widgetRef = ref(null);
onMounted(async () => {
// Dynamically load loader script if not present in index.html
if (!customElements.get('bildhive-chat-widget')) {
const script = document.createElement('script');
script.src = 'https://cdn.bildhive.com/scripts/CustomWebsiteWidgets/widgetLoader.js';
script.async = true;
document.head.appendChild(script);
}
await customElements.whenDefined('bildhive-chat-widget');
if (widgetRef.value) {
widgetRef.value.headerLogo = { url: '/logo.svg' };
widgetRef.value.aiProfileImage = { url: '/ai-avatar.png' };
widgetRef.value.privacyPolicy = { label: 'Privacy Policy', link: '/privacy' };
widgetRef.value.termsOfUse = { label: 'Terms of Use', link: '/terms' };
}
});
</script>Troubleshooting & FAQ
1. "The API add-on is not enabled for this project"
- Cause: Your Bildhive project subscription does not currently include the API Add-on.
- Resolution: The project owner or billing manager should enable the API add-on in the Bildhive Admin dashboard under Settings > Projects > Edit > Add-ons.
2. Content Security Policy (CSP) & CORS Domains
If your website uses strict Content Security Policy headers, make sure the following domains are whitelisted:
| Directive | Allowed Domain | Purpose |
|---|---|---|
script-src | https://cdn.bildhive.com (or .dev) | Loading the widgetLoader.js bundle. |
connect-src | https://api.bildhive.com | Contacts CRM and duplicate phone validation. |
connect-src | https://ai-backend.bildhive.com | Real-time AI chat stream & conversation endpoints. |
img-src | https://*.digitaloceanspaces.com | Default avatar and icon assets. |
3. Z-Index and Layering
The widget automatically positions its host container at z-index: 999999 and position: fixed. If you have modals or navigation drawers with a higher z-index, you can adjust their CSS stacking context accordingly.
4. Maximized Window Mode
When the user clicks the "Maximize" toggle in the header, the widget expands to 95vw / 90vh centered on screen with backdrop focus, offering an expansive view for detailed product recommendations and image lightbox browsing.