Widget Integration Guide

â„šī¸ Available on All Plans
Widget integration is available on all dialektai plans, including the free trial. No subscription required to get started.

The dialektai widget provides an embeddable chat interface that allows your users to query their data using natural language. This guide will walk you through integrating the widget into your application.

💡 Need More Control?
This guide covers widget integration with pre-built UI components. If you need to:
- Build custom chat interfaces with your own design
- Integrate into mobile applications (iOS, Android, React Native)
- Create backend-to-backend integrations

See the API Integration Guide for direct API access (requires Starter plan or higher).

Prerequisites

Before you begin, you'll need:

  1. A dialektai organization account
  2. A connected database
  3. A database-level API key (recommended for widget integration)

Quick Start

The simplest way to add dialektai to your application:

<!-- Add widget container -->
<div id="dialektai-chat"></div>

<!-- Load widget script -->
<script src="https://widget.dialektai.com/widget.js"></script>

<!-- Initialize the widget -->
<script>
  DialektAI.create('#dialektai-chat', {
    apiKey: 'pk_your_database_api_key_here',
    databaseId: 'your-database-uuid'
  });
</script>

That's it! The widget will appear in the specified container.

Step-by-Step Integration

Step 1: Get Your API Key

  1. Log in to your dialektai dashboard
  2. Navigate to Databases → Select your database → API Keys
  3. Click Create Database API Key
  4. Copy the generated key (it starts with pk_)
  5. Note your database ID from the database settings
💡 Database-level vs Organization-level API Keys
For widget integration, use database-level API keys (pk_*). These keys are:
- Scoped to a single database for better security
- Safe for client-side use (e.g., embedded in web pages)
- Available on all plans

Organization API keys (sk_*) provide broader access and are used for:
- Direct API integration without the widget
- Custom chat UI implementations
- Requires Starter plan or higher
- See API Integration Guide for details

Step 2: Add the Widget Script

Add the widget script to your HTML page, preferably before the closing </body> tag:

<!DOCTYPE html>
<html>
<head>
  <title>My Application</title>
</head>
<body>
  <!-- Your application content -->

  <!-- DialektAI Widget Container -->
  <div id="dialektai-chat"></div>

  <!-- dialektai Widget Script -->
  <script src="https://widget.dialektai.com/widget.js"></script>
  <script>
    DialektAI.create('#dialektai-chat', {
      apiKey: 'pk_your_api_key_here',
      databaseId: 'your-database-uuid',

      // Optional configuration
      theme: 'light',  // 'light', 'dark', or 'auto'
      position: 'bottom-right',  // Widget position
      placeholder: 'Type your question...',
    });
  </script>
</body>
</html>

Step 3: Configure Personality (Optional)

To use a specific AI personality for customized responses:

  1. Log in to the dialektai portal
  2. Navigate to Settings → AI Personalities
  3. Find the personality card you want to use
  4. Click the Copy button next to the Personality ID
  5. Use that UUID in your widget configuration:
DialektAI.create('#dialektai-chat', {
  apiKey: 'pk_your_api_key_here',
  databaseId: 'your-database-uuid',
  personalityId: 'a1201dbc-0d37-4c74-8ea0-235f7466162b'  // Paste your personality ID here
});
💡 Finding Personality IDs
Each personality card in the portal displays:
- Name: Analytics Expert, Customer Support Bot, etc.
- Response Style: CASUAL, PROFESSIONAL, TECHNICAL, etc.
- Personality ID: UUID with a copy button for easy access

You can create custom personalities with specific tones, instructions, and behaviors.

Step 4: Enable Tenant Filtering (Optional)

If your application serves multiple customers and you want each user to see only their own data, enable tenant filtering:

<script>
  DialektAI.create('#dialektai-chat', {
    apiKey: 'pk_your_api_key_here',
    databaseId: 'your-database-uuid',

    // Enable tenant filtering
    tenantId: getCurrentOrganizationId(),  // Customer/organization ID (required for filtering)
    scopeId: getCurrentUserId()             // User ID (for tracking or additional filtering)
  });

  function getCurrentOrganizationId() {
    // Your logic to get the current organization/customer ID
    // FLEXIBLE: Accepts any string format (integers, UUIDs, custom strings)
    // Examples: "82", "customer-123", "550e8400-e29b-41d4-a716-446655440000"
    // Used for row-level data filtering: WHERE customer_id = tenantId
    return window.currentUser?.organizationId || null;
  }

  function getCurrentUserId() {
    // Your logic to get the current user's ID
    // Can be ANY string format: number, UUID, "user-123", etc.
    // Examples: "550e8400-e29b-41d4-a716-446655440000", "user-123", "42"
    // - If tenant filtering DISABLED: Used for conversation tracking only
    // - If tenant filtering ENABLED: Applies additional SQL filtering
    return window.currentUser?.id || null;
  }
