Advanced Features
Explore powerful advanced features of the SiteAssist widget
Overview
The SiteAssist widget includes several advanced features that enhance user experience and provide powerful capabilities beyond basic chat functionality.
Text Selection & Context
One of the most powerful features of the SiteAssist widget is intelligent text selection. Users can select any text on your page and instantly ask the AI about it.
How It Works
- User selects text on your page
- An "Ask AI" popover appears near the selection
- User clicks the popover
- Widget opens with the selected text as context
- AI provides answers based on both the selection and page content
Automatic Context Sharing
The widget automatically shares page context with the AI, including:
- Page URL: Current page location
- Page Title: Document title
- Page Content: Cleaned, text-only version of page content
- Selected Text: Any text the user has selected (if using text selection feature)
What gets filtered out:
- Scripts and styles
- Navigation menus
- Advertisements
- SVG and canvas elements
- Media elements (audio, video, images)
- The widget itself
Example Use Cases
Documentation Sites:
User selects: "To install the package, run npm install..."
User asks: "What does this command do?"
AI responds with context-aware explanation
E-commerce:
User selects: "Free shipping on orders over $50"
User asks: "How can I get free shipping?"
AI explains the shipping policy
Blog Posts:
User selects: "The React useEffect hook..."
User asks: "Can you explain this in simpler terms?"
AI provides a simplified explanation
Controlling Text Selection Areas
You can control where the text selection popover appears using the contentSelector
option:
// Default - only show popover in .main-content elements
SiteAssist("init", {
apiKey: "YOUR_API_KEY",
contentSelector: true, // or omit entirely
});
// Show popover everywhere on the page
SiteAssist("init", {
apiKey: "YOUR_API_KEY",
contentSelector: false,
});
// Custom selector - only in specific areas
SiteAssist("init", {
apiKey: "YOUR_API_KEY",
contentSelector: ".main-content",
});
Use Cases:
- Documentation sites: Restrict to main content areas to avoid confusion
- Blogs: Only allow selection in article content, not navigation
- E-commerce: Enable everywhere for product help and support
- Admin panels: Restrict to specific content sections
Example HTML Structure:
<div class="sidebar">
<nav>
<a href="/">Home</a>
<a href="/docs">Docs</a>
</nav>
<!-- Text selection popover won't appear here -->
</div>
<div class="main-content">
<h1>Documentation</h1>
<p>Select this text to ask AI questions!</p>
<!-- Text selection popover WILL appear here -->
</div>
Fullscreen Mode
The widget supports fullscreen mode for immersive chat experiences.
Automatic Fullscreen
Fullscreen is automatically activated on:
- Mobile devices (screens < 768px wide)
- When user clicks fullscreen button in widget
Manual Fullscreen Control
The widget can request fullscreen mode, which is handled automatically:
// Widget internally handles fullscreen requests
// No manual API needed - users control via widget UI
Fullscreen Behavior
When fullscreen is active:
- Widget expands to fill entire viewport
- Page scrolling is disabled (
overflow: hidden
) - Close button remains accessible
- User can exit via close button or ESC key
When fullscreen exits:
- Widget returns to normal size
- Page scrolling is restored
- Content layout returns to normal
Responsive Breakpoints
The widget uses these breakpoints:
- Mobile (
< 768px
): Always fullscreen when open - Tablet (
768px - 1024px
): Standard size, can go fullscreen - Desktop (
≥ 1024px
): Standard size with sidepanel support
Page Context Integration
The widget automatically integrates with your page content to provide intelligent, context-aware responses.
Context Extraction
When a user interacts with the widget, it automatically extracts:
{
url: "https://yoursite.com/page",
title: "Page Title",
content: "Clean text content of the page...",
textSelection: "Selected text (if any)"
}
How Content is Cleaned
The widget intelligently cleans page content:
- Clone the document body
- Remove unnecessary elements (scripts, styles, widgets, media)
- Extract link text and URLs:
"Link Text (https://url)"
- Normalize whitespace and line breaks
- Send to AI for context-aware responses
Example Context Usage
User visits: https://example.com/pricing
// Automatically shared context:
{
url: "https://example.com/pricing",
title: "Pricing - Example SaaS",
content: "Pricing Plans Starter $9/month Basic features... Pro $29/month Advanced features...",
textSelection: null
}
User asks: "What's included in the Pro plan?"
AI receives context and can answer specifically about that page's Pro plan.
Privacy Considerations
What is shared:
- Publicly visible text content
- Page URL and title
- User's selected text
What is NOT shared:
- Form inputs or user data
- Hidden or password-protected content
- Images or media files
- Scripts or technical implementation
Custom Events
The widget dispatches custom events that you can listen to for advanced integrations.
Event Format
All custom events are prefixed with sa:
and dispatched on the window
object:
window.addEventListener("sa:event_name", (event) => {
console.log("Event detail:", event.detail);
});
Common Events
While specific events depend on your widget configuration, you can listen for custom events:
// Example: Listen for chat opened
window.addEventListener("sa:opened", () => {
console.log("Chat widget opened");
// Track in your analytics
analytics.track("Chat Opened");
});
// Example: Listen for chat closed
window.addEventListener("sa:closed", () => {
console.log("Chat widget closed");
});
// Example: Custom event from widget
window.addEventListener("sa:custom_action", (event) => {
console.log("Custom action:", event.detail);
});
Event-Driven Integrations
Example - Track widget usage:
let chatOpenedAt = null;
window.addEventListener("sa:opened", () => {
chatOpenedAt = Date.now();
console.log("Chat opened");
});
window.addEventListener("sa:closed", () => {
if (chatOpenedAt) {
const duration = Date.now() - chatOpenedAt;
console.log(`Chat was open for ${duration}ms`);
chatOpenedAt = null;
}
});
Example - Trigger other UI elements:
window.addEventListener("sa:opened", () => {
// Hide other overlays when chat opens
document.getElementById("promo-banner").style.display = "none";
});
window.addEventListener("sa:closed", () => {
// Show promo banner again
document.getElementById("promo-banner").style.display = "block";
});
Responsive Behavior
The widget automatically adapts to different screen sizes and orientations.
Mobile Optimization
On mobile devices (< 768px):
- Widget opens in fullscreen
- "Ask AI" text selection popover is optimized for touch
- Page scrolling disabled when widget is open
- Swipe gestures for closing (native behavior)
Tablet Behavior
On tablets (768px - 1024px):
- Standard widget size
- Sidepanel floats over content (doesn't push)
- Touch-optimized interactions
- Responsive text selection
Desktop Experience
On desktop (≥ 1024px):
- Full-featured experience
- Sidepanel can push content
- Keyboard shortcuts work
- Precise text selection
Orientation Changes
The widget automatically handles orientation changes:
// Automatically handled - no code needed
// Widget adjusts when device rotates
Sidepanel Integration
The sidepanel widget type offers advanced integration with your application layout.
Content Push Behavior
When sidepanel opens on desktop screens:
SiteAssist("init", {
apiKey: "YOUR_API_KEY",
type: "sidepanel",
appContainerSelector: ".main-content",
});
Desktop (≥ 1024px):
- Container margin-right:
400px
- Smooth transition animation
- Content visible alongside widget
Tablet (< 1024px):
- Sidepanel floats over content
- No content push
- Overlay-style interaction
Mobile (< 768px):
- Full-screen mode
- Content hidden while widget open
Multiple Containers
You can have multiple containers that respond to the sidepanel:
<div class="siteassist-container">
<header>Header content</header>
</div>
<div class="siteassist-container">
<main>Main content</main>
</div>
<div class="siteassist-container">
<footer>Footer content</footer>
</div>
All containers with the class will be pushed when the sidepanel opens.
Custom Transition
The widget applies default transitions, but you can customize:
.siteassist-container {
transition-property: margin-right;
transition-duration: 200ms;
transition-timing-function: ease-in-out;
}
Performance Optimization
The widget is designed for optimal performance:
Async Loading
The widget loads asynchronously and doesn't block page rendering:
// Non-blocking async load
o.async = !0;
o.src = "https://...widget.js";
e.head.appendChild(o);
Lazy Initialization
The iframe content only loads when:
- Widget is initialized
- User first interacts with the widget
Resource Optimization
- Small bundle size: ~10KB gzipped
- No external dependencies: Self-contained
- Efficient event handlers: Debounced and throttled
- Smart content extraction: Only when needed
Security Best Practices
Publishable Key Protection
// ✅ Good - use environment variables
SiteAssist("init", {
apiKey: process.env.NEXT_PUBLIC_SITEASSIST_PUBLISHABLE_KEY,
});
// ❌ Avoid - hardcoded keys in public repos
SiteAssist("init", {
apiKey: "pk_live_hardcoded_key_123", // Don't commit this!
});
Content Security Policy (CSP)
If you use CSP headers, whitelist these domains:
script-src 'self' https://cnrib24ur3hk4b49.public.blob.vercel-storage.com;
frame-src https://widgets.siteassist.io;
connect-src https://api.siteassist.io;
Cross-Origin Communication
The widget uses secure postMessage
communication:
// Widget validates message origin
if (ev.origin !== options.widgetUrl) return;
Advanced Customization Examples
Custom Trigger Button
Replace default floating button with your own:
<style>
.sa-button {
display: none !important;
} /* Hide default button */
</style>
<button id="custom-chat-button" class="your-button-class">
💬 Chat with AI
</button>
<script>
SiteAssist("init", {
apiKey: "YOUR_API_KEY",
type: "floating-bubble",
});
document
.getElementById("custom-chat-button")
.addEventListener("click", () => {
SiteAssist("toggle");
});
</script>
Conditional Loading
Load widget only for specific pages or users:
// Only load on product pages
if (window.location.pathname.startsWith("/products/")) {
SiteAssist("init", {
apiKey: "YOUR_API_KEY",
});
}
// Only for logged-in users
if (userIsLoggedIn) {
SiteAssist("init", {
apiKey: "YOUR_API_KEY",
externalId: currentUser.id,
});
}
Theme Synchronization
Sync widget theme with your site:
// Watch for site theme changes
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.attributeName === "data-theme") {
const theme = document.documentElement.getAttribute("data-theme");
SiteAssist("changeTheme", theme);
}
});
});
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ["data-theme"],
});
Troubleshooting
Text Selection Not Working
Check:
- Widget is properly initialized
- No conflicting JavaScript on the page
- Browser supports Selection API
- Content selector is correctly configured
Debug:
window.addEventListener("mouseup", () => {
const selection = window.getSelection();
console.log("Selected text:", selection.toString());
// Check if selection is in the right area
const range = selection.getRangeAt(0);
const container = range.commonAncestorContainer;
console.log("Selection container:", container);
});
Common Issues:
- Popover not appearing: Check your
contentSelector
setting - Popover appears in wrong areas: Verify your CSS selector is correct
- Selection not working at all: Ensure widget is properly initialized
Example debugging:
// Test if contentSelector is working
SiteAssist("init", {
apiKey: "YOUR_API_KEY",
contentSelector: ".test-area", // Test with a specific area
});
// Check if the selector exists
console.log("Content element found:", document.querySelector(".test-area"));
Fullscreen Issues
Common causes:
- Browser restrictions on fullscreen
- Conflicting CSS
overflow
properties - Z-index conflicts
Solution:
/* Ensure widget has high z-index */
.sa-frame.fullscreen {
z-index: 999999 !important;
}
Content Not Being Captured
Check:
- Page content isn't in an iframe
- Content is rendered (not dynamically loaded after widget init)
- No security restrictions
Next Steps
- Examples - See real-world implementation examples
- API Reference - Complete API documentation
- Configuration - Customization options
Need help with advanced features? Contact us at support@siteassist.io