TakonAI/Widget Documentation
v1

Quick Start

Tambahkan satu baris script tag ke halaman HTML Anda. Widget akan otomatis muncul sebagai floating button di kanan bawah halaman.

<script
  src="https://cdn.ztakonai.com/widget.js"
  data-widget-id="wgt_abc123"
  data-api-key="tk_live_xxxx">
</script>
html

Script Tag Attributes

AttributeRequiredDescription
data-widget-id*stringWidget ID dari TakonAI dashboard (format: wgt_...)
data-api-key*stringPublic API key dari TakonAI dashboard (format: tk_live_...)
data-base-urlstringOverride URL widget — hanya untuk development/staging. Default: https://cdn.ztakonai.com

Embed Guide

Widget bekerja dengan menginjeksi sebuah <iframe> ke halaman Anda. Komunikasi antara halaman host dan widget dilakukan via postMessage.

Cara Kerja

  1. Script tag loader dieksekusi saat halaman load.
  2. Loader membuat floating bubble button (fixed, bottom-right, z-index 9990).
  3. Saat user klik bubble, iframe /embed diinjeksi dan chat panel dibuka.
  4. Iframe berkomunikasi dengan halaman host via postMessage.
  5. window.Takonai tersedia untuk kontrol programmatic setelah script dimuat.

Inisialisasi dengan User Context

Panggil window.Takonai.init() setelah halaman selesai dimuat untuk menghubungkan widget dengan sesi user Anda.

window.Takonai.init({
  externalId: 'user_123',       // ID unik user dari sistem Anda
  currentStep: 1,               // Step aktif saat ini (opsional)
  context: {                    // Data konteks tambahan (opsional)
    planType: 'pro',
    cartTotal: 150000,
  },
});
js

Mengelola Banyak Step (Multi-Step)

Untuk halaman yang memiliki urutan step — seperti form checkout atau pendaftaran wizard — Anda dapat memisahkan konfigurasi form menjadi beberapa step di dashboard TakonAI.

Di sisi frontend, Anda perlu memberitahu widget setiap kali user berpindah step menggunakan setStep(). Dengan cara ini, AI hanya memproses Tool/Form Filling yang sesuai dengan form di step yang sedang aktif.

Cara kerja multi-step

  1. Buat konfigurasi widget di dashboard dengan beberapa step, masing-masing memiliki form yang berbeda.
  2. Saat halaman pertama dimuat, panggil init({ currentStep: 1 }).
  3. Setiap kali user pindah ke step berikutnya, panggil setStep(n) agar AI tahu step mana yang aktif.
  4. AI hanya akan mengisi form di step yang sedang aktif — tidak ada kebocoran data antar step.
// Step 1 — saat halaman pertama load
window.Takonai.init({
  externalId: 'usr_123',
  currentStep: 1,
});

// Step 2 — saat user klik tombol "Lanjut"
function goToStep2() {
  showStep(2); // tampilkan form step 2 di halaman Anda

  window.Takonai.setStep(2, {
    // opsional: kirim data dari step sebelumnya sebagai konteks
    buyerName: document.querySelector('[name="full_name"]').value,
  });
}

// Step 3 — opsional, lanjut ke step berikutnya
function goToStep3() {
  showStep(3);
  window.Takonai.setStep(3);
}
js

Gunakan callback onFill untuk mengisi form yang tepat berdasarkan step yang dikirim AI:

window.Takonai.onFill = ({ step, formName, data }) => {
  // Pilih form yang sesuai dengan step aktif
  const formMap = {
    1: document.getElementById('form-buyer'),
    2: document.getElementById('form-shipping'),
    3: document.getElementById('form-payment'),
  };
  const formEl = formMap[step];
  if (!formEl) return;

  Object.entries(data).forEach(([field, value]) => {
    const el = formEl.querySelector('[name="' + field + '"]');
    if (el) el.value = value;
  });
};
js

window.Takonai

