# Embeddable Widget

Add AI chat widget to your website.

## Overview

**Features**:

* Floating chat button (customizable position)
* Mobile-responsive (full-screen on mobile, bubble on desktop)
* Session persistence (conversation history stored 30 days)
* Customizable theme (light/dark/auto)
* File upload support (max 10MB, PDF/images)

**Bundle size**: 45KB gzipped\
**Load time**: <50ms (async, non-blocking)\
**Browser support**: Chrome 90+, Firefox 88+, Safari 14+, Edge 90+

## Quick Start

### Get Widget Code

1. Twig → Agents → \[Agent] → Deploy tab
2. Click **Embed Widget**
3. Copy generated script tag

### Install

Paste before `</body>` tag:

```html
<script
  src="https://widget.twig.so/widget.js"
  data-agent-id="agent_abc123"
  data-organization-id="org_xyz789"
  async
></script>
```

**Expected result**: Chat button appears bottom-right corner (customizable)

**Load time**: Widget loads asynchronously (\~45KB, cached after first load)

## Configuration

### Basic Configuration

```html
<script
  src="https://widget.twig.so/widget.js"
  data-agent-id="agent-123"
  data-organization-id="org-456"
  data-position="bottom-right"
  data-theme="light"
  data-primary-color="#6366f1"
  async
></script>
```

### Advanced Configuration

```html
<script>
  window.TwigConfig = {
    agentId: 'agent-123',
    organizationId: 'org-456',
    
    // Appearance
    position: 'bottom-right',  // bottom-left, top-right, top-left
    theme: 'light',            // light, dark, auto
    primaryColor: '#6366f1',
    borderRadius: '12px',
    
    // Behavior
    openOnLoad: false,
    persistSession: true,
    enableFileUpload: true,
    enableFeedback: true,
    
    // Text Customization
    welcomeMessage: 'Hi! How can I help?',
    placeholder: 'Ask me anything...',
    submitButtonText: 'Send',
    
    // User Context
    user: {
      id: 'user-789',
      name: 'John Doe',
      email: 'john@example.com',
      metadata: {
        plan: 'pro',
        accountId: 'acc-123'
      }
    }
  };
</script>
<script src="https://widget.twig.so/widget.js" async></script>
```

## Customization

### Styling

#### Theme Selection

**Light Mode:**

```javascript
theme: 'light'
```

**Dark Mode:**

```javascript
theme: 'dark'
```

**Auto (respects system):**

```javascript
theme: 'auto'
```

#### Custom Colors

```javascript
{
  primaryColor: '#6366f1',    // Button and header
  textColor: '#1f2937',       // Main text
  backgroundColor: '#ffffff',  // Widget background
  inputBackground: '#f9fafb'  // Input field
}
```

#### Custom CSS

```html
<style>
  /* Override widget styles */
  .twig-widget {
    font-family: 'Inter', sans-serif;
  }
  
  .twig-widget-header {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  }
  
  .twig-widget-message {
    border-radius: 16px;
  }
</style>
```

### Positioning

```javascript
// Built-in positions
position: 'bottom-right'  // Default
position: 'bottom-left'
position: 'top-right'
position: 'top-left'

// Custom position
customPosition: {
  bottom: '20px',
  right: '20px'
}
```

### Language & Text

```javascript
{
  language: 'en',  // en, es, fr, de, etc.
  
  text: {
    welcomeMessage: '¡Hola! ¿Cómo puedo ayudarte?',
    placeholder: 'Escribe tu pregunta...',
    submitButtonText: 'Enviar',
    feedbackPrompt: '¿Fue útil esta respuesta?',
    feedbackYes: 'Sí',
    feedbackNo: 'No'
  }
}
```

## User Context

### Identifying Users

Pass user information for personalized responses:

```javascript
{
  user: {
    id: 'user-123',              // Unique identifier
    name: 'John Doe',            // Display name
    email: 'john@example.com',   // Email
    metadata: {
      // Custom fields
      plan: 'enterprise',
      accountId: 'acc-456',
      role: 'admin'
    }
  }
}
```

### Session Persistence

```javascript
{
  persistSession: true,          // Remember conversation
  sessionDuration: 3600,         // 1 hour in seconds
  clearOnLogout: true            // Clear when user logs out
}
```

## JavaScript API

### Opening/Closing

```javascript
// Open widget
TwigWidget.open();

// Close widget
TwigWidget.close();

// Toggle widget
TwigWidget.toggle();
```

### Sending Messages Programmatically

```javascript
// Send message from your code
TwigWidget.sendMessage('What is your pricing?');

// Send message with callback
TwigWidget.sendMessage('Hello', (response) => {
  console.log('AI Response:', response);
});
```

### Events

```javascript
// Listen to widget events
TwigWidget.on('open', () => {
  console.log('Widget opened');
});

TwigWidget.on('close', () => {
  console.log('Widget closed');
});

TwigWidget.on('message', (data) => {
  console.log('User sent:', data.userMessage);
  console.log('AI replied:', data.aiResponse);
});

TwigWidget.on('feedback', (data) => {
  console.log('User feedback:', data.rating);
});
```

### Updating Configuration

