> ## Documentation Index
> Fetch the complete documentation index at: https://tomee-mintlify-c1ec36c9.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Widget de Mintlify

> Instala y configura el widget de Mintlify para incrustar el asistente de IA entrenado con tu contenido en cualquier sitio web o aplicación web.

export const AssistantWidgetPlayground = ({children, CodeBlockComponent}) => {
  const EXAMPLE_WIDGET_ID = "YOUR_WIDGET_ID";
  const EMBED_URL = "https://cdn.jsdelivr.net/npm/@mintlify/assistant-widget@0.0/dist/browser/embed.js";
  const PREVIEW_READY_MESSAGE = "mintlify-assistant-playground:ready";
  const PREVIEW_UPDATE_MESSAGE = "mintlify-assistant-playground:update";
  const PREVIEW_STATE_MESSAGE = "mintlify-assistant-playground:state";
  const SUPPORT_EMAIL = "hi@mintlify.com";
  const STARTER_QUESTIONS = ["How do I get started with Mintlify?", "How do I customize my docs?", "How do I deploy my docs?"];
  const VARIANT_OPTIONS = [{
    value: "widget",
    label: "Widget"
  }, {
    value: "modal",
    label: "Modal"
  }, {
    value: "panel",
    label: "Panel"
  }];
  const THEME_OPTIONS = [{
    value: "system",
    label: "System"
  }, {
    value: "light",
    label: "Light"
  }, {
    value: "dark",
    label: "Dark"
  }];
  const SIDE_OPTIONS = [{
    value: "top",
    label: "Top"
  }, {
    value: "bottom",
    label: "Bottom"
  }, {
    value: "left",
    label: "Left"
  }, {
    value: "right",
    label: "Right"
  }, {
    value: "inline-start",
    label: "Inline start"
  }, {
    value: "inline-end",
    label: "Inline end"
  }];
  const ALIGN_OPTIONS = [{
    value: "start",
    label: "Start"
  }, {
    value: "center",
    label: "Center"
  }, {
    value: "end",
    label: "End"
  }];
  const INSTALL_OPTIONS = [{
    value: "html",
    label: "HTML"
  }, {
    value: "next",
    label: "Next.js"
  }];
  const [installTarget, setInstallTarget] = useState("html");
  const [variant, setVariant] = useState("widget");
  const [theme, setTheme] = useState("system");
  const [accent, setAccent] = useState("#16a34a");
  const [radius, setRadius] = useState(18);
  const [side, setSide] = useState("bottom");
  const [align, setAlign] = useState("end");
  const [trackEvents, setTrackEvents] = useState(false);
  const [reportErrors, setReportErrors] = useState(false);
  const [previewHostReady, setPreviewHostReady] = useState(false);
  const [previewUrl, setPreviewUrl] = useState(null);
  const [previewStatus, setPreviewStatus] = useState("loading");
  const previewRef = useRef(null);
  const previewHostRef = useRef(null);
  useEffect(() => {
    const pageMatch = window.location.pathname.replace(/\/$/, "").match(/^(.*?)(\/[a-z]{2}(?:-[A-Za-z]{2,4})?)?\/assistant\/widget$/);
    const basePath = pageMatch?.[1] ?? "";
    const locale = pageMatch?.[2] ?? "";
    const mode = document.documentElement.classList.contains("dark") ? "dark" : "light";
    setPreviewUrl(`${basePath}/_minimal${locale}/assistant/widget-preview?mode=${mode}`);
  }, []);
  useEffect(() => {
    const removeRootWidget = () => {
      const rootWidget = document.querySelector("body > mintlify-assistant");
      if (!rootWidget) return false;
      const destroyPromise = window.MintlifyAssistant?.destroy();
      void destroyPromise?.catch(() => {});
      rootWidget.remove();
      return true;
    };
    const rootWidgetObserver = new MutationObserver(removeRootWidget);
    removeRootWidget();
    rootWidgetObserver.observe(document.body, {
      childList: true
    });
    return () => rootWidgetObserver.disconnect();
  }, []);
  useEffect(() => {
    const host = previewHostRef.current;
    if (!host) return undefined;
    const markReady = height => {
      if (height > 0) setPreviewHostReady(true);
    };
    markReady(host.getBoundingClientRect().height);
    if (typeof ResizeObserver === "undefined") {
      setPreviewHostReady(true);
      return undefined;
    }
    const observer = new ResizeObserver(entries => {
      markReady(entries[0]?.contentRect.height ?? 0);
    });
    observer.observe(host);
    return () => observer.disconnect();
  }, []);
  const classNames = (...classes) => classes.filter(Boolean).join(" ");
  const renderSegmentedControl = ({ariaLabel, onChange, options, threeColumns = false, value}) => <div role="group" aria-label={ariaLabel} className="grid gap-1 rounded-lg bg-gray-100 p-1 dark:bg-white/10" style={{
    gridTemplateColumns: `repeat(${threeColumns ? 3 : options.length}, minmax(0, 1fr))`
  }}>
      {options.map(option => <button key={option.value} type="button" aria-pressed={value === option.value} onClick={() => onChange(option.value)} className={classNames("min-h-8 rounded-md px-2 py-1.5 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40", value === option.value ? "bg-white text-gray-950 shadow-sm dark:bg-white/15 dark:text-white" : "text-gray-600 hover:text-gray-950 dark:text-gray-400 dark:hover:text-white")}>
          {option.label}
        </button>)}
    </div>;
  const renderSelectField = ({label, onChange, options, value}) => <label className="flex min-w-0 flex-col text-sm font-medium text-gray-700 dark:text-gray-300">
      <span className="mb-2">{label}</span>
      <select value={value} onChange={event => onChange(event.target.value)} className="h-10 w-full rounded-xl border border-gray-950/10 bg-transparent px-3 text-sm font-normal text-gray-950 outline-none transition-shadow focus-visible:ring-2 focus-visible:ring-primary/30 dark:border-white/10 dark:text-white">
        {options.map(option => <option key={option.value} value={option.value}>
            {option.label}
          </option>)}
      </select>
    </label>;
  const renderToggleRow = ({checked, description, label, onChange}) => <label className="flex cursor-pointer items-center justify-between gap-5 py-3">
      <span className="min-w-0">
        <span className="block text-sm font-medium text-gray-950 dark:text-white">
          {label}
        </span>
        <span className="block text-sm text-gray-600 dark:text-gray-400">
          {description}
        </span>
      </span>
      <span className="relative inline-flex shrink-0 rounded-full focus-within:ring-2 focus-within:ring-primary/40">
        <input type="checkbox" role="switch" checked={checked} onChange={event => onChange(event.target.checked)} className="sr-only" />
        <span aria-hidden="true" className={classNames("h-5 w-9 rounded-full transition-colors", checked ? "bg-primary" : "bg-gray-200 dark:bg-white/15")} />
        <span aria-hidden="true" className={classNames("pointer-events-none absolute left-0.5 top-0.5 size-4 rounded-full bg-white shadow-sm transition-all", checked && "ml-4")} />
      </span>
    </label>;
  const appearance = useMemo(() => ({
    variant,
    theme,
    accent,
    radius: `${radius}px`,
    side,
    align
  }), [accent, align, radius, side, theme, variant]);
  const updatePreview = useCallback(() => {
    const previewWindow = previewRef.current?.contentWindow;
    if (!previewWindow) return;
    const liveTheme = appearance.theme === "system" ? document.documentElement.classList.contains("dark") ? "dark" : "light" : appearance.theme;
    previewWindow.postMessage({
      type: PREVIEW_UPDATE_MESSAGE,
      trackEvents,
      reportErrors,
      appearance: {
        ...appearance,
        theme: liveTheme
      }
    }, window.location.origin);
  }, [appearance, reportErrors, trackEvents]);
  useEffect(() => {
    const handlePreviewMessage = event => {
      if (event.source !== previewRef.current?.contentWindow) return;
      if (event.data?.type === PREVIEW_READY_MESSAGE) {
        updatePreview();
        return;
      }
      if (event.data?.type === PREVIEW_STATE_MESSAGE) {
        setPreviewStatus(event.data.state === "error" ? "error" : "ready");
      }
    };
    const themeObserver = new MutationObserver(updatePreview);
    window.addEventListener("message", handlePreviewMessage);
    themeObserver.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class"]
    });
    updatePreview();
    return () => {
      window.removeEventListener("message", handlePreviewMessage);
      themeObserver.disconnect();
    };
  }, [updatePreview]);
  useEffect(() => {
    if (!previewHostReady || !previewUrl || previewStatus !== "loading") {
      return undefined;
    }
    const timeout = window.setTimeout(() => {
      setPreviewStatus(status => status === "loading" ? "error" : status);
    }, 20000);
    return () => window.clearTimeout(timeout);
  }, [previewHostReady, previewStatus, previewUrl]);
  const configLines = ["{", `  id: '${EXAMPLE_WIDGET_ID}',`, `  supportEmail: '${SUPPORT_EMAIL}',`, "  starterQuestions: [", ...STARTER_QUESTIONS.map(question => `    '${question}',`), "  ],", "  appearance: {", `    variant: '${variant}',`, `    theme: '${theme}',`, `    accent: '${accent}',`, `    radius: '${radius}px',`, `    side: '${side}',`, `    align: '${align}',`, "  },"];
  if (trackEvents || reportErrors) {
    configLines.push("  hooks: {");
    if (trackEvents) {
      configLines.push("    event(event) {", "      console.log('Assistant event', event);", "    },");
    }
    if (reportErrors) {
      configLines.push("    error(error) {", "      console.error('Assistant error', error.code, error);", "    },");
    }
    configLines.push("  },");
  }
  configLines.push("}");
  const configCode = configLines.join("\n");
  const indentedConfig = configCode.split("\n").join("\n  ");
  const htmlCode = `<script
  type="module"
  src="${EMBED_URL}"
></script>
<script type="module">
  await window.MintlifyAssistant.init(${indentedConfig});
</script>`;
  const nextCode = `'use client';

import Script from 'next/script';

const ASSISTANT_CONFIG = ${configCode};

export const AssistantWidget = () => (
  <Script
    type="module"
    src="${EMBED_URL}"
    onReady={() => {
      void window.MintlifyAssistant.init(ASSISTANT_CONFIG);
    }}
  />
);`;
  const installCode = installTarget === "html" ? htmlCode : nextCode;
  return <div className="my-6 grid gap-8" data-assistant-playground-layout="">
      <div className="min-w-0">
        <div className="not-prose overflow-hidden rounded-xl border border-gray-950/10 dark:border-white/10">
          <div className="px-5 py-4">
            <div className="text-sm font-medium text-gray-950 dark:text-white">
              Widget playground
            </div>
            <p className="mt-0.5 text-sm text-gray-600 dark:text-gray-400">
              Changes apply to the widget preview.
            </p>
          </div>

          <div className="border-t border-gray-950/10 px-5 py-5 dark:border-white/10">
            <div className="space-y-6">
              <fieldset>
                <legend className="mb-2 text-sm font-medium text-gray-950 dark:text-white">
                  Variants
                </legend>
                {renderSegmentedControl({
    ariaLabel: "Variants",
    value: variant,
    options: VARIANT_OPTIONS,
    onChange: setVariant
  })}
              </fieldset>

              <div className="grid gap-4 sm:grid-cols-2">
                {renderSelectField({
    label: "Theme",
    value: theme,
    options: THEME_OPTIONS,
    onChange: setTheme
  })}

                <label className="flex min-w-0 flex-col text-sm font-medium text-gray-700 dark:text-gray-300">
                  <span className="mb-2">Accent</span>
                  <span className="flex h-10 items-center gap-2 rounded-xl border border-gray-950/10 px-2 dark:border-white/10">
                    <input type="color" value={accent} onChange={event => setAccent(event.target.value)} aria-label="Accent color" className="h-7 w-8 cursor-pointer rounded border-0 bg-transparent p-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40" />
                    <span className="font-mono text-xs font-normal text-gray-600 dark:text-gray-400">
                      {accent}
                    </span>
                  </span>
                </label>
              </div>

              <label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
                <span className="mb-2 flex items-center justify-between">
                  Corner radius
                  <output className="font-mono text-xs font-normal text-gray-500 dark:text-gray-400">
                    {radius}px
                  </output>
                </span>
                <input type="range" min="0" max="32" step="2" value={radius} onChange={event => setRadius(Number.parseInt(event.target.value))} className="block w-full accent-primary" />
              </label>

              <div className="grid gap-4 sm:grid-cols-2">
                <fieldset>
                  <legend className="mb-2 text-sm font-medium text-gray-950 dark:text-white">
                    Trigger side
                  </legend>
                  {renderSegmentedControl({
    ariaLabel: "Trigger side",
    threeColumns: true,
    value: side,
    options: SIDE_OPTIONS,
    onChange: setSide
  })}
                </fieldset>

                <fieldset>
                  <legend className="mb-2 text-sm font-medium text-gray-950 dark:text-white">
                    Trigger alignment
                  </legend>
                  {renderSegmentedControl({
    ariaLabel: "Trigger alignment",
    value: align,
    options: ALIGN_OPTIONS,
    onChange: setAlign
  })}
                </fieldset>
              </div>

              <fieldset>
                <legend className="text-sm font-medium text-gray-950 dark:text-white">
                  Hooks
                </legend>
                <div className="mt-1 divide-y divide-gray-950/10 dark:divide-white/10">
                  {renderToggleRow({
    label: "Lifecycle events",
    description: "Observe open, close, ask, update, and navigation events.",
    checked: trackEvents,
    onChange: setTrackEvents
  })}
                  {renderToggleRow({
    label: "Structured errors",
    description: "Receive stable error codes and retry metadata.",
    checked: reportErrors,
    onChange: setReportErrors
  })}
                </div>
              </fieldset>
            </div>
          </div>

          <div className="border-t border-gray-950/10 p-5 dark:border-white/10">
            <div className="mb-3 flex flex-wrap items-center justify-between gap-3">
              <div>
                <div className="text-sm font-medium text-gray-950 dark:text-white">
                  Install
                </div>
                <div className="mt-0.5 text-sm text-gray-600 dark:text-gray-400">
                  Copy the generated setup for your stack.
                </div>
              </div>
              {renderSegmentedControl({
    ariaLabel: "Installation target",
    value: installTarget,
    options: INSTALL_OPTIONS,
    onChange: setInstallTarget
  })}
            </div>

            <CodeBlockComponent language="jsx" filename={installTarget === "html" ? "index.html" : "assistant-widget.jsx"} wrap>
              {installCode}
            </CodeBlockComponent>
          </div>
        </div>
        {children ? <div className="mt-8">{children}</div> : null}
      </div>

      <aside className="not-prose" data-assistant-preview="">
        <div ref={previewHostRef} className="relative flex h-[42rem] min-h-0 flex-col overflow-hidden rounded-xl border border-gray-950/10 bg-transparent dark:border-white/10 lg:sticky lg:top-20 lg:h-[calc(100vh-6rem)]" data-assistant-preview-card="">
          {previewHostReady && previewUrl ? <iframe ref={previewRef} title="Live Assistant Widget preview" src={previewUrl} onLoad={updatePreview} scrolling="no" className="min-h-0 w-full flex-1 border-0 bg-transparent [color-scheme:light_dark] dark:[color-scheme:dark]" /> : null}
          {previewStatus !== "ready" ? <div aria-live="polite" role="status" className="pointer-events-none absolute inset-0 z-10 flex items-center justify-center gap-3 px-6 text-center text-sm text-gray-600 dark:text-gray-400">
              {previewStatus === "loading" ? <span aria-hidden="true" className="size-[18px] shrink-0 animate-spin rounded-full border-[1.5px] border-gray-300 border-t-gray-600 motion-reduce:animate-none dark:border-gray-600 dark:border-t-gray-300" /> : null}
              <span>
                {previewStatus === "loading" ? "Loading assistant preview..." : "The live preview could not load. It requires a deployed docs site and the browser console may have details."}
              </span>
            </div> : null}
        </div>
      </aside>
    </div>;
};