Global object yang di-expose oleh widget loader script. Tersedia setelah script tag dimuat.

init(opts)

Method

Inisialisasi widget dengan konteks user. Harus dipanggil sebelum widget bisa berinteraksi dengan data sesi Anda. Widget akan mengirim TAKONAI_INIT ke iframe dan menerima konfirmasi TAKONAI_INIT_ACK.

window.Takonai.init(opts: TakonaiInitOptions): void

interface TakonaiInitOptions {
  externalId: string;                  // Required — ID user dari sistem Anda
  currentStep?: number;                // Optional — step aktif (default: 1)
  context?: Record<string, unknown>;   // Optional — data konteks dinamis
  welcomeMessage?: string;             // Optional — override pesan sapaan dari dashboard
}
ts

Parameters

NameTypeDescription
externalId*stringID unik user dari sistem Anda. Digunakan untuk identifikasi sesi.
currentStepnumberStep aktif saat init. Default: 1.
contextobjectData konteks bebas yang diteruskan ke AI (kategori produk, nilai form, dll).
welcomeMessagestringOverride pesan sapaan yang dikonfigurasi di dashboard. Berguna untuk personalisasi per-user atau per-halaman.

Example

window.Takonai.init({
  externalId: 'usr_4891',
  currentStep: 2,
  context: {
    category: 'electronics',
    priceRange: '500k-1jt',
  },
  welcomeMessage: 'Halo, Budi! Ada yang bisa kami bantu hari ini?',
});
js

setStep(step, context?)

Method

Update step aktif widget, misalnya saat user berpindah halaman atau mengisi form multi-step. Mengirim pesan TAKONAI_STEP_CHANGED ke iframe.

window.Takonai.setStep(step: number, context?: Record<string, unknown>): void
ts

Parameters

NameTypeDescription
step*numberNomor step baru (1-indexed, sesuai konfigurasi widget di dashboard).
contextobjectKonteks baru yang akan menggantikan konteks sebelumnya.
// User pindah ke step checkout pengiriman
window.Takonai.setStep(2, {
  selectedItems: ['item_001', 'item_002'],
  total: 320000,
});
js

setContext(context)

Method

Update konteks tanpa mengubah step aktif. Berguna saat data halaman berubah tapi posisi step tidak berubah. Mengirim TAKONAI_CONTEXT_UPDATE.

window.Takonai.setContext(context: Record<string, unknown>): void
ts
// User memilih produk lain tanpa pindah step
window.Takonai.setContext({
  selectedProduct: 'SKU-9921',
  color: 'black',
  size: 'XL',
});
js

open() / close()

Method

Buka atau tutup chat panel secara programmatic, tanpa user harus klik bubble button.

window.Takonai.open(): void
window.Takonai.close(): void
ts
// Buka widget otomatis setelah 5 detik
setTimeout(() => {
  window.Takonai.open();
}, 5000);

// Tutup widget setelah form selesai diisi
window.Takonai.onFill = (payload) => {
  fillMyForm(payload.data);
  window.Takonai.close();
};
js

onFill(payload)

Callback

Dipanggil ketika AI berhasil mengisi form (tool use selesai). Gunakan callback ini untuk mengisi form di halaman Anda dengan data yang dikirim AI.

window.Takonai.onFill = (payload: TakonaiFillPayload) => void

interface TakonaiFillPayload {
  step: number;                        // Step yang di-fill
  formName: string;                    // Nama form (dari konfigurasi widget)
  data: Record<string, unknown>;       // Field-value hasil fill AI
}
ts

Parameters

FieldTypeDescription
stepnumberNomor step yang baru saja di-fill oleh AI.
formNamestringNama form sesuai konfigurasi widget di dashboard.
dataobjectKey-value hasil isian AI. Key sesuai field name di konfigurasi form.

Example

window.Takonai.onFill = ({ step, formName, data }) => {
  console.log('Form filled:', formName, data);

  // Isi field HTML dengan data dari AI
  Object.entries(data).forEach(([field, value]) => {
    const el = document.querySelector(`[name="${field}"]`);
    if (el) el.value = value;
  });
};
js