```javascript
// Update user context
TwigWidget.updateUser({
  id: 'user-789',
  name: 'Jane Smith'
});

// Update theme
TwigWidget.setTheme('dark');

// Update agent
TwigWidget.setAgent('agent-456');
```

## Advanced Features

### File Upload

```javascript
{
  enableFileUpload: true,
  allowedFileTypes: [
    'application/pdf',
    'image/*',
    'text/plain'
  ],
  maxFileSize: 10485760  // 10MB in bytes
}
```

### Proactive Messages

```javascript
// Show message after delay
setTimeout(() => {
  TwigWidget.showSuggestion('Need help getting started?');
}, 5000);

// Show based on user action
if (userOnPricingPage) {
  TwigWidget.showSuggestion('Questions about pricing?');
}
```

### Analytics Integration

```javascript
{
  analytics: {
    enabled: true,
    trackEvents: [
      'widget_opened',
      'message_sent',
      'feedback_given'
    ]
  }
}

// Custom event tracking
TwigWidget.on('message', (data) => {
  gtag('event', 'ai_interaction', {
    query: data.userMessage,
    agent: 'support'
  });
});
```

### Custom Actions

```javascript
{
  customActions: [
    {
      label: 'Talk to Sales',
      icon: '📞',
      action: () => {
        window.open('/contact-sales', '_blank');
      }
    },
    {
      label: 'View Docs',
      icon: '📚',
      action: () => {
        window.open('/docs', '_blank');
      }
    }
  ]
}
```

## Mobile Optimization

The widget is automatically mobile-responsive:

* **Desktop**: Floating chat bubble
* **Mobile**: Full-screen overlay
* **Tablet**: Adaptive sizing

**Mobile-specific options:**

```javascript
{
  mobile: {
    fullScreen: true,
    showCloseButton: true,
    swipeToClose: true
  }
}
```

## Performance

### Lazy Loading

Widget loads asynchronously by default:

```html
<script src="https://widget.twig.so/widget.js" async></script>
```

### Bundle Size

* Initial load: \~45KB (gzipped)
* Lazy-loaded on first interaction
* Cached by browser

### Load Time Impact

* < 50ms on fast connections
* Does not block page render
* No impact on Core Web Vitals

## Security

### Content Security Policy

Add to your CSP:

```
script-src 'self' https://widget.twig.so;
connect-src 'self' https://api.twig.so;
frame-src 'self' https://widget.twig.so;
```

### Data Privacy

* No cookies set (uses sessionStorage)
* GDPR compliant
* User data encrypted
* No tracking without consent

## Examples

### React Application

```tsx
import { useEffect } from 'react';

function App() {
  useEffect(() => {
    // Load widget
    const script = document.createElement('script');
    script.src = 'https://widget.twig.so/widget.js';
    script.async = true;
    
    script.onload = () => {
      window.TwigWidget.init({
        agentId: 'agent-123',
        organizationId: 'org-456'
      });
    };
    
    document.body.appendChild(script);
    
    return () => {
      document.body.removeChild(script);
    };
  }, []);
  
  return <div>Your App</div>;
}
```

### Vue.js Application

```vue
<script setup>
import { onMounted } from 'vue';

onMounted(() => {
  const script = document.createElement('script');
  script.src = 'https://widget.twig.so/widget.js';
  script.setAttribute('data-agent-id', 'agent-123');
  script.setAttribute('data-organization-id', 'org-456');
  document.body.appendChild(script);
});
</script>
```

### Next.js Application

```tsx
// components/TwigWidget.tsx
import { useEffect } from 'react';
import Script from 'next/script';

export default function TwigWidget() {
  return (
    <Script
      src="https://widget.twig.so/widget.js"
      strategy="lazyOnload"
      onLoad={() => {
        window.TwigWidget.init({
          agentId: process.env.NEXT_PUBLIC_TWIG_AGENT_ID,
          organizationId: process.env.NEXT_PUBLIC_TWIG_ORG_ID
        });
      }}
    />
  );
}
```

## Troubleshooting

### Widget Not Appearing

**Symptom**: No chat button visible on page

**Diagnostic steps**:

1. Browser DevTools → Network tab → verify `widget.js` loaded (200 status)
2. Console tab → check for errors (e.g., "Failed to load widget")
3. Verify `data-agent-id` matches agent ID from Twig (format: `agent_abc123`)
4. Check ad blocker not blocking (disable temporarily)

**Fix**: Correct agent ID, check script placement (must be in `<body>` not `<head>`)

***

**Symptom**: Widget shows "Agent not found"

**Cause**: Invalid agent ID or agent deleted

**Fix**: Verify agent exists: Twig → Agents → check list for agent ID

***

**Symptom**: Widget appears but styling broken

**Cause**: CSS conflicts or z-index issues

**Fix**: Add to your CSS:

```css
.twig-widget {
  z-index: 999999 !important;
}
```

## Next Steps

* [Browser Extension](/product/plugins/setup-browser-extension.md) - Desktop AI assistant
* [Zendesk App](/product/plugins/zendesk-app.md) - Support integration
* [REST API](/product/developer-api/overview.md) - Custom integrations
* [Agent Configuration](/product/overview/configuration.md) - Optimize your agent


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://help.twig.so/product/plugins/embeddable-widget.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
