DocumentationWidget Guide

Widget Guide

The Jhunkoo AI widget is a self-contained script that adds a conversational AI chat interface to any website. This guide covers every supported installation method — from a single script tag to framework-specific integrations and Google Tag Manager.


The safest and most performant way to load the widget. This method is asynchronous and will never block your website’s main thread from rendering.

<!-- 1. Place this anywhere in your HTML (optimally in <head> or before </body>) -->
<script>
  // Establish the queue so commands work even before the script loads
  window.Jhunkoo =
    window.Jhunkoo ||
    function () {
      ;(window.Jhunkoo.q = window.Jhunkoo.q || []).push(Array.from(arguments))
    }
 
  // Initialize with your Publishable Key
  Jhunkoo('init', { publishableKey: 'YOUR_PUBLISHABLE_KEY' })
</script>
 
<!-- 2. Load the widget asynchronously -->
<script src="https://cdn.jhunkoo.ai/widget.js" async></script>

2. No-Code / Synchronous Method

If you prefer a single-line installation without writing any JavaScript, use the dataset approach.

⚠️

By omitting the async flag, the browser will wait for the widget to download before finishing rendering the page.

<script
  src="https://cdn.jhunkoo.ai/widget.js"
  data-pk="YOUR_PUBLISHABLE_KEY"
></script>

3. Inline Container (Embedded Mode)

By default, the widget floats in the bottom right corner of the screen. You can force the widget to render inside a specific block on your page (like a sidebar or a dedicated chat page).

<!-- Create the destination container anywhere in your layout -->
<div id="jhunkoo-chat-wrapper" style="height: 600px; width: 100%;"></div>
 
<script>
  window.Jhunkoo =
    window.Jhunkoo ||
    function () {
      ;(window.Jhunkoo.q = window.Jhunkoo.q || []).push(Array.from(arguments))
    }
 
  // Pass the CSS selector of your container
  Jhunkoo('init', {
    publishableKey: 'YOUR_PUBLISHABLE_KEY',
    container: '#jhunkoo-chat-wrapper', // <-- Targets the div above
  })
</script>
<script src="https://cdn.jhunkoo.ai/widget.js" async></script>

4. Lazy-Loading (Performance Optimized)

To achieve a perfect Lighthouse / Pagespeed score, you can instruct the SDK to wait until the user interacts with the page (scrolling, clicking, moving the mouse) before it downloads the heavy chat interface.

<script
  src="https://cdn.jhunkoo.ai/widget.js"
  data-pk="YOUR_PUBLISHABLE_KEY"
  data-lazy="interaction"
></script>

5. Identifying Users (Optional Metadata)

If you want to attach custom data to a chat session, you can pass an optional JSON metadata string to the widget. This can be anything: user identity (like email or user ID), the current page context, pricing plan, or any other arbitrary metadata you want your AI agent to have access to.

Method A: Via Javascript Config (Async)

<script>
  window.Jhunkoo =
    window.Jhunkoo ||
    function () {
      ;(window.Jhunkoo.q = window.Jhunkoo.q || []).push(Array.from(arguments))
    }
  Jhunkoo('init', {
    publishableKey: 'YOUR_PUBLISHABLE_KEY',
    metadata: '{"user_id": "123", "email": "[email protected]"}',
  })
</script>
<script src="https://cdn.jhunkoo.ai/widget.js" async></script>

Method B: Via HTML Attributes (Sync/No-Code)

<script
  src="https://cdn.jhunkoo.ai/widget.js"
  data-pk="YOUR_PUBLISHABLE_KEY"
  data-metadata='{"user_id": "123", "email": "[email protected]"}'
></script>

6. Google Tag Manager (GTM) / Segment

GTM automatically strips custom script attributes (like async or data-pk) from the UI. To install the widget reliably via GTM, create a Custom HTML Tag and use this exact dynamic injection snippet:

<script>
  // 1. Establish the robust command queue
  window.Jhunkoo =
    window.Jhunkoo ||
    function () {
      ;(window.Jhunkoo.q = window.Jhunkoo.q || []).push(Array.from(arguments))
    }
 
  // 2. Initialize the widget
  window.Jhunkoo('init', { publishableKey: 'YOUR_PUBLISHABLE_KEY' })
 
  // 3. (Optional) Pass GTM DataLayer variables!
  // window.Jhunkoo('setUser', { email: '{{User_Email}}' });
 
  // 4. Inject script dynamically
  var script = document.createElement('script')
  script.src = 'https://cdn.jhunkoo.ai/widget.js'
  script.async = true
  document.head.appendChild(script)
</script>

Framework Integration Guides

React / Next.js (App Router)

For modern Next.js applications, use the next/script component inside your app/layout.tsx to optimize load priority safely across client hydration boundaries.

import Script from 'next/script'
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang='en'>
      <body>
        {children}
 
        {/* Jhunkoo AI Embed */}
        <Script
          src='https://cdn.jhunkoo.ai/widget.js'
          strategy='lazyOnload' // or 'afterInteractive'
          data-pk='YOUR_PUBLISHABLE_KEY'
          data-lazy='interaction'
        />
      </body>
    </html>
  )
}

Vue 3

In a plain Vue 3 application, inject the script dynamically inside the onMounted lifecycle hook of your root App.vue.

<script setup>
import { onMounted } from 'vue'
 
onMounted(() => {
  const s = document.createElement('script')
  s.src = 'https://cdn.jhunkoo.ai/widget.js'
  s.setAttribute('data-pk', 'YOUR_PUBLISHABLE_KEY')
  s.async = true
  document.head.appendChild(s)
})
</script>

Vue 3 / Nuxt 3

Inject the script globally within your app.vue using the useHead composable.

<script setup>
useHead({
  script: [
    {
      src: 'https://cdn.jhunkoo.ai/widget.js',
      'data-pk': 'YOUR_PUBLISHABLE_KEY',
      'data-lazy': 'interaction',
      defer: true,
    },
  ],
})
</script>
 
<template>
  <div>
    <NuxtLayout>
      <NuxtPage />
    </NuxtLayout>
  </div>
</template>

Astro

Drop the inline script tag right before the closing </body> tag of your shared Layout.astro file.

---
// src/layouts/Layout.astro
interface Props {
  title: string;
}
const { title } = Astro.props;
---
 
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>{title}</title>
  </head>
  <body>
    <slot />
 
    <!-- Jhunkoo AI Embed -->
    <script
      is:inline
      src="https://cdn.jhunkoo.ai/widget.js"
      data-pk="YOUR_PUBLISHABLE_KEY"
    ></script>
  </body>
</html>

Svelte / SvelteKit

Place the script directly into the <svelte:head> block of your main layout file (src/routes/+layout.svelte).

<svelte:head>
  <!-- Jhunkoo AI Embed -->
  <script
    src="https://cdn.jhunkoo.ai/widget.js"
    data-pk="YOUR_PUBLISHABLE_KEY"
    data-lazy="interaction"
    defer
  ></script>
</svelte:head>
 
<main>
  <slot />
</main>

Single Page Application (SPA) Security & Routing

If your website is a Single Page App (React, Vue, Angular) and your users log in and out, you must clear the widget securely to prevent chat history from leaking between users.

Simply call the destroy command when the user logs out:

// When user clicks Logout
function handleLogout() {
  window.Jhunkoo('destroy')
}

If you ever need to manually assign a different user or tenant without refreshing the page, just call init again with a new key. The SDK handles completely destroying the old interface on its own:

// Switches tenants cleanly and safely
window.Jhunkoo('init', { publishableKey: 'NEW_PUBLISHABLE_KEY' })