</script>
âš ī¸ Database Configuration Required
For tenant filtering to work, you must:
1. Set requires_organization_scoping = true on your database connection
2. Configure the tenant filter column (usually tenant_id, customer_id, or organization_id)
3. Provide tenantId in any string format (integers: "82", UUIDs, or custom strings: "customer-123")
4. Ensure this column exists in all tables you want to query

Understanding scopeId behavior:
- When tenant filtering is DISABLED: scopeId is used only for conversation tracking (no SQL filtering)
- When tenant filtering is ENABLED: scopeId applies additional SQL filtering on top of tenant filtering

Configuration Options

Basic Options

Option Type Required Default Description
apiKey string Yes - Database-level API key (pk_*)
databaseId string No - UUID of the database to query
theme string No 'light' Widget theme: 'light', 'dark', or 'auto'
position string No 'bottom-right' Widget position: 'bottom-right', 'bottom-left', 'top-right', 'top-left'

Display Options

Option Type Default Description
placeholder string 'Ask a question about your data...' Input field placeholder text
height number 600 Widget height in pixels
className string - Additional CSS classes for the widget container
customStyles object {} Custom CSS styles (React CSSProperties)

Advanced Options

Option Type Default Description
tenantId string - Customer/organization ID for row-level data filtering. Accepts any string format (integers, UUIDs, custom strings). Examples: "82", "customer-123", "550e8400-...". Requires requires_organization_scoping = true in DB config.
scopeId string - User/scope ID for conversation tracking and optional filtering. Accepts any string format (UUIDs, "user-123", numbers, etc.). Dual purpose: (1) Conversation tracking when tenant filtering disabled, (2) Additional SQL filtering when enabled
personalityId string - Use specific AI personality (UUID). Get from portal: Settings → AI Personalities → Copy ID
enableLinks boolean true Enable contextual links in responses
qaEnabled boolean true Enable Q&A functionality

Complete Configuration Example

DialektAI.create('#dialektai-chat', {
  // Required
  apiKey: 'pk_prod_abc123def456',

  // Optional: Database and personality
  databaseId: '550e8400-e29b-41d4-a716-446655440000',
  personalityId: 'a1201dbc-0d37-4c74-8ea0-235f7466162b',

  // Multi-tenant data filtering (requires DB config: requires_organization_scoping = true)
  tenantId: getCurrentOrganizationId(),  // Organization ID (any string format: "82", "customer-123", UUID)
  scopeId: getCurrentUserId(),            // User ID (any string: UUID, "user-123", etc.)

  // Display customization
  theme: 'auto',  // 'light', 'dark', or 'auto' (follows system preference)
  position: 'bottom-right',
  placeholder: 'Type your question about your data...',
  height: 600,

  // Features
  enableLinks: true,  // Show contextual links in responses
  qaEnabled: true,    // Enable Q&A functionality

  // Advanced styling (optional)
  className: 'my-custom-widget',
  customStyles: {
    borderRadius: '16px',
    boxShadow: '0 10px 40px rgba(0, 0, 0, 0.1)'
  }
});

Automatic Branding

💡 Available on Business+ Plans
Custom branding features (colors, logos) are available on Business and Enterprise plans. All plans include basic theme customization.

The dialektai widget automatically fetches and applies your organization's branding configuration. No additional code required - just configure your branding in the portal and it applies to all widgets using your API key.

What's Included

The widget automatically applies:

How It Works

  1. Configure branding in the dialektai Portal: Settings → Branding
  2. Upload your logo (PNG, SVG, or JPG, max 2MB)
  3. Customize colors using the color picker
  4. Configure widget settings (position, messages, etc.)
  5. Save changes - All widgets update automatically

That's it! Your branding applies instantly to all widgets.

Example

<!-- Widget automatically applies your organization's branding -->
<div id="dialektai-chat"></div>
<script src="https://widget.dialektai.com/widget.js"></script>
<script>
  DialektAI.create('#dialektai-chat', {
    apiKey: 'pk_prod_abc123def456',
    databaseId: '550e8400-e29b-41d4-a716-446655440000'
    // No additional configuration needed!
    // Widget fetches branding automatically from your organization settings
  });
