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

# Instalación avanzada

> Configura la API de Restoo.js: la vista inicial, el idioma, los triggers y el comportamiento del widget en tu integración.

Esta página da por hecho que ya has completado la [guía rápida de instalación](/es/widget/quickstart). Cubre todo lo que va más allá de esa instalación básica: la [API de Restoo.js](#api-de-restoo-js), los [enlaces profundos](#enlaces-profundos), la [atribución forzada](#atribución-forzada), las [notas para integradores](#notas-para-integradores) y las opciones de [alojado en Restoo](#alojado-en-restoo). Para personalizar colores y tipografías, consulta [Apariencia](/es/widget/appearance).

<Note>
  Todo lo que sigue es de **tenerlo incrustado en tu web**, con el formulario de
  reservas dentro de tu propia web. Si tus clientes reservan en la página alojada
  por Restoo no hay código que escribir: lo que se configura y dónde lo tienes en
  [Alojado en Restoo](#alojado-en-restoo), al final de la página.
</Note>

## API de Restoo.js

El widget se presenta de tres formas, y en el código cada una tiene su valor. Aquí y en [los eventos](/es/widget/events#campos-comunes-a-todos-los-eventos) los verás así:

| Cómo se presenta       | Valor de API | Cómo se monta                               |
| ---------------------- | ------------ | ------------------------------------------- |
| Modal sobre tu página  | `OVERLAY`    | [`.bindTriggers()`](#bindtriggers-settings) |
| Integrado en tu página | `INLINE`     | [`.mount()`](#mount-containerid)            |
| Alojado en Restoo      | `STANDALONE` | Nada: es la página que te aloja Restoo      |

Todos los métodos devuelven la instancia, así que se pueden encadenar. Y donde un valor
admite solo letras, dígitos, guiones y guiones bajos (`[a-zA-Z0-9-_]`), se indica.

### Ejemplo completo

Todo lo que expone la API, junto en una instalación: una instancia con nombre propio, los cinco
parámetros de `.create()` y un atributo de trigger personalizado. El resto de esta sección lo
explica pieza por pieza, y no hace falta incluirlo todo: solo lo que necesite tu integración.

```js theme={null}
const widget = window.Restoo("best-burger", { widgetId: "w-reservations" });

widget
  .create({
    options: {
      language: "es",
      view: "experiences",
      layout: { hasBorder: true },
    },
    // Sustituye la apariencia de la cuenta por completo, así que se declara entera.
    appearance: {
      fonts: [
        {
          cssSrc:
            "https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;600&display=swap",
        },
      ],
      variables: {
        colorAccent: "#c0392b",
        fontFamilyHeading: '"Playfair Display", serif',
      },
    },
    // Esta página no tiene contenedor de GTM; el resto de destinos vienen de la cuenta.
    connect: { gtm: false },
    cmp: "GOOGLE_CONSENT_MODE",
    utmTags: { utmSource: "portal_colaborador", utmMedium: "referral" },
  })
  .bindTriggers({ attribute: "data-open-booking" });
```

### `window.Restoo(account, settings?)`

Crea una instancia del widget. Está disponible en cuanto se lanza el evento `restoo:loaded` en `window`.

**Parámetros**

<ParamField body="account" type="string" required>
  Tu Account ID de Restoo, por ejemplo `"best-burger"`. Fuera del juego de
  caracteres admitido lanza un error.
</ParamField>

<ParamField body="settings.widgetId" type="string">
  ID único de esta instancia. Por defecto toma el valor de `account`. Restoo le
  añade el prefijo `restoo_`, así que `widgetId: "w-reservations"` aparece como
  `"restoo_w-reservations"` en `source.widget_id` de los [eventos del widget de
  Restoo](/es/widget/events#campos-comunes-a-todos-los-eventos).
</ParamField>

Devuelve una instancia del widget con `create()`, `mount()`, `bindTriggers()` y `setConsent()`.

<Tip>
  Define `widgetId` de forma explícita cuando montes **más de una instancia del
  widget en la misma página** para el mismo `account`; por ejemplo, dos
  formularios de reserva distintos con vistas iniciales diferentes. Cada
  `widgetId` mantiene su propio estado, aislado del resto.
</Tip>

### `.create(settings?)`

**Opcional.** Configura la instancia antes de montarla: si no necesitas personalizar nada, llama directamente a `.mount()` o a `.bindTriggers()` y el widget usará sus valores por defecto.

```js theme={null}
widget.create({ options, appearance, connect, cmp, utmTags });
```

**Parámetros**

<ParamField body="options" type="object">
  Cómo se comporta el widget: el idioma, la vista con la que arranca y cómo se
  asienta dentro de tu página.

  <Expandable title="propiedades">
    <ParamField body="language" type="string">
      Idioma del widget. Usa uno de los valores admitidos en
      [CustomerLanguage](/getting-started/enums#customerlanguage). Si lo omites, el
      widget detecta automáticamente el idioma del navegador del visitante. Ejemplo:
      `language: "es"`.
    </ParamField>

    <ParamField body="view" type="string" default="reservation">
      Vista inicial que usa `.mount()`. Para un modal, pon la vista que quieras como
      valor de su trigger `data-restoo-open`. Uno de estos valores:

      | Valor         | Descripción                                                    |
      | ------------- | -------------------------------------------------------------- |
      | `reservation` | El flujo de reserva.                                           |
      | `experiences` | Experiencias y menús degustación.                              |
      | `store`       | Tienda de tarjetas regalo y productos.                         |
      | `announces`   | Página de anuncios.                                            |
      | `locations`   | Selector de local, para cuentas con varios locales vinculados. |
      | `redeem`      | Canjear una tarjeta regalo o un vale.                          |

      Ejemplo: `view: "experiences"`.
    </ParamField>

    <ParamField body="layout" type="object">
      Ajusta con detalle cómo se asienta el widget dentro de tu página.

      <Expandable title="propiedades">
        <ParamField body="hasPadding" type="boolean">
          Espaciado interior alrededor del contenido del widget. Por defecto es `false`
          en un widget incrustado y `true` en un modal, que ya flota sobre tu página.
        </ParamField>

        <ParamField body="hasBorder" type="boolean">
          Borde alrededor del contenedor del widget. Por defecto es `false`; actívalo si
          el widget necesita destacar sobre un fondo del mismo color.
        </ParamField>
      </Expandable>
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="appearance" type="object">
  Apariencia solo para esta instancia: sustituye la de tu cuenta por completo, no
  la retoca. Consulta [Apariencia](/es/widget/appearance) para más información.
</ParamField>

<ParamField body="connect" type="object">
  Destinos que hay que desactivar para esta instalación: `ga4`, `googleAds`,
  `metaPixel`, `tiktokPixel` o `gtm`, cada uno con el valor `false`, el único
  admitido. Todo lo demás de un destino viene de tu cuenta. Consulta [Restoo
  Connect](/es/widget/connect#desactivar-un-destino-en-una-instalación) para más
  información.
</ParamField>

<ParamField body="cmp" type="&#x22;COOKIEBOT&#x22; | &#x22;GOOGLE_CONSENT_MODE&#x22;">
  [Plataforma de gestión de consentimiento](/es/widget/consent#qué-es-una-plataforma-de-gestión-de-consentimiento)
  instalada en esta página, de la que Restoo lee la decisión del visitante. Si lo
  omites, el consentimiento llega únicamente a través de
  [`setConsent()`](#setconsent-signals). Consulta
  [Consentimiento](/es/widget/consent#declarar-tu-plataforma-de-consentimiento)
  para más información.
</ParamField>

<ParamField body="utmTags" type="object">
  Atribución de campaña fija para esta instalación: lo que declares manda sobre
  los parámetros UTM que traiga la URL del visitante. Si lo omites, la atribución
  sale de esa URL, como siempre. Consulta [Atribución forzada](#atribución-forzada) para más información.

  <Expandable title="propiedades">
    <ParamField body="utmSource" type="string">
      De dónde viene la reserva; el parámetro `utm_source`. Ejemplo:
      `"portal_colaborador"`.
    </ParamField>

    <ParamField body="utmMedium" type="string">
      El canal que la trae; el parámetro `utm_medium`. Ejemplo: `"referral"`.
    </ParamField>

    <ParamField body="utmCampaign" type="string">
      La campaña a la que pertenece; el parámetro `utm_campaign`. Ejemplo:
      `"verano_2026"`.
    </ParamField>

    <ParamField body="utmTerm" type="string">
      La palabra clave de pago que hay detrás; el parámetro `utm_term`. Ejemplo:
      `"reservar_mesa"`.
    </ParamField>

    <ParamField body="utmContent" type="string">
      De qué creatividad o emplazamiento viene; el parámetro `utm_content`.
      Ejemplo: `"widget_lateral"`.
    </ParamField>
  </Expandable>
</ParamField>

### `.mount(containerId)`

Monta el widget dentro del elemento HTML indicado. Se usa para los widgets `INLINE`.

```js theme={null}
widget.mount("restoo-widget");
```

**Parámetros**

<ParamField body="containerId" type="string" required>
  El `id` de tu elemento contenedor, por ejemplo `"restoo-widget"`. Además del
  juego de caracteres admitido, no puede empezar por un dígito, ni por un guion
  seguido de un dígito, ni ser un único guion. Los `id` con acentos o con
  caracteres no latinos, como `"menú"` o `"café-2"`, se rechazan: renombra el
  elemento o dale al widget un `id` más sencillo.
</ParamField>

### `.bindTriggers(settings?)`

Pone la instancia en modo `OVERLAY` y registra como triggers de clic los elementos que llevan `data-restoo-open` (o el atributo personalizado que indiques). El widget **se monta de forma diferida en el primer clic del usuario**; los clics siguientes navegan directamente, sin volver a montarlo.

```js theme={null}
widget.bindTriggers();

// Con un atributo personalizado
widget.bindTriggers({ attribute: "data-open-booking" });
```

**Parámetros**

<ParamField body="settings.attribute" type="string" default="data-restoo-open">
  Atributo HTML que se usa como trigger, por ejemplo `"data-open-booking"`.

  Solo admite letras, dígitos, guiones, guiones bajos y dos puntos, y tiene que
  empezar por una letra; en caso contrario lanza un error.
</ParamField>

**Uso en HTML:**

El valor del atributo es la vista con la que se abre el modal. Déjalo vacío para abrir la vista por
defecto, o pon cualquiera de los valores que admite la [opción `view`](#param-view) para llevar al
visitante directamente a esa parte del widget.

```html theme={null}
<!-- Sin valor: abre la vista por defecto (reserva) -->
<button data-restoo-open>Reservar</button>

<!-- Con valor: abre directamente en esa vista -->
<button data-restoo-open="experiences">Ver nuestras experiencias</button>
<button data-restoo-open="store">Tarjetas regalo</button>
```

### `.setConsent(signals)`

**Opcional si has declarado tu [plataforma de consentimiento](/es/widget/consent#qué-es-una-plataforma-de-gestión-de-consentimiento) con [`cmp`](#param-cmp)**, porque entonces Restoo ya lee esa plataforma. Informa a Restoo del consentimiento del visitante usando los nombres y valores de señal del [Consent Mode v2 de Google](https://support.google.com/tagmanager/answer/10718549).

Llámalo desde tu aviso de cookies cada vez que el visitante acepte, rechace o cambie su decisión.

```js theme={null}
widget.setConsent({
  ad_storage: "granted",
  ad_user_data: "granted",
  ad_personalization: "denied",
  analytics_storage: "granted",
});
```

**Parámetros**

<ParamField body="signals" type="object" required>
  Una o varias de las siete señales del Consent Mode v2 de Google. Cada valor
  tiene que ser exactamente `"granted"` o `"denied"`. En
  [Consentimiento](/es/widget/consent#param-signals) tienes qué significa cada
  señal, cómo se acumulan entre llamadas y qué desbloquea cada una.
</ParamField>

***

## Enlaces profundos

El widget refleja en la URL de tu página la vista en la que está, dentro de un parámetro `?restoo_widgets=`. Eso convierte esa dirección en un enlace que se puede compartir o guardar en favoritos: al abrirla, el widget arranca en la vista guardada en lugar de en la que tiene por defecto.

Funciona en los dos modos, con una diferencia:

| Modo      | Al cargar la página con ese parámetro                                                   |
| --------- | --------------------------------------------------------------------------------------- |
| `INLINE`  | El widget se monta directamente en la vista guardada.                                   |
| `OVERLAY` | El modal **se abre por sí solo**, y su estado se elimina de la URL en cuanto se cierra. |

No tienes que construir esas URL a mano: el widget escribe el parámetro por su cuenta al navegar, y tu página solo tiene que conservarlo si la enlazas o la compartes.

<Note>
  Las pantallas que identifican una reserva o a su cliente **nunca se escriben
  en la URL de tu página**, así que no se guardan y no se puede enlazar a ellas.
  Una URL acaba en muchos sitios —tu analítica, un enlace compartido, el
  historial de un navegador— y los datos del cliente no tienen por qué acabar
  ahí.
</Note>

***

## Atribución forzada

Hay instalaciones en las que la URL del visitante no debe decidir la atribución, porque la página misma **es** el canal. El caso habitual es un portal de reservas que colabora con el negocio: el negocio quiere medir cuántas reservas le envía ese portal, y todas las que se hacen ahí son suyas, sea lo que sea lo que llevó al visitante hasta el portal.

Declara esos valores como `utmTags` y todas las reservas y todos los eventos de esa instalación los llevan. Es una **atribución forzada**: lo que declares manda sobre lo que traiga la URL del visitante.

```js theme={null}
window
  .Restoo("best-burger")
  .create({ utmTags: { utmSource: "portal_colaborador", utmMedium: "referral" } })
  .mount("restoo-widget");
```

Lo que declaras es **inmutable** y **completo**:

* **Inmutable**: los parámetros UTM que lleguen por la URL no pueden pisarlo, ni tampoco los valores recordados de una visita anterior mediante [Restoo Attribution Transfer](/es/widget/attribution-transfer).
* **Completo**: el conjunto declarado sustituye la atribución entera; un campo que dejes fuera no se coge de la URL, así que dos visitas distintas no acaban mezcladas en el mismo registro. Declarar solo `utmSource` da a todas las reservas ese origen y ninguna campaña, y el medio toma [el valor por defecto](/es/widget/attribution#atribución-por-defecto).

Cualquier cosa que no sea uno de los cinco campos de arriba, o que venga con el valor vacío, se ignora, con una advertencia en la consola del navegador que dice qué se ha descartado.

<Note>
  Una atribución forzada **no necesita consentimiento**. Estos valores son parte
  de tu instalación, no información leída del dispositivo del visitante, así que
  ahí no se guarda nada y no hay nada que preguntar. Tampoco se escriben nunca en
  `localStorage`: una visita posterior que entre por otra puerta se atribuye por
  su cuenta.
</Note>

***

## Notas para integradores

<AccordionGroup>
  <Accordion title="Qué hace Restoo.js en tu página">
    El código de la guía rápida de instalación carga **Restoo.js** (`restoo-widget`) desde el subdominio de
    Restoo de tu cuenta. Restoo.js:

    1. Añade la función `window.Restoo()` a tu página y después lanza un evento `restoo:loaded` en `window` para avisar de que ya se puede usar.
    2. Crea un `<iframe>` que apunta a tu subdominio de Restoo y renderiza dentro la aplicación de reservas: al llamar a `.mount()`, o en el primer clic del visitante cuando usas `.bindTriggers()`.
    3. Mantiene sincronizados tu página y el widget de forma automática: redimensiona el widget `INLINE` para que se ajuste a su contenido, reenvía los [eventos del widget de Restoo](/es/widget/events) a `window` y sincroniza la navegación de atrás y adelante del navegador.
  </Accordion>

  <Accordion title="Cómo se carga Restoo.js">
    Restoo.js tiene que cargarse con `type="module"`. Como los scripts de tipo módulo se
    ejecutan de forma diferida, inicializa siempre tu widget desde dentro de un listener de
    `restoo:loaded` en lugar de justo después de la etiqueta `<script>`; si no, puede que
    `window.Restoo` todavía no exista.
  </Accordion>

  <Accordion title="Autoscroll al navegar (widget integrado)">
    Cuando un visitante navega entre las páginas internas del widget (por ejemplo, calendario →
    formulario → confirmación), un widget `INLINE` pide a tu página que desplace su
    contenedor hasta dejarlo a la vista, pero solo si la parte superior del contenedor no está
    visible en ese momento, así que nunca hace scroll sin necesidad. La carga inicial de la página
    no lo activa nunca.

    Si tu web tiene una cabecera fija que taparía la parte superior del widget, dale a tu
    contenedor un `scroll-margin-top` igual a su altura:

    ```css theme={null}
    #restoo-widget {
      scroll-margin-top: 80px; /* altura de tu cabecera fija */
    }
    ```
  </Accordion>

  <Accordion title="Presentación del modal (móvil y escritorio)">
    En móvil, el modal —el valor `OVERLAY`— ocupa toda la pantalla. En escritorio es un panel
    flotante centrado sobre un fondo oscurecido. Esto es automático; lo único que
    puedes personalizar son los colores del propio panel, con
    `colorWidgetBackground` y `colorWidgetForeground`: consulta
    [Apariencia](/es/widget/appearance).
  </Accordion>

  <Accordion title="Varios widgets en una misma página">
    El estado de los enlaces profundos (`?restoo_widgets=`) y la navegación de
    atrás y adelante del navegador se controlan de forma independiente para cada
    widget, así que puedes montar tantos `OVERLAY` o `INLINE` como necesites en la
    misma página.
  </Accordion>

  <Accordion title="Content Security Policy (CSP)">
    Una Content Security Policy es una regla que envía tu servidor para indicar al navegador qué
    dominios externos puede usar una página. **La mayoría de las webs no tienen ninguna**; si no
    lo sabes, pregunta a quien mantenga tu web. Si la tuya sí tiene una, necesita permitir tres
    cosas para el widget, que se añaden a las directivas que ya tengas:

    | Directiva     | Añade                                             | Para qué sirve                                                            |
    | ------------- | ------------------------------------------------- | ------------------------------------------------------------------------- |
    | `frame-src`   | `https://*.myrestoo.net`                          | El widget en sí, que se carga desde tu subdominio de Restoo.              |
    | `script-src`  | `https://*.myrestoo.net https://cdn.jsdelivr.net` | Restoo.js y la librería que redimensiona un widget `INLINE`.              |
    | `connect-src` | `https://*.myrestoo.net`                          | Permite a Restoo.js leer los ajustes configurados en tu cuenta de Restoo. |

    <Warning>
      **`connect-src` falla en silencio, así que merece la pena revisarlo dos veces.** Sin él, el
      widget se carga y sigue aceptando reservas, pero no puede leer los ajustes de tu cuenta: los
      colores y las tipografías de tu marca vuelven a los valores por defecto y los destinos de
      analítica configurados en tu cuenta no se activan nunca. No aparece ningún error en ninguna
      parte: simplemente el widget no se ve ni reporta como debería.
    </Warning>

    <Note>
      Un widget `INLINE` necesita además que se permitan los **scripts en línea** —con un nonce,
      un hash o `'unsafe-inline'`— porque el redimensionador se carga a través de una pequeña
      etiqueta `<script>` en línea. Permitir solo el dominio `cdn.jsdelivr.net` no basta. Sin eso
      el widget funciona, pero deja de ajustar su altura al contenido. Los widgets `OVERLAY` no se
      redimensionan, así que no les afecta.
    </Note>
  </Accordion>
</AccordionGroup>

***

## Alojado en Restoo

El widget alojado en Restoo tiene estas opciones de configuración.

### En tu cuenta de Restoo

Se guardan una vez y valen para todos tus enlaces:

* **La apariencia** — tus colores, tus tipografías y tu estilo.
* **[Las plataformas donde mides](/es/widget/integrations)** — GA4, Google Ads, Meta Pixel, TikTok Pixel y OpenAI Pixel.

Cualquier cambio se aplica en la siguiente carga de página, sin desplegar nada.

Aquí la medición la monta Restoo de principio a fin: **instala las etiquetas de esas plataformas y pide el consentimiento con su propio aviso de cookies.** Por tu parte no hay nada que añadir. En [Restoo Connect](/es/widget/connect#antes-de-empezar) explicamos cómo funciona.

### En el enlace

El idioma, la vista con la que arranca y la campaña a la que se atribuye la reserva:

| Parámetro                         | Para qué sirve                                                                                                                  |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `?lang=`                          | Fija el idioma. Sin él, se detecta el del navegador del visitante. Ejemplo: `?lang=en`.                                         |
| `?view=`                          | Abre el widget en una vista concreta, con [los mismos valores que la opción `view`](#param-view). Ejemplo: `?view=experiences`. |
| `?utm_source=`, `?utm_medium=`, … | Los cinco parámetros UTM habituales, tal cual: consulta [Atribución de campañas](/es/widget/attribution#alojado-en-restoo).     |

```
https://best-burger.myrestoo.net/?lang=en&view=store
```

Así puedes tener varios enlaces a la vez: uno en inglés para tus clientes internacionales, otro que abra directamente la tienda de tarjetas regalo.

<Note>
  **Lo que no existe con el widget alojado en Restoo.** No hay instalación que declare nada, así
  que tampoco hay `appearance` ni `connect` por instalación, ni [`cmp`](#param-cmp)
  ni [`setConsent()`](#setconsent-signals) —el aviso de cookies es nuestro—, ni
  [`utmTags`](#atribución-forzada), ni `bindTriggers()`. Y como el widget no está dentro de tu
  web, no hay nada que ajustar de CSP, de autoscroll ni de altura.
</Note>

***

## Siguientes pasos

<CardGroup cols={2}>
  <Card title="Apariencia" icon="palette" href="/es/widget/appearance">
    Ajusta el widget a tu marca: colores, tipografías y redondeos.
  </Card>

  <Card title="Restoo Connect" icon="chart-line" href="/es/widget/connect">
    Envía los eventos de reserva a GA4, Google Ads, Meta, TikTok, ChatGPT Ads y GTM
    automáticamente.
  </Card>
</CardGroup>
