> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thunderphone.com/llms.txt
> Use this file to discover all available pages before exploring further.

# CDN / Tag Skrip

> Tambahkan widget suara ThunderPhone ke situs web apa pun tanpa bundler

Build CDN membundel React secara internal, sehingga Anda dapat menggunakan widget di situs statis, WordPress, Webflow, atau halaman apa pun tempat Anda dapat menambahkan HTML. Tidak memerlukan npm, bundler, atau framework.

## URL CDN

<CodeGroup>
  ```html Latest (recommended) theme={null}
  <link rel="stylesheet" href="https://cdn.thunderphone.com/widget/latest/style.css" />
  <script src="https://cdn.thunderphone.com/widget/latest/widget.js"></script>
  ```

  ```html Pinned version theme={null}
  <!-- Each stable release also publishes an immutable /widget/vX.Y.Z/ path
       matching the @thunderphone/widget npm version (v1.1.2 at the time of
       writing). If you pin, you own updating the URL for new releases. -->
  <link rel="stylesheet" href="https://cdn.thunderphone.com/widget/v1.1.2/style.css" />
  <script src="https://cdn.thunderphone.com/widget/v1.1.2/widget.js"></script>
  ```
</CodeGroup>

<Tip>
  URL `latest` adalah URL yang dihasilkan oleh generator cuplikan embed dashboard. URL ini di-cache selama 5 menit dan otomatis menggunakan rilis stabil baru. Jalur `/widget/vX.Y.Z/` yang dipatok bersifat tidak dapat diubah dan di-cache untuk jangka panjang -- jika Anda mematok versi, sesuaikan versinya dengan rilis npm `@thunderphone/widget` yang Anda gunakan untuk pengembangan.
</Tip>

***

## Penggunaan Dasar

```html theme={null}
<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="https://cdn.thunderphone.com/widget/latest/style.css" />
</head>
<body>

  <div id="thunderphone"></div>

  <script src="https://cdn.thunderphone.com/widget/latest/widget.js"></script>
  <script>
    ThunderPhone.mount({
      element: '#thunderphone',
      publishableKey: 'pk_live_your_publishable_key',
    })
  </script>

</body>
</html>
```

Widget dipasang ke elemen target dan dirender sebagai **bilah berposisi tetap di sudut viewport** (default `bottom-right`, dikendalikan oleh opsi `position`). Elemen pemasangan hanya merupakan root React -- lokasinya di halaman tidak memengaruhi tempat widget muncul.

***

## Opsi Pemasangan

`ThunderPhone.mount()` menerima opsi yang sama seperti komponen React, ditambah properti `element`:

| Opsi             | Tipe                                                           | Wajib | Default                                    | Deskripsi                                                                                                                                                      |
| ---------------- | -------------------------------------------------------------- | ----- | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `element`        | `string \| HTMLElement`                                        | Ya    | --                                         | Selektor CSS (misalnya, `'#thunderphone'`) atau referensi elemen DOM.                                                                                          |
| `publishableKey` | `string`                                                       | Ya    | --                                         | Kunci API yang dapat dipublikasikan (`pk_live_...`). Agen ditentukan secara otomatis dari konfigurasi widget kunci tersebut.                                   |
| `theme`          | `'light' \| 'dark'`                                            | Tidak | `'light'`                                  | Skema warna.                                                                                                                                                   |
| `primaryColor`   | `string`                                                       | Tidak | `'#000000'` (terang) / `'#ffffff'` (gelap) | String warna CSS yang digunakan sebagai warna aksen.                                                                                                           |
| `title`          | `string`                                                       | Tidak | `'Voice assistant'`                        | Teks yang ditampilkan di bilah widget.                                                                                                                         |
| `position`       | `'bottom-right' \| 'bottom-left' \| 'top-right' \| 'top-left'` | Tidak | `'bottom-right'`                           | Posisi viewport tetap.                                                                                                                                         |
| `apiBase`        | `string`                                                       | Tidak | `'https://api.thunderphone.com/v1'`        | Penggantian URL dasar API.                                                                                                                                     |
| `language`       | `string`                                                       | Tidak | --                                         | Penggantian bahasa per sesi -- kode bahasa atau lokal seperti `en`, `es`, atau `fr-FR`. Jika tidak ditetapkan, bahasa yang dikonfigurasi untuk agen digunakan. |
| `voice`          | `string`                                                       | Tidak | --                                         | Penggantian suara per sesi -- nama suara seperti `maria`. Jika tidak ditetapkan, suara yang dikonfigurasi untuk agen digunakan.                                |
| `context`        | `string`                                                       | Tidak | --                                         | Konteks faktual halaman atau situs per sesi yang diteruskan ke agen. Dipotong di sisi server hingga 12.000 karakter.                                           |
| `onConnect`      | `() => void`                                                   | Tidak | --                                         | Dipanggil saat sesi suara terhubung.                                                                                                                           |
| `onDisconnect`   | `() => void`                                                   | Tidak | --                                         | Dipanggil saat sesi berakhir.                                                                                                                                  |
| `onError`        | `(error) => void`                                              | Tidak | --                                         | Dipanggil ketika terjadi kesalahan. Error memiliki field `error` (kode) dan `message`.                                                                         |
| `ringtone`       | `boolean \| string`                                            | Tidak | `false`                                    | Putar nada dering saat menghubungkan. `true` untuk nada dering default, atau string URL untuk audio kustom.                                                    |