</script>

The widget will display with:

Plan Requirements

Feature Starter Professional Business Enterprise
Custom Colors ❌ ❌ ✅ ✅
Custom Logo ❌ ❌ ✅ ✅
Widget Positioning ✅ ✅ ✅ ✅
Custom Placeholder ✅ ✅ ✅ ✅
Custom Greeting ✅ ✅ ✅ ✅
Hide "Powered by" ❌ ❌ ❌ ✅
Dark Mode Logo ❌ ❌ ✅ ✅

Branding Configuration

To configure your organization's branding:

  1. Log in to the dialektai Portal
  2. Navigate to Settings → Branding
  3. Upload your logo (recommended: 200x60 pixels, PNG or SVG)
  4. Optional: Upload a dark mode logo variant
  5. Choose your color palette using the color pickers
  6. Configure widget settings (position, messages)
  7. Preview your changes in the live widget preview
  8. Click Save Changes

Changes apply automatically to all widgets within 1-2 minutes (cached for performance).

💡 Branding Best Practices
- Logo: Use SVG for sharp display at any size, or PNG at 2x resolution (400x120)
- Colors: Ensure sufficient contrast for accessibility (WCAG AA standard)
- Dark Mode: Upload a separate logo optimized for dark backgrounds
- Testing: Use the live preview to test your branding before saving

Troubleshooting Branding

Logo not displaying:

Colors not applying:

Changes not visible:

Styling and Customization

â„šī¸ Advanced Customization
The automatic branding system handles most customization needs. Use custom CSS only if you need advanced styling beyond the branding settings.

Custom CSS

You can override the widget's styles using CSS:

<style>
  /* Customize widget button */
  .dialektai-widget-button {
    background-color: #your-brand-color !important;
    border-radius: 50% !important;
  }

  /* Customize chat window */
  .dialektai-widget-window {
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2) !important;
    border-radius: 16px !important;
  }

  /* Customize header */
  .dialektai-widget-header {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
  }

  /* Customize messages */
  .dialektai-message-user {
    background-color: #your-color !important;
  }
</style>

Programmatic Control

Control the widget programmatically via JavaScript:

// Create widget - returns widget ID (string)
const widgetId = DialektAI.create('#dialektai-chat', {
  apiKey: 'pk_your_api_key_here',
  databaseId: 'your-database-uuid'
});

console.log('Widget created with ID:', widgetId);

// Get widget instance (for advanced usage)
const instance = DialektAI.getInstance(widgetId);
console.log('Widget instance:', instance);

// Destroy widget when needed
DialektAI.destroy(widgetId);

// Auto-initialize widgets from DOM
// Finds all elements with [data-dialekt-ai-widget] attribute
const widgetIds = DialektAI.init();
console.log('Initialized widgets:', widgetIds);

Available Methods:

Method Parameters Returns Description
create() containerSelector: string, config: object string Create widget in specified container, returns widget ID
embed() config: EmbedConfig string Embed widget with advanced configuration
destroy() widgetId: string boolean Destroy widget instance, returns success status
getInstance() widgetId: string WidgetInstance | undefined Get widget instance for advanced usage
init() selector?: string string[] Auto-initialize widgets from DOM, returns widget IDs

Framework Integration Examples

React

import { useEffect, useRef } from 'react';

function App() {
  const widgetIdRef = useRef(null);
  const currentUser = useAuth(); // Your auth hook

  useEffect(() => {
    // Load widget script
    const script = document.createElement('script');
    script.src = 'https://widget.dialektai.com/widget.js';
    script.async = true;
    script.onload = () => {
      // Create widget and store the widget ID
      widgetIdRef.current = window.DialektAI.create('#dialektai-chat', {
        apiKey: process.env.REACT_APP_DIALEKTAI_API_KEY,
        databaseId: process.env.REACT_APP_DIALEKTAI_DB_ID,
        tenantId: String(currentUser?.organizationId),  // Any string format (integers, UUIDs, custom strings)
        scopeId: currentUser?.id,                        // Any string format (UUID, "user-123", etc.)
        theme: 'auto'
      });
    };
    document.body.appendChild(script);

    return () => {
      // Cleanup
      if (widgetIdRef.current) {
        window.DialektAI.destroy(widgetIdRef.current);
      }
      document.body.removeChild(script);
    };
  }, [currentUser]);

  return (
    <div className="App">
      {/* Your app content */}
      <div id="dialektai-chat"></div>
    </div>
  );
}