export const WidgetCodeBlock = ({children, ...props}) => <CodeBlock {...props}>{children}</CodeBlock>;

El [asistente](/es/assistant) responde preguntas en tu sitio de Mintlify. Para incrustar la misma capacidad en otro sitio o aplicación web, usa el widget. Con el widget, puedes ofrecer a tus usuarios acceso a un chat de IA entrenado con tu contenido en el panel de tu producto, sitio de marketing, portal de soporte u otros lugares.

Usa el paquete [`@mintlify/assistant-widget`](https://www.npmjs.com/package/@mintlify/assistant-widget) para añadir tu asistente de Mintlify a cualquier sitio web o aplicación web. El paquete alojado gestiona su propio activador y se renderiza dentro de un Shadow DOM cerrado, lo que evita que los estilos de tu aplicación afecten al widget.

La única opción de navegador obligatoria es el ID público del widget. Gestiona el estado de activación, los orígenes permitidos, los adjuntos y la protección contra bots desde tu panel. Configura las preguntas iniciales específicas del embed y un correo electrónico de soporte en la configuración del navegador.

<div id="prerequisites">
  ## Requisitos previos
</div>

* Un [plan Pro o Enterprise](https://mintlify.com/pricing?ref=assistant). El widget usa los mismos créditos que el asistente.

<div id="enable-the-widget">
  ## Activar el widget
</div>

1. Ve a la página [Widget](https://app.mintlify.com/settings/deployment/widget) de tu despliegue.
2. Activa el widget.
3. Añade los orígenes permitidos donde vas a incrustar el widget.
4. Copia el ID del widget.

<div id="install-and-configure">
  ## Instalar y configurar
</div>

Usa el playground para configurar la presentación, las opciones visuales y los hooks de observación de tu widget. El bloque de código de instalación se actualiza a medida que cambias cada opción.

<Info>
  Reemplaza `YOUR_WIDGET_ID` en el código generado por el ID del widget de la página [Widget](https://app.mintlify.com/settings/deployment/widget) de tu panel.
</Info>

Después de añadir el código generado a tu sitio, recarga la página. Confirma que aparece el activador y, luego, haz clic en él y envía una pregunta de prueba para verificar que el widget está conectado.

<AssistantWidgetPlayground CodeBlockComponent={WidgetCodeBlock}>
  <Warning>
    Los scripts de módulo se difieren y se ejecutan en el orden del documento. Mantén el cargador alojado antes del bloque de inicialización cuando instales el widget con HTML, o el widget no se montará.
  </Warning>

  <div id="open-on-initialization">
    ## Abrir en la inicialización
  </div>

  Establece `defaultOpen` en `true` para abrir el widget inmediatamente después de su primer montaje:

  ```js theme={null}
  await window.MintlifyAssistant.init({
    id: "YOUR_WIDGET_ID",
    defaultOpen: true,
  });
  ```

  `defaultOpen` es `false` por defecto y solo se aplica a la primera inicialización. Llamar a `init()` de nuevo con el mismo ID de widget y endpoint de API no vuelve a abrir un widget que un visitante haya cerrado. Usa `open()` y `close()` para controlarlo después de la inicialización.

  <div id="use-a-custom-trigger">
    ## Usar un activador personalizado
  </div>

  Espera a `init()` antes de llamar a otros métodos. Mantén el activador integrado o abre la presentación configurada desde cualquier botón de tu aplicación.

  ```js theme={null}
  await window.MintlifyAssistant.init({
    id: "YOUR_WIDGET_ID",
    supportEmail: "hi@mintlify.com",
    starterQuestions: [
      "How do I get started with Mintlify?",
      "How do I customize my docs?",
      "How do I deploy my docs?",
    ],
  });

  document.querySelector("#help-button").addEventListener("click", () => {
    void window.MintlifyAssistant.open({
      source: "help-button",
      focus: true,
    });
  });
  ```

  Para abrir el widget y enviar inmediatamente una pregunta, llama a `ask()`:

  ```js theme={null}
  await window.MintlifyAssistant.ask("How do I authenticate?", {
    source: "authentication-guide",
    open: true,
    focus: true,
  });
  ```

  Los metadatos de eventos y las solicitudes incluyen el valor `source`, que te permite distinguir las interacciones integradas de tus puntos de entrada personalizados.

  <div id="update-a-mounted-widget">
    ## Actualizar un widget montado
  </div>

  Usa `update()` para cambiar la apariencia, las etiquetas, el correo de soporte, las preguntas iniciales o los hooks sin borrar la conversación actual. Solo se cambian los campos proporcionados.

  ```js theme={null}
  await window.MintlifyAssistant.update({
    appearance: {
      theme: "dark",
      accent: "#7c3aed",
    },
    labels: {
      title: "Docs copilot",
      trigger: "Ask docs",
    },
    supportEmail: "support@example.com",
    starterQuestions: [
      "How do I get started?",
      "How do I manage my account?",
    ],
  });
  ```

  Pasa `null` para restaurar un campo o grupo a su valor por defecto, eliminar el correo de soporte o restaurar una lista vacía de preguntas iniciales:

  ```js theme={null}
  await window.MintlifyAssistant.update({
    appearance: {
      accent: null,
    },
    supportEmail: null,
    starterQuestions: null,
    hooks: null,
  });
  ```

  Cambiar `identity` inicia una nueva conversación. Cambiar el ID del widget o el endpoint de la API requiere llamar a `destroy()` antes de un nuevo `init()`.

  Puedes proporcionar `supportEmail` y `starterQuestions` durante la inicialización y cambiarlos más tarde con `update()`. Estos valores se aplican al embed actual y no se heredan desde tu panel de Mintlify.

  <div id="configuration-reference">
    ## Referencia de configuración
  </div>

  <div id="assistantconfig">
    ### `AssistantConfig`
  </div>

  Pasa este objeto a `init()`.

  | Option             | Type                                          | Description                                                                                              |
  | ------------------ | --------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
  | `id`               | string                                        | ID público del widget desde el panel de Mintlify.                                                        |
  | `endpoint`         | string                                        | Sobrescribe el endpoint alojado de la API del widget.                                                    |
  | `identity`         | string                                        | Token firmado de identidad del usuario final. Omítelo para visitantes anónimos.                          |
  | `nonce`            | string                                        | Nonce de CSP copiado a los recursos creados por el widget.                                               |
  | `defaultOpen`      | boolean                                       | Abre el widget en su primera inicialización. El valor por defecto es `false`.                            |
  | `appearance`       | [`AssistantAppearance`](#assistantappearance) | Sobrescrituras visuales y de presentación.                                                               |
  | `labels`           | [`AssistantLabels`](#assistantlabels)         | Sobrescrituras de texto orientado al cliente.                                                            |
  | `supportEmail`     | string                                        | Establece la dirección de soporte que se muestra en la barra de herramientas del widget para este embed. |
  | `starterQuestions` | string\[]                                     | Establece hasta **tres** sugerencias de estado vacío para este embed.                                    |
  | `hooks`            | [`AssistantHooks`](#assistanthooks)           | Observadores de eventos y errores.                                                                       |

  <div id="assistantappearance">
    ### `AssistantAppearance`
  </div>

  | Option                     | Values                                                         | Description                                                                                        |
  | -------------------------- | -------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
  | `variant`                  | `widget`, `modal`, `panel`                                     | Controla si el asistente se abre como popover anclado, diálogo centrado o panel lateral adaptable. |
  | `theme`                    | `light`, `dark`, `system`                                      | Establece el esquema de color del widget. El valor por defecto es `system`.                        |
  | `accent`                   | CSS color                                                      | Establece el color de los controles principales.                                                   |
  | `radius`                   | CSS border radius                                              | Establece el radio del panel, como `18px`.                                                         |
  | `font`                     | CSS font family                                                | Usa una fuente ya cargada por tu aplicación. Por defecto se incluye Inter.                         |
  | `side`                     | `top`, `bottom`, `left`, `right`, `inline-start`, `inline-end` | Coloca el activador integrado en un borde de la pantalla.                                          |
  | `align`                    | `start`, `center`, `end`                                       | Alinea el activador a lo largo del borde seleccionado.                                             |
  | `dismissOnInteractOutside` | boolean                                                        | Controla si las interacciones de puntero o foco fuera del asistente lo cierran.                    |
  | `logo`                     | URL or `{ light, dark }`                                       | Reemplaza la marca predeterminada de Mintlify.                                                     |
  | `zIndex`                   | number                                                         | Cambia el orden de apilado del host del widget.                                                    |

  No se admiten sobrescrituras arbitrarias de CSS ni de paleta neutra. El Shadow DOM cerrado protege tanto a tu aplicación como al widget de regresiones de estilos entre sitios.

  <div id="assistantlabels">
    ### `AssistantLabels`
  </div>

  | Option        | Values                     | Description                                                                                   |
  | ------------- | -------------------------- | --------------------------------------------------------------------------------------------- |
  | `title`       | string or `null`           | Establece el encabezado del panel. El valor por defecto es `Assistant`.                       |
  | `trigger`     | string or `null`           | Establece el texto del widget compacto y del activador del panel.                             |
  | `placeholder` | string or `null`           | Establece el marcador de posición del compositor y del activador modal.                       |
  | `disclaimer`  | string, `false`, or `null` | Establece el aviso del estado vacío. Pasa `false` para ocultarlo.                             |
  | `suggestions` | string or `null`           | Establece el encabezado sobre las preguntas iniciales. El valor por defecto es `Suggestions`. |

  <div id="assistanthooks">
    ### `AssistantHooks`
  </div>

  ```js theme={null}
  hooks: {
    event(event) {
      console.log(event.type, event.actor, event.source);
    },
    error(error) {
      console.error(error.code, error.retryable, error.status);
    },
  }
  ```

  El hook `event` recibe metadatos de ciclo de vida e interacción para `init`, `open`, `close`, `ask`, `update`, `reset`, `navigate` y `destroy`. Los eventos no incluyen el texto de la pregunta, la identidad, la sesión ni los tokens CAPTCHA.

  El hook `error` recibe un `code` estable, un booleano `retryable` y un `status` HTTP opcional. Las excepciones lanzadas por cualquiera de los hooks no interrumpen el widget.

  <div id="assistantopenoptions">
    ### `AssistantOpenOptions`
  </div>

  Pasa este objeto opcional a `open()`.

  | Option   | Type    | Description                                                            |
  | -------- | ------- | ---------------------------------------------------------------------- |
  | `source` | string  | Atribución definida por el cliente incluida en eventos y solicitudes.  |
  | `focus`  | boolean | Enfoca el compositor después de abrir. El valor por defecto es `true`. |

  <div id="assistantaskoptions">
    ### `AssistantAskOptions`
  </div>

  Pasa este objeto opcional después de la cadena de la pregunta en `ask()`.

  | Option   | Type    | Description                                                           |
  | -------- | ------- | --------------------------------------------------------------------- |
  | `source` | string  | Atribución definida por el cliente incluida en eventos y solicitudes. |
  | `open`   | boolean | Abre el panel antes de enviar. El valor por defecto es `true`.        |
  | `focus`  | boolean | Enfoca el compositor al abrir. El valor por defecto es `true`.        |

  <div id="assistantupdate">
    ### `AssistantUpdate`
  </div>

  Pasa este objeto a `update()`. Todos los campos son opcionales y `null` restaura su valor por defecto.

  | Option             | Type                                                    | Description                                                                |
  | ------------------ | ------------------------------------------------------- | -------------------------------------------------------------------------- |
  | `identity`         | string or `null`                                        | Cambia la identidad firmada e inicia una nueva conversación.               |
  | `appearance`       | [`AssistantAppearance`](#assistantappearance) or `null` | Aplica parches en profundidad a la configuración de apariencia.            |
  | `labels`           | [`AssistantLabels`](#assistantlabels) or `null`         | Aplica parches en profundidad al texto orientado al cliente.               |
  | `supportEmail`     | string or `null`                                        | Cambia la dirección de soporte. Pasa `null` para eliminarla.               |
  | `starterQuestions` | string\[] or `null`                                     | Cambia hasta tres sugerencias. Pasa `null` para restaurar una lista vacía. |
  | `hooks`            | [`AssistantHooks`](#assistanthooks) or `null`           | Aplica parches en profundidad a los observadores de eventos y errores.     |

  <div id="browser-api">
    ## API del navegador
  </div>

  | Method                   | Parameter types                                       | Description                                                                              |
  | ------------------------ | ----------------------------------------------------- | ---------------------------------------------------------------------------------------- |
  | `init(config)`           | [`AssistantConfig`](#assistantconfig)                 | Carga y monta el widget. Es la promesa de disponibilidad para todos los demás métodos.   |
  | `open(options)`          | [`AssistantOpenOptions`](#assistantopenoptions)       | Abre la presentación configurada.                                                        |
  | `close()`                | —                                                     | Cierra el widget.                                                                        |
  | `ask(question, options)` | string, [`AssistantAskOptions`](#assistantaskoptions) | Abre el widget si se solicita y envía una pregunta.                                      |
  | `update(config)`         | [`AssistantUpdate`](#assistantupdate)                 | Aplica parches en profundidad a la identidad mutable, apariencia, textos y observadores. |
  | `reset()`                | —                                                     | Inicia una conversación nueva.                                                           |
  | `destroy()`              | —                                                     | Elimina el widget y libera sus recursos del navegador.                                   |

  Las capturas de conversación permanecen privadas al widget. Cada método se resuelve en `void`.

  <div id="content-security-policy">
    ## Content Security Policy
  </div>

  Si tu sitio usa una Content Security Policy, permite los orígenes requeridos por las funciones habilitadas de tu widget:

  | Directive                                    | Source                              | Required for                     |
  | -------------------------------------------- | ----------------------------------- | -------------------------------- |
  | `script-src`                                 | `https://cdn.jsdelivr.net`          | Cargador y runtime del widget    |
  | `connect-src`                                | `https://api.mintlify.com`          | API del widget                   |
  | `style-src`                                  | `https://cdn.jsdelivr.net`          | Hoja de estilos del widget       |
  | `font-src`                                   | `https://cdn.jsdelivr.net`          | Fuente Inter incluida opcional   |
  | `script-src`, `connect-src`, and `frame-src` | `https://challenges.cloudflare.com` | Protección contra bots Turnstile |
  | `script-src`                                 | `https://js.hcaptcha.com`           | Protección contra bots hCaptcha  |
  | `connect-src` and `frame-src`                | `https://*.hcaptcha.com`            | Protección contra bots hCaptcha  |

  Una política `script-src` estricta debe autorizar tanto el cargador como el script de inicialización. Pasar `nonce` a `init()` lo propaga solo a los recursos que el widget crea después de la inicialización.
</AssistantWidgetPlayground>