onError(payload)

Callback

Dipanggil ketika terjadi error di dalam widget (streaming gagal, config tidak ditemukan, dll).

window.Takonai.onError = (payload: TakonaiErrorPayload) => void

interface TakonaiErrorPayload {
  code: string;     // Error code, contoh: 'STREAM_ERROR', 'CONFIG_NOT_FOUND'
  message: string;  // Pesan error human-readable
}
ts
window.Takonai.onError = ({ code, message }) => {
  console.error('[TakonAI]', code, message);
  // Log ke Sentry, tampilkan fallback UI, dll
};
js

sendImage(url)

Method

Lampirkan gambar dari URL publik ke composer chat widget secara programatik. Gambar belum dikirim sampai user mengetik pesan dan menekan tombol Send — sehingga Anda bisa pra-lampirkan gambar produk sebelum user mulai chat.

URL harus menggunakan skema https:// dan dapat diakses publik, karena Anthropic akan men-fetch URL tersebut langsung saat memproses pesan.

window.Takonai.sendImage(url: string): void
ts

Parameters

NameTypeDescription
url*stringURL gambar publik (https:// wajib). Tidak mendukung base64 atau URL yang memerlukan autentikasi.

Example

// Pra-lampirkan foto produk saat user membuka detail produk
window.Takonai.sendImage('https://cdn.toko.com/products/kaos-putih.jpg');

// User bisa langsung tanya "berapa harga ini?" dan AI sudah bisa melihat gambarnya
js

Catatan

  • Maksimal 3 gambar per pesan. Memanggil sendImage saat sudah mencapai batas akan diabaikan.
  • Gambar yang sudah dilampirkan via sendImage akan dibersihkan otomatis setelah pesan terkirim.
  • Callback onImageUpload akan dipanggil setiap kali gambar berhasil dilampirkan, termasuk dari sendImage.

onImageUpload(payload)

Callback

Dipanggil setiap kali gambar berhasil dilampirkan ke composer chat — baik via tombol paperclip di widget, paste dari clipboard, drag-and-drop, maupun panggilan sendImage().

window.Takonai.onImageUpload = (payload: TakonaiImagePayload) => void

interface TakonaiImagePayload {
  url: string;        // URL publik gambar di Supabase Storage (atau URL asli untuk sendImage)
  mimeType: string;   // MIME type gambar, contoh: "image/jpeg"
  sizeBytes: number;  // Ukuran file dalam bytes (0 untuk sendImage)
  fileName: string;   // Nama file asli
}
ts

Parameters

FieldTypeDescription
urlstringURL gambar yang siap diakses. Untuk upload file, ini adalah URL Supabase Storage. Untuk sendImage, ini adalah URL yang dipass.
mimeTypestringMIME type gambar (image/jpeg, image/png, image/webp, image/gif).
sizeBytesnumberUkuran file dalam bytes. Bernilai 0 untuk gambar yang dilampirkan via sendImage(url).
fileNamestringNama file asli dari upload, atau bagian akhir URL untuk sendImage.

Example

// Analytics: lacak setiap gambar yang diupload user
window.Takonai.onImageUpload = ({ url, mimeType, sizeBytes, fileName }) => {
  console.log('Image attached:', fileName, '(' + Math.round(sizeBytes / 1024) + 'KB)');

  // Contoh: tampilkan preview di sidebar halaman host
  document.getElementById('image-preview').src = url;
};
js

postMessage Events

Widget berkomunikasi dengan halaman host via window.postMessage. Anda dapat meng-intercept event ini langsung jika perlu kontrol lebih dalam.

Host → Widget

Pesan yang dikirim dari halaman host ke iframe widget.

TypePayloadDikirim oleh
TAKONAI_INITTakonaiInitOptionswindow.Takonai.init()
TAKONAI_STEP_CHANGED{ currentStep, context? }window.Takonai.setStep()
TAKONAI_CONTEXT_UPDATE{ context }window.Takonai.setContext()
TAKONAI_SEND_IMAGE{ url: string }window.Takonai.sendImage()

Widget → Host

Pesan yang dikirim dari iframe widget ke halaman host.

TypePayloadKapan dikirim
TAKONAI_READY{}Widget iframe selesai dimuat dan config berhasil di-fetch.
TAKONAI_INIT_ACK{ widgetName, steps }Setelah host memanggil init() dan widget memproses request.
TAKONAI_FILLTakonaiFillPayloadAI berhasil menggunakan tool untuk mengisi form.
TAKONAI_IMAGE_UPLOADEDTakonaiImagePayloadGambar berhasil dilampirkan (dari upload file atau sendImage).
TAKONAI_ERRORTakonaiErrorPayloadTerjadi error di dalam widget.

Intercept Manual

// Intercept langsung jika perlu (biasanya tidak diperlukan)
window.addEventListener('message', (event) => {
  if (event.data?.type === 'TAKONAI_FILL') {
    console.log('Fill event:', event.data.payload);
  }
});
js

Type Reference

// Opsi untuk window.Takonai.init()
interface TakonaiInitOptions {
  externalId: string;
  currentStep?: number;
  context?: Record<string, unknown>;
}

// Payload dari callback onFill
interface TakonaiFillPayload {
  step: number;
  formName: string;
  data: Record<string, unknown>;
}

// Payload dari callback onError
interface TakonaiErrorPayload {
  code: string;
  message: string;
}

// Payload dari callback onImageUpload
interface TakonaiImagePayload {
  url: string;
  mimeType: string;
  sizeBytes: number;
  fileName: string;
}

// Global window.Takonai object
interface TakonaiWidget {
  init(opts: TakonaiInitOptions): void;
  setStep(step: number, context?: Record<string, unknown>): void;
  setContext(context: Record<string, unknown>): void;
  open(): void;
  close(): void;
  sendImage(url: string): void;
  onFill: ((payload: TakonaiFillPayload) => void) | null;
  onError: ((payload: TakonaiErrorPayload) => void) | null;
  onImageUpload: ((payload: TakonaiImagePayload) => void) | null;
}

declare global {
  interface Window {
    Takonai: TakonaiWidget;
  }
}
ts

Dashboard Configuration Guide

Sebelum widget bisa mengisi form, Anda perlu mengkonfigurasi Form di TakonAI dashboard. Form mendefinisikan tool yang digunakan AI untuk mengekstrak data dari percakapan dan mengirimkannya ke halaman Anda.

Konsep: Form sebagai AI Tool

Setiap form di TakonAI adalah sebuah Anthropic tool. Saat AI memutuskan data sudah cukup untuk mengisi form, ia akan memanggil tool tersebut dengan output berupa JSON yang sesuai skema yang Anda definisikan. Output inilah yang dikirim via callback onFill ke halaman Anda.

Struktur Payload Kompleks (Nested JSON)

Anthropic Tool Schema sepenuhnya mendukung stuktur nested seperti objects dan arrays. Ini sangat bermanfaat ketika Anda ingin output payload dari onFill siap pakai untuk request ke backend API Anda (seperti format produk dengan berbagai atribut dan varian).

Berikut adalah contoh konversi payload untuk produk (Tiket Wisata) yang kompleks:

{
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "description": "Nama produk tiket"
    },
    "sku": {
      "type": "string",
      "description": "Kode SKU tiket"
    },
    "description": {
      "type": "string",
      "description": "Deskripsi lengkap terkait produk wisata"
    },
    "category_id": {
      "type": "integer",
      "description": "ID kategori produk (misal: 3 untuk tiket wisata)"
    },
    "price": {
      "type": "number",
      "description": "Harga jual"
    },
    "publish_rate": {
      "type": "number",
      "description": "Harga coret / harga publish"
    },
    "product_advantages_item": {
      "type": "array",
      "description": "Keunggulan produk",
      "items": {
        "type": "object",
        "properties": {
          "name": { "type": "string" }
        }
      }
    },
    "attributes": {
      "type": "array",
      "description": "Atribut varian (contoh: paket, waktu)",
      "items": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "items": {
            "type": "array",
            "items": { "type": "string" }
          },
          "priority": { "type": "integer" }
        }
      }
    },
    "varian_items": {
      "type": "array",
      "description": "Kombinasi hasil varian beserta spesifikasinya",
      "items": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "sku": { "type": "string" },
          "price": { "type": "number" },
          "stok": { "type": "integer" }
        }
      }
    },
    "tracking_adds": {
      "type": "object",
      "description": "Pengaturan tracking pixel",
      "properties": {
        "all_event": { "type": "boolean" },
        "facebook_pixel": {
          "type": "object",
          "properties": {
            "pixel_id": { "type": "array", "items": { "type": "string"} },
            "event": { "type": "array", "items": { "type": "string"} }
          }
        }
      }
    }
  },
  "required": ["name", "sku", "description", "price", "attributes", "varian_items"]
}
json