Vue.js

<template>
  <div id="app">
    <!-- Your app content -->
    <div id="dialektai-chat"></div>
  </div>
</template>

<script>
export default {
  name: 'App',
  data() {
    return {
      widgetId: null
    };
  },
  mounted() {
    const script = document.createElement('script');
    script.src = 'https://widget.dialektai.com/widget.js';
    script.async = true;
    script.onload = () => {
      // Create widget and store the widget ID
      this.widgetId = window.DialektAI.create('#dialektai-chat', {
        apiKey: process.env.VUE_APP_DIALEKTAI_API_KEY,
        databaseId: process.env.VUE_APP_DIALEKTAI_DB_ID,
        tenantId: String(this.$store.state.user.organizationId),  // Any string format (integers, UUIDs, custom strings)
        scopeId: this.$store.state.user.id,                        // Any string format (UUID, "user-123", etc.)
        theme: 'auto'
      });
    };
    document.body.appendChild(script);
  },
  beforeUnmount() {
    if (this.widgetId) {
      window.DialektAI.destroy(this.widgetId);
    }
  }
}
</script>

Next.js

// components/DialektaiWidget.tsx
'use client';

import { useEffect, useRef } from 'react';
import { useSession } from 'next-auth/react';

export default function DialektaiWidget() {
  const { data: session } = useSession();
  const widgetIdRef = useRef<string | null>(null);

  useEffect(() => {
    const script = document.createElement('script');
    script.src = 'https://widget.dialektai.com/widget.js';
    script.async = true;

    script.onload = () => {
      // Create widget and store the widget ID
      widgetIdRef.current = window.DialektAI.create('#dialektai-chat', {
        apiKey: process.env.NEXT_PUBLIC_DIALEKTAI_API_KEY!,
        databaseId: process.env.NEXT_PUBLIC_DIALEKTAI_DB_ID!,
        tenantId: String(session?.user?.organizationId),  // Any string format (integers, UUIDs, custom strings)
        scopeId: session?.user?.id,                        // Any string format (UUID, "user-123", etc.)
        theme: 'auto'
      });
    };

    document.body.appendChild(script);

    return () => {
      if (widgetIdRef.current) {
        window.DialektAI.destroy(widgetIdRef.current);
      }
      document.body.removeChild(script);
    };
  }, [session]);

  return <div id="dialektai-chat"></div>;
}

// app/layout.tsx
import DialektaiWidget from '@/components/DialektaiWidget';

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <DialektaiWidget />
      </body>
    </html>
  );
}

Security Best Practices

When integrating the dialektai widget, follow security best practices to protect your API keys and users' data.

For comprehensive security guidelines including key management, rotation schedules, and secure storage, see the API Keys Guide.

Key Points for Widget Integration:

1. Use Database-Level API Keys

Always use database-level API keys (pk_*) for widget integration, not organization-level keys (sk_*).

See API Integration Guide for when to use organization keys.

2. Enable Tenant Filtering for Multi-Tenant Apps

For multi-tenant applications, always enable tenant filtering to ensure data isolation:

DialektAI.create('#dialektai-chat', {
  apiKey: 'pk_prod_abc123',
  databaseId: 'your-db-id',
  tenantId: String(getAuthenticatedOrganizationId()),  // Any string format: "82", "customer-123", UUID
  scopeId: getAuthenticatedUserId()                     // Any string (UUID, "user-123", etc.)
});

Important:

3. Additional Best Practices

Troubleshooting

Widget Not Appearing

Check:

Tenant Filtering Not Working

Check:

Test with cURL:

curl -X POST https://api.dialektai.com/api/v1/chat/message \
  -H "X-API-Key: pk_your_api_key_here" \
  -H "X-Tenant-Id: 123" \
  -H "Content-Type: application/json" \
  -d '{"message": "test"}'

CORS Errors

Solution:
Add your domain to allowed origins in dialektai dashboard:

  1. Database Settings → API Keys → Allowed Origins
  2. Add https://yourdomain.com

Widget Button Covered by Other Elements

Solution:
Adjust z-index in CSS:

.dialektai-widget-button {
  z-index: 9999 !important;
}

Next Steps