***

## Pembersihan

`ThunderPhone.mount()` mengembalikan instance widget dengan metode pembersihan:

```html theme={null}
<script>
  var widget = ThunderPhone.mount({
    element: '#thunderphone',
    publishableKey: 'pk_live_your_publishable_key',
  })

  // Later, when you want to remove the widget:
  widget.unmount()

  // Or equivalently:
  widget.destroy()
</script>
```

`unmount()` dan `destroy()` melakukan hal yang sama -- keduanya memutuskan sesi suara aktif dan menghapus widget dari DOM. Gunakan yang paling sesuai dibaca dalam kode Anda.

<Note>
  Selalu bersihkan widget saat berpindah halaman dalam aplikasi satu halaman atau ketika elemen yang memuatnya dihapus. Ini memastikan sesi suara aktif diputuskan dengan benar.
</Note>

***

## Contoh

### Tema Gelap dengan Warna Kustom

```html theme={null}
<div id="thunderphone"></div>

<link rel="stylesheet" href="https://cdn.thunderphone.com/widget/latest/style.css" />
<script src="https://cdn.thunderphone.com/widget/latest/widget.js"></script>
<script>
  ThunderPhone.mount({
    element: '#thunderphone',
    publishableKey: 'pk_live_your_publishable_key',
    theme: 'dark',
    primaryColor: '#8b5cf6',
    title: 'Talk to our AI',
  })
</script>
```

### Posisi Kustom

```html theme={null}
<div id="thunderphone"></div>

<script src="https://cdn.thunderphone.com/widget/latest/widget.js"></script>
<script>
  ThunderPhone.mount({
    element: '#thunderphone',
    publishableKey: 'pk_live_your_publishable_key',
    position: 'bottom-left',
  })
</script>
```

### Dengan Callback Peristiwa

```html theme={null}
<div id="thunderphone"></div>

<link rel="stylesheet" href="https://cdn.thunderphone.com/widget/latest/style.css" />
<script src="https://cdn.thunderphone.com/widget/latest/widget.js"></script>
<script>
  ThunderPhone.mount({
    element: '#thunderphone',
    publishableKey: 'pk_live_your_publishable_key',
    onConnect: function () {
      console.log('Call started')
    },
    onDisconnect: function () {
      console.log('Call ended')
    },
    onError: function (error) {
      console.error('Widget error:', error.error, error.message)
    },
  })
</script>
```

### Dengan Nada Dering

```html theme={null}
<div id="thunderphone"></div>

<link rel="stylesheet" href="https://cdn.thunderphone.com/widget/latest/style.css" />
<script src="https://cdn.thunderphone.com/widget/latest/widget.js"></script>
<script>
  ThunderPhone.mount({
    element: '#thunderphone',
    publishableKey: 'pk_live_your_publishable_key',
    ringtone: true, // or a custom URL: 'https://example.com/ringtone.mp3'
  })
</script>
```

### Menggunakan Referensi Elemen DOM

```html theme={null}
<div id="thunderphone"></div>

<script src="https://cdn.thunderphone.com/widget/latest/widget.js"></script>
<script>
  var container = document.getElementById('thunderphone')

  ThunderPhone.mount({
    element: container,
    publishableKey: 'pk_live_your_publishable_key',
  })
</script>
```

### Integrasi WordPress / CMS

Tambahkan ini ke blok HTML Kustom atau footer tema Anda:

```html theme={null}
<link rel="stylesheet" href="https://cdn.thunderphone.com/widget/latest/style.css" />
<script src="https://cdn.thunderphone.com/widget/latest/widget.js"></script>

<div id="thunderphone-widget"></div>
<script>
  ThunderPhone.mount({
    element: '#thunderphone-widget',
    publishableKey: 'pk_live_your_publishable_key',
  })
</script>
```

<Tip>
  `<div>` dapat ditempatkan di mana saja -- ini hanya titik mount. Widget itu sendiri dirender sebagai overlay tetap di sudut viewport (ditetapkan oleh opsi `position`) dan tidak mengikuti aliran konten di sekitarnya.
</Tip>

***

## Pemecahan Masalah

<AccordionGroup>
  <Accordion title="Widget tidak muncul">
    Pastikan file CSS dan JS telah dimuat. Periksa konsol browser untuk kesalahan jaringan. Verifikasi bahwa elemen target ada di DOM sebelum memanggil `ThunderPhone.mount()`.
  </Accordion>

  <Accordion title="ThunderPhone tidak terdefinisi">
    Skrip belum dimuat. Pastikan tag `<script>` untuk `widget.js` muncul sebelum pemanggilan mount Anda, atau bungkus pemanggilan mount dalam listener `DOMContentLoaded`.
  </Accordion>

  <Accordion title="Kesalahan domain tidak diizinkan">
    Tambahkan domain Anda ke daftar domain yang diizinkan di pengaturan **Developer** pada [app.thunderphone.com](https://app.thunderphone.com). Ingat bahwa `localhost` selalu diizinkan.
  </Accordion>
</AccordionGroup>

***

## Langkah Selanjutnya

<CardGroup cols={2}>
  <Card title="Penataan Gaya" icon="palette" href="/id/widget/styling">
    Sesuaikan tampilan widget dengan properti kustom CSS.
  </Card>

  <Card title="Komponen React" icon="react" href="/id/widget/react">
    Menggunakan React? Integrasi komponen lebih sederhana.
  </Card>
</CardGroup>
