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

# Personaliza con Custom Events

> Usa las propiedades de Custom Events para personalizar mensajes de Journey con sintaxis Liquid. Aprende cómo se almacenan, acceden y renderizan los eventos en plantillas de push, correo electrónico y SMS.

Los [Custom Events](./custom-events) te permiten personalizar mensajes de Journey usando propiedades de eventos (nombres de productos, precios, URLs, arrays, etc.).

Las propiedades de eventos están disponibles en las plantillas solo si el evento:

* Activa la entrada al Journey, o
* Coincide con una condición **Wait Until** dentro del Journey

Las propiedades de eventos almacenadas se pueden acceder usando [sintaxis Liquid](./using-liquid-syntax).

***

## Cómo funciona la personalización con Custom Events

Agrega propiedades de eventos a tus mensajes de Journey siguiendo estos pasos:

<Steps>
  <Step title="Enviar un Custom Event con propiedades">
    Ejemplo de payload de [Custom Events](./custom-events):

    ```json JSON theme={null}
    {
      "name": "purchase",
      "properties": {
        "item": "Blue Sweater",
        "price": "29.99",
        "order status": "pending",
        "details": [
          {
            "manufacturer": "Company A",
            "model": "1234567890"
          },
          {
            "manufacturer": "Company B",
            "model": "9876543210"
          }
        ]
      },
      "external_id": "user_12345",
      "timestamp": "2025-10-21T19:09:32.263Z",
    }
    ```
  </Step>

  <Step title="Referencia las propiedades del evento en las plantillas de mensajes de tu Journey">
    Usa [sintaxis Liquid](./using-liquid-syntax) para acceder a las propiedades del evento.

    ### Patrones comunes de acceso con Liquid

    | Qué necesitas                       | Liquid                                                                | Resultado                      |
    | ----------------------------------- | --------------------------------------------------------------------- | ------------------------------ |
    | Nombre del evento                   | `{{ journey.first_event.name }}`                                      | `purchase`                     |
    | Propiedad                           | `{{ journey.first_event.properties.item }}`                           | `Blue Sweater`                 |
    | Propiedades anidadas                | `{{ journey.first_event.properties.details.first.manufacturer }}`     | `Company A`                    |
    | Propiedad con caracteres especiales | `{{ journey.last_event.properties["order status"] }}`                 | `pending`                      |
    | Marca de tiempo                     | `{{ journey.last_event.timestamp \| date: "%B %d, %Y at %I:%M %p" }}` | `October 21, 2025 at 07:09 PM` |

    #### Patrones de acceso Liquid anidados

    También puedes acceder a propiedades anidadas usando notación de punto y corchetes:

    ```liquid Liquid theme={null}
    {{ journey.first_event.properties.details.first.manufacturer }} = Company A
    {{ journey.first_event.properties.details.last.manufacturer }} = Company B
    {{ journey.first_event.properties.details[0].manufacturer }} = Company A
    {{ journey.first_event.properties.details[1].manufacturer }} = Company B
    ```

    <Warning>
      El Liquid inválido o las propiedades faltantes se renderizan como cadenas vacías. Los mensajes se envían de todas formas. Usa [filtros default](./using-liquid-syntax#default) para establecer un valor de respaldo.
    </Warning>
  </Step>

  <Step title="Crear un Journey">
    Configura el Journey para usar el Custom Event como regla de entrada y/o condición Wait Until.

    * Consulta [Configuración de Journeys](./journeys-settings) para las reglas de entrada.
    * Consulta [Acciones de Journeys](./journeys-actions) para las condiciones Wait Until.

    Agrega nodos de mensaje con las plantillas.
  </Step>
</Steps>

### Reglas de almacenamiento de propiedades de eventos

* Puedes usar múltiples eventos en tu Journey combinando reglas de entrada y pasos Wait Until.
* Máximo: **100 propiedades de eventos almacenadas por usuario por instancia de Journey** (las más antiguas se eliminan).
* Las propiedades de eventos se almacenan **por usuario, por instancia de Journey**.
* Los eventos enviados antes de la entrada no son accesibles.
* Las propiedades de eventos se borran cuando el usuario sale del Journey.

<Warning>
  Los eventos almacenados en un Journey no pueden ser accedidos desde otro Journey.
</Warning>

***

## Referencia Liquid de Custom Events

Usa estos objetos para acceder a los eventos almacenados dentro del Journey.

<ParamField body="journey.first_event">
  El primer evento almacenado para esta instancia de Journey.

  * Si usas una **regla de entrada de Custom Event**, este es el evento que causó la entrada al Journey.
  * Si no usas una regla de entrada de Custom Event, este es el primer evento almacenado al coincidir con una condición Wait Until.

  ```liquid Liquid theme={null}
  Thanks for purchasing {{ journey.first_event.properties.item | default: "your item" }}!
  ```
</ParamField>

<ParamField body="journey.last_event">
  El evento almacenado más reciente para esta instancia de Journey.

  * Si solo hay un evento almacenado, `first_event` y `last_event` devuelven lo mismo.

  ```liquid Liquid theme={null}
  Your most recent purchase was {{ journey.last_event.properties.item | default: "made" }}!
  ```
</ParamField>

<ParamField body="journey.event.EVENT_NAME">
  El evento almacenado más reciente con un nombre específico.

  * Reemplaza `EVENT_NAME` con el nombre de tu evento (por ejemplo, `purchase`).
  * Si el mismo nombre de evento se usa varias veces, esto devuelve la instancia más reciente.

  ```liquid Liquid theme={null}
  {% assign event = journey.event.purchase %}
  ```

  Si el nombre de tu evento incluye espacios o caracteres especiales, usa [notación de corchetes](https://shopify.dev/docs/api/liquid/basics#referencing-handles).

  **Ejemplo de evento:** `"name": "order status"`

  ```liquid Liquid theme={null}
  {% assign event = journey.event["order status"] %}
  ```
</ParamField>

<ParamField body="journey.all_events" type="array">
  Todos los eventos almacenados para esta instancia de Journey, en el orden en que fueron almacenados.

  * Usa [bucles for](./using-liquid-syntax#for-loops) para iterar sobre ellos.

  ```liquid Liquid theme={null}
  {% for event in journey.all_events %}
  • {{ event.properties.item | default: "Item" }} — ${{ event.properties.price | default: "0.00" }}
  {% endfor %}
  ```

  * `journey.first_event` es una abreviación de `journey.all_events[0]`.
  * `journey.last_event` es una abreviación del evento más reciente en el array.
</ParamField>

***

## Ejemplo: Plantillas de carrito abandonado usando Custom Events

Este ejemplo muestra cómo personalizar mensajes de carrito abandonado usando Custom Events. Se basa en el [tutorial de Carrito abandonado](./abandoned-cart).

**Conjunto de Custom Events de ejemplo:**

```json JSON theme={null}
{
  "events": [
    {
      "name": "cart_abandoned",
      "properties": {
        "cart_url": "https://yourdomain.com/username/cart",
        "cart": [
          {
            "product_name": "24 Pack of Acorns",
            "product_image": "https://i.imgur.com/ssPCfbC.png",
            "product_price": "$12.99",
            "product_quantity": "1"
          },
          {
            "product_name": "Fancy Sweater",
            "product_image": "https://i.imgur.com/8QWTfV4.png",
            "product_price": "$9.99",
            "product_quantity": "1"
          }
        ]
      },
      "external_id": "ID_OF_THE_USER"
    }
  ]
}
```

### Plantilla de correo electrónico

Este ejemplo muestra cómo crear una plantilla de correo electrónico que muestra:

* La cantidad de artículos en el carrito
* Cada producto con imagen, nombre, cantidad y precio usando un bucle for
* Un botón que enlaza a la URL única del carrito del cliente

<Frame caption="Ejemplo de plantilla de correo electrónico de carrito abandonado">
  <img src="https://mintcdn.com/onesignal/KSCNwSpBCNSQ8xdF/images/docs/fd61543-Screenshot_2023-08-28_at_10.52.05_AM.png?fit=max&auto=format&n=KSCNwSpBCNSQ8xdF&q=85&s=4128b15d8d53d69c6626e129eee538fa" width="693" height="1477" data-path="images/docs/fd61543-Screenshot_2023-08-28_at_10.52.05_AM.png" />
</Frame>

<Steps>
  <Step title="Crear la plantilla de correo electrónico">
    Navega a **Messages > Templates > New Email Template** y abre el editor de arrastrar y soltar.
  </Step>

  <Step title="Agregar la estructura del diseño">
    Crea cinco filas:

    * Filas 1, 2 y 4: una columna con un bloque **Paragraph**
    * Fila 3: cuatro columnas con **HTML | Paragraph | Paragraph | Paragraph**
    * Fila 5: una columna con un bloque **Button**

    <Frame caption="Plantilla de correo electrónico inicial para carrito abandonado">
      <img src="https://mintcdn.com/onesignal/v-hm59YoewwF90UX/images/email/starter-template-abandoned-cart.png?fit=max&auto=format&n=v-hm59YoewwF90UX&q=85&s=551e9ec4618f64fdc0b6ab610a537c48" width="2968" height="2124" data-path="images/email/starter-template-abandoned-cart.png" />
    </Frame>
  </Step>

  <Step title="Mostrar la cantidad de artículos">
    En la fila 1, agrega:

    ```liquid Liquid theme={null}
    We're holding onto {{journey.first_event.properties.cart.size}} items in your cart, but don't wait too long!
    ```

    Para una mejor gramática, podrías usar un condicional para decir "1 item" vs "2 items", pero para correos de carrito abandonado, el plural generalmente es aceptable.

    ```liquid Liquid theme={null}
    {% assign cart = message.custom_data.cart %}
    {% assign item_count = cart.size | plus: 0 %}
    {% if item_count == 1 %}
    We're holding onto {{item_count}} item in your cart, but don't wait too long, other squirrels are getting ahead!
    {% endif %}
    {% if item_count > 1 %}
    We're holding onto {{item_count}} items in your cart, but don't wait too long, other squirrels are getting ahead!
    {% endif %}
    ```
  </Step>

  <Step title="Iniciar el bucle for">
    Usa un [bucle for](./using-liquid-syntax#for-loops) para repetir la fila de visualización del producto para cada artículo del carrito.

    En la fila 2 (inicio del bucle), agrega:

    ```liquid Liquid theme={null}
    {% for product in journey.first_event.properties.cart %}
    ```

    **Qué hace esto:**

    * Inicia un bucle que itera sobre cada objeto en el array `cart`
    * Crea una variable temporal `product` que representa el artículo actual
    * Todo lo que está entre `{% for %}` y `{% endfor %}` se repite una vez por cada artículo del carrito
    * Puedes nombrar `product` como quieras (por ejemplo, `item`, `cartItem`), solo mantén la consistencia

    <Warning>
      Ubicación del bucle for: Asegúrate de que la sintaxis `{% for %}` esté en su propia fila de bloque de texto. No la coloques dentro de una fila de múltiples columnas con otro contenido, ya que esto puede romper el renderizado del correo electrónico en algunos clientes.
    </Warning>
  </Step>

  <Step title="Mostrar los detalles del producto">
    Esta fila de 4 columnas muestra imagen, nombre, cantidad y precio. Como está dentro del bucle, se repite para cada artículo del carrito.

    En la fila 3 (detalles del producto), configura:

    **Columna 1 - Bloque HTML** (imagen del producto):

    ```html theme={null}
    <img src="{{product.product_image}}" alt="Product image" style="max-width:100%;" />
    ```

    **Columnas 2–4 - Bloques de texto** (nombre del producto, cantidad, precio):

    * Columna 2: `{{product.product_name}}`
    * Columna 3: `{{product.product_quantity}}`
    * Columna 4: `{{product.product_price}}`

    **Cómo funciona el bucle:**

    * En la primera iteración, `product` = primer objeto en el array del carrito
    * `{{product.product_image}}` obtiene la imagen del primer artículo
    * En la segunda iteración, `product` = segundo objeto
    * La fila se repite automáticamente para todos los artículos del carrito

    <Warning>
      **Coincidencia de nombres de campo:** Las claves como `product_image` deben coincidir exactamente con el payload de tu evento (distingue mayúsculas y minúsculas). Las diferencias se renderizan como cadenas vacías.
    </Warning>
  </Step>

  <Step title="Cerrar el bucle for">
    Cierra el bucle para marcar dónde termina la repetición.

    En la fila 4 (fin del bucle), agrega:

    ```liquid Liquid theme={null}
    {% endfor %}
    ```

    <Note>
      Cada `{% for %}` debe tener un `{% endfor %}` correspondiente. Si falta, el renderizado del correo electrónico se romperá.
    </Note>
  </Step>

  <Step title="Agregar el botón con la URL del carrito">
    En el bloque **Button** de la fila 5, establece la URL de acción en:

    ```liquid Liquid theme={null}
    {{journey.first_event.properties.cart_url}}
    ```

    <Frame caption="Plantilla de correo electrónico base terminada para carrito abandonado sin estilos">
      <img src="https://mintcdn.com/onesignal/v-hm59YoewwF90UX/images/email/finished-template-abandoned-cart-custom-event.png?fit=max&auto=format&n=v-hm59YoewwF90UX&q=85&s=67217e202cc57ca4039e0b34d2501f15" width="2968" height="1716" data-path="images/email/finished-template-abandoned-cart-custom-event.png" />
    </Frame>
  </Step>

  <Step title="Probar la plantilla">
    * Agrega la plantilla a un Journey en blanco y establece la regla de entrada a un Custom Event.
    * Habilita el Journey e ingrésate a ti mismo a través de la API de Custom Events.
    * Verifica que los datos se muestren correctamente.

    <Check>Ahora puedes aplicar tu propio estilo a la plantilla. Consulta [Diseñar correos electrónicos con arrastrar y soltar](./design-emails-with-drag-and-drop).</Check>
  </Step>
</Steps>

### Plantilla de push

Las notificaciones push tienen espacio limitado, así que muestra un artículo y menciona la cantidad total.

**Campo de mensaje:**

Muestra el artículo y la cantidad con gramática correcta usando [declaraciones condicionales](./using-liquid-syntax#if-elsif-else).

```liquid Liquid theme={null}
{% assign cart = journey.first_event.properties.cart %}
{% assign item_count = cart.size | plus: 0 %}
{% if item_count == 1 %}
You left {{cart.first.product_name}} in your cart.
{% endif %}
{% if item_count == 2 %}
You left {{cart.first.product_name}} and {{item_count | minus: 1}} more item in your cart.
{% endif %}
{% if item_count > 2 %}
You left {{cart.first.product_name}} and {{item_count | minus: 1}} more items in your cart.
{% endif %}
```

**Campo de imagen:**

```liquid Liquid theme={null}
{{journey.first_event.properties.cart.first.product_image | default: "https://i.imgur.com/ssPCfbC.png"}}
```

**Campo de URL de lanzamiento:**

```liquid Liquid theme={null}
{{journey.first_event.properties.cart_url | default: "https://yourdomain.com/cart"}}
```

Envíate una notificación push de prueba agregándola al Journey de prueba e ingresándote a través de otra llamada a la API de Custom Events. Deberías ver una notificación similar a esta:

<Frame caption="Ejemplo de plantilla de push de carrito abandonado">
  <img src="https://mintcdn.com/onesignal/4HyuQPBpu-4xjmQC/images/docs/d0db985-Screenshot_2023-08-28_at_9.30.23_AM.png?fit=max&auto=format&n=4HyuQPBpu-4xjmQC&q=85&s=6cf03ce9b622ba399656f2b14fb055f3" width="688" height="656" data-path="images/docs/d0db985-Screenshot_2023-08-28_at_9.30.23_AM.png" />
</Frame>

<Check>Ahora puedes crear más plantillas y usarlas en el [Journey de carrito abandonado](./abandoned-cart).</Check>

***

## Solución de problemas y mejores prácticas

**Errores comunes:**

| Error                                       | Por qué falla                            | Sintaxis correcta                              |
| ------------------------------------------- | ---------------------------------------- | ---------------------------------------------- |
| `{{ journey.first_event.item }}`            | Falta `.properties`                      | `{{ journey.first_event.properties.item }}`    |
| `{{ journey.event.purchase.item }}`         | Falta `.properties`                      | `{{ journey.event.purchase.properties.item }}` |
| `{{ journey.first_event.properties.Item }}` | Mayúsculas incorrectas (debe ser `item`) | `{{ journey.first_event.properties.item }}`    |
| `{{ event.properties.item }}`               | Falta el prefijo `journey.`              | `{{ journey.first_event.properties.item }}`    |

**Mejores prácticas:**

* Siempre prueba las plantillas antes de ponerlas en producción
* Usa [filtros default](./using-liquid-syntax#default) para propiedades opcionales
* Valida que el esquema del evento coincida con las expectativas de la plantilla

***

## Páginas relacionadas

<Columns cols={2}>
  <Card title="Personalización de mensajes" href="./message-personalization" icon="sparkles">
    Resumen de todas las opciones de personalización en OneSignal, incluyendo cuándo usar Custom Events vs otros métodos.
  </Card>

  <Card title="Custom Events" href="./custom-events" icon="bolt">
    Guía completa para implementar y enviar Custom Events a través de SDK o API.
  </Card>

  <Card title="Resumen de Journeys" href="./journeys-overview" icon="route">
    Aprende cómo crear flujos de trabajo de mensajería automatizados con disparadores, condiciones y acciones.
  </Card>

  <Card title="Configuración de Journeys" href="./journeys-settings" icon="gear">
    Configura reglas de entrada activadas por eventos y el comportamiento de Journeys.
  </Card>

  <Card title="Acciones Wait Until" href="./journeys-actions#wait-until" icon="clock">
    Usa nodos Wait Until para almacenar eventos adicionales durante la progresión del Journey.
  </Card>

  <Card title="Uso de sintaxis Liquid" href="./using-liquid-syntax" icon="droplet">
    Referencia completa de Liquid con filtros, condicionales, bucles y manipulación de cadenas.
  </Card>

  <Card title="Templates" href="./templates" icon="file">
    Crea y gestiona plantillas de mensajes reutilizables para usar en Journeys.
  </Card>
</Columns>

<Info>
  ¿Necesita ayuda?

  Chatee con nuestro equipo de Soporte o envíe un correo electrónico a `support@onesignal.com`

  Por favor incluya:

  * Detalles del problema que está experimentando y pasos para reproducir si están disponibles
  * Su ID de aplicación de OneSignal
  * El ID externo o ID de suscripción si corresponde
  * La URL del mensaje que probó en el panel de OneSignal si corresponde
  * Cualquier [registro o mensaje de error](/docs/es/capturing-a-debug-log) relevante

  ¡Estamos felices de ayudar!
</Info>

***
