> ## 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 / Etiqueta de script

> Agrega el widget de voz de ThunderPhone a cualquier sitio web sin un empaquetador

La compilación de CDN incluye React internamente, por lo que puedes usar el widget en sitios estáticos, WordPress, Webflow o cualquier página donde puedas agregar HTML. No se requiere npm, empaquetador ni framework.

## URL de 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>
  Las URL de `latest` son las que genera el generador de fragmentos de inserción del panel. Se almacenan en caché durante 5 minutos e incorporan automáticamente nuevas versiones estables. Las rutas fijadas `/widget/vX.Y.Z/` son inmutables y se almacenan en caché a largo plazo -- si fijas una versión, haz que coincida con la versión de npm de `@thunderphone/widget` con la que desarrollas.
</Tip>

***

## Uso básico

```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>
```

El widget se monta en el elemento de destino y se muestra como una **barra de posición fija en una esquina de la ventana gráfica** (el valor predeterminado es `bottom-right`, controlado por la opción `position`). El elemento de montaje solo es la raíz de React -- su ubicación en la página no afecta dónde aparece el widget.

***

## Opciones de montaje

`ThunderPhone.mount()` acepta las mismas opciones que el componente de React, además de la propiedad `element`:

| Opción           | Tipo                                                           | Obligatorio | Predeterminado                             | Descripción                                                                                                                                                                   |
| ---------------- | -------------------------------------------------------------- | ----------- | ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `element`        | `string \| HTMLElement`                                        | Sí          | --                                         | Selector CSS (p. ej., `'#thunderphone'`) o una referencia a un elemento DOM.                                                                                                  |
| `publishableKey` | `string`                                                       | Sí          | --                                         | Clave de API publicable (`pk_live_...`). El agente se resuelve automáticamente a partir de la configuración del widget de la clave.                                           |
| `theme`          | `'light' \| 'dark'`                                            | No          | `'light'`                                  | Esquema de colores.                                                                                                                                                           |
| `primaryColor`   | `string`                                                       | No          | `'#000000'` (claro) / `'#ffffff'` (oscuro) | Cadena de color CSS utilizada como color de acento.                                                                                                                           |
| `title`          | `string`                                                       | No          | `'Voice assistant'`                        | Texto mostrado en la barra del widget.                                                                                                                                        |
| `position`       | `'bottom-right' \| 'bottom-left' \| 'top-right' \| 'top-left'` | No          | `'bottom-right'`                           | Posición fija en la ventana gráfica.                                                                                                                                          |
| `apiBase`        | `string`                                                       | No          | `'https://api.thunderphone.com/v1'`        | Anulación de la URL base de la API.                                                                                                                                           |
| `language`       | `string`                                                       | No          | --                                         | Anulación de idioma por sesión -- un código de idioma o configuración regional como `en`, `es` o `fr-FR`. Cuando no se establece, se aplica el idioma configurado del agente. |
| `voice`          | `string`                                                       | No          | --                                         | Anulación de voz por sesión -- un nombre de voz como `maria`. Cuando no se establece, se aplica la voz configurada del agente.                                                |
| `context`        | `string`                                                       | No          | --                                         | Contexto factual de página o sitio por sesión que se pasa al agente. Se trunca del lado del servidor a 12.000 caracteres.                                                     |
| `onConnect`      | `() => void`                                                   | No          | --                                         | Se llama cuando se conecta la sesión de voz.                                                                                                                                  |
| `onDisconnect`   | `() => void`                                                   | No          | --                                         | Se llama cuando termina la sesión.                                                                                                                                            |
| `onError`        | `(error) => void`                                              | No          | --                                         | Se llama cuando ocurren errores. El error tiene los campos `error` (código) y `message`.                                                                                      |
| `ringtone`       | `boolean \| string`                                            | No          | `false`                                    | Reproduce un tono de llamada durante la conexión. `true` para el tono de llamada predeterminado o una cadena de URL para audio personalizado.                                 |

***

## Limpieza

`ThunderPhone.mount()` devuelve una instancia del widget con métodos de limpieza:

```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>
```

Tanto `unmount()` como `destroy()` hacen lo mismo -- desconectan cualquier sesión de voz activa y eliminan el widget del DOM. Usa el que se lea mejor en tu código.

<Note>
  Siempre limpia el widget al navegar fuera de aplicaciones de una sola página o cuando se elimina el elemento contenedor. Esto garantiza que las sesiones de voz activas se desconecten correctamente.
</Note>

***

## Ejemplos

### Tema oscuro con color personalizado

```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>
```

### Posición personalizada

```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>
```

### Con callbacks de eventos

```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>
```

### Con tono de llamada

```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>
```

### Uso de una referencia a un elemento 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>
```

### Integración con WordPress / CMS

Agrega esto a un bloque de HTML personalizado o al pie de página de tu tema:

```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>
  El `<div>` puede ir en cualquier lugar -- solo es el punto de montaje. El widget se muestra como una superposición fija en una esquina de la ventana gráfica (definida por la opción `position`) y no fluye con el contenido circundante.
</Tip>

***

## Solución de problemas

<AccordionGroup>
  <Accordion title="El widget no aparece">
    Asegúrate de que se carguen los archivos CSS y JS. Revisa la consola del navegador para detectar errores de red. Verifica que el elemento de destino exista en el DOM antes de llamar a `ThunderPhone.mount()`.
  </Accordion>

  <Accordion title="ThunderPhone no está definido">
    El script aún no se ha cargado. Asegúrate de que la etiqueta `<script>` para `widget.js` aparezca antes de tu llamada de montaje, o envuelve la llamada de montaje en un listener de `DOMContentLoaded`.
  </Accordion>

  <Accordion title="Error: dominio no permitido">
    Agrega tu dominio a la lista de dominios permitidos en la configuración de **Desarrolladores** en [app.thunderphone.com](https://app.thunderphone.com). Recuerda que `localhost` siempre está permitido.
  </Accordion>
</AccordionGroup>

***

## Próximos pasos

<CardGroup cols={2}>
  <Card title="Estilos" icon="palette" href="/es/widget/styling">
    Personaliza la apariencia del widget con propiedades personalizadas de CSS.
  </Card>

  <Card title="Componente de React" icon="react" href="/es/widget/react">
    ¿Usas React? La integración del componente es más sencilla.
  </Card>
</CardGroup>