Tips Penting: Untuk skema yang sangat kompleks seperti pembuatan varian produk, disarankan menggunakan system prompt tambahan di dashboard agar AI tahu bagaimana cara mengisi field tertentu (misal: "Pastikan sku formatnya kebab-case"). Anda juga bisa langsung mem-pass sebagian struktur default (seperti properti tracking_adds) tersebut pada halaman host Anda setelah menerima callback onFill, alih-alih memaksa AI membuat keseluruhan payload statis.


Full Example

Contoh integrasi lengkap untuk form checkout multi-step. Widget di-init saat user login, step di-update saat user berpindah halaman, dan form diisi otomatis saat AI selesai.

<!DOCTYPE html>
<html>
<head>
  <title>Checkout</title>
</head>
<body>

  <!-- Step 1: Data Pembeli -->
  <form id="form-buyer">
    <input name="full_name" placeholder="Nama Lengkap" />
    <input name="email" placeholder="Email" />
    <input name="phone" placeholder="No. HP" />
    <button type="button" onclick="goToStep2()">Lanjut</button>
  </form>

  <!-- Step 2: Alamat Pengiriman -->
  <form id="form-shipping" style="display:none">
    <input name="address" placeholder="Alamat" />
    <input name="city" placeholder="Kota" />
    <input name="postal_code" placeholder="Kode Pos" />
    <button type="submit">Bayar</button>
  </form>

  <!-- 1. Embed widget -->
  <script
    src="https://cdn.ztakonai.com/widget.js"
    data-widget-id="wgt_abc123"
    data-api-key="tk_live_xxxx">
  </script>

  <script>
    // 2. Init saat halaman load
    window.Takonai.init({
      externalId: 'usr_' + currentUserId,
      currentStep: 1,
      context: {
        cartItems: 3,
        totalAmount: 450000,
      },
    });

    // 3. Isi form otomatis saat AI selesai
    window.Takonai.onFill = ({ step, formName, data }) => {
      const formEl = step === 1
        ? document.getElementById('form-buyer')
        : document.getElementById('form-shipping');

      Object.entries(data).forEach(([field, value]) => {
        const el = formEl.querySelector('[name="' + field + '"]');
        if (el) el.value = value;
      });
    };

    // 4. Handle error
    window.Takonai.onError = ({ code, message }) => {
      console.error('[TakonAI Error]', code, message);
    };

    // 5. Update step saat user pindah halaman
    function goToStep2() {
      document.getElementById('form-buyer').style.display = 'none';
      document.getElementById('form-shipping').style.display = 'block';

      window.Takonai.setStep(2, {
        buyerName: document.querySelector('[name="full_name"]').value,
      });
    }
  </script>

</body>
</html>
html