> ## 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.

# Personnaliser les messages avec l'API custom_data

> Envoyez des donnees dynamiques et specifiques a chaque message via l'API Create Message en utilisant custom_data. Referencez les valeurs dans les templates avec la syntaxe Liquid pour une personnalisation en temps reel.

Utilisez le champ `custom_data` dans l'[API Create Message](/reference/create-message) pour envoyer des donnees dynamiques depuis votre backend et les afficher dans les templates en utilisant la [syntaxe Liquid](./using-liquid-syntax).

`custom_data` :

* Est **specifique au message**
* N'est **pas stocke**
* Existe uniquement pendant la requete API
* Doit etre utilise avec un `template_id`

Referencez les valeurs dans les templates avec :

```liquid Liquid theme={null}
{{ message.custom_data.key_name }}
```

<Warning>
  `custom_data` est ephemere. Les donnees ne sont pas enregistrees dans les profils utilisateurs et ne peuvent pas etre reutilisees dans de futurs messages. Si vous avez besoin de donnees persistantes, consultez [Personnalisation des messages](./message-personalization).
</Warning>

***

## Quand utiliser `custom_data`

Utilisez `custom_data` lorsque vous avez besoin de :

* Donnees qui changent a chaque message (totaux de commande, articles du panier, soldes)
* Tableaux (listes de produits, lignes de commande, recommandations)
* Donnees qui ne doivent pas persister (codes a usage unique, URLs temporaires)
* Messages declenches depuis le backend
* Personnalisation en masse dans une seule requete API

***

## Comment fonctionne la personnalisation avec `custom_data`

L'ajout de `custom_data` aux messages necessite quelques etapes :

<Steps>
  <Step title="Creer un template">
    Creez un template Push, Email ou SMS dans le [tableau de bord Templates](./templates) ou via l'[API Create Template](/reference/create-template).
  </Step>

  <Step title="Ajouter des espaces reservés Liquid">
    Inserez des references en utilisant le prefixe requis :

    ```liquid Liquid theme={null}
    Hi {{ message.custom_data.first_name }},
    Order {{ message.custom_data.order_id }} is confirmed.
    ```
  </Step>

  <Step title="Envoyer custom_data dans votre requete API">
    Appelez l'[API Create Message](/reference/create-message) avec :

    * `template_id` - L'identifiant du template
    * `custom_data` - L'objet de donnees
    * Ciblage de l'audience (`include_player_ids`, `include_aliases` ou segments)

    OneSignal effectue le rendu du template au moment de l'envoi en utilisant vos donnees.

    Si la syntaxe Liquid est invalide ou si les cles n'existent pas, ces champs s'affichent comme des chaines vides, mais le message est tout de meme envoye.
  </Step>
</Steps>

***

## Modeles de donnees

Exemples courants de modeles de donnees que vous pouvez utiliser avec `custom_data`.

### Exemple JSON simple

Utilisez des paires cle-valeur simples pour une personnalisation basique comme les noms, les identifiants, les URLs ou toute donnee a valeur unique.

**Cas d'utilisation :** Messages transactionnels (factures, recus, confirmations) ou chaque champ contient une seule valeur.

**Template :**

```liquid Liquid theme={null}
Invoice {{ message.custom_data.invoice_id }} for {{ message.custom_data.product_name }} is ready.
```

**Requete API :**

```json JSON theme={null}
{
  "app_id": "YOUR_APP_ID",
  "template_id": "YOUR_TEMPLATE_ID",
  "include_email_tokens": ["user@example.com"],
  "custom_data": {
    "invoice_id": "463246732",
    "product_name": "Widget"
  }
}
```

**Ce que le client voit :**

```liquid Text theme={null}
Invoice 463246732 for Widget is ready.
```

***

### Exemple avec des tableaux de donnees

Transmettez des tableaux d'objets pour travailler avec plusieurs elements comme les produits du panier, les lignes de commande ou les recommandations. Les tableaux permettent a la fois l'acces direct (indexation) et l'iteration (boucles).

**Cas d'utilisation :** Affichage de listes de produits, classements, recapitulatifs de commande ou toute donnee multi-elements.

**Template d'indexation (acces au premier element) :**

```liquid Liquid theme={null}
Your {{message.custom_data.cart_items[0].item_name}} is waiting for you!
Image: {{message.custom_data.cart_items[0].img_url}}
```

<Warning>
  **L'indexation des tableaux commence a 0**, pas a 1. Le premier element est `[0]`, le deuxieme est `[1]`, etc. Acceder a un index qui n'existe pas retourne une valeur vide (aucune erreur n'est generee).
</Warning>

**Template avec boucle (acces a tous les elements) :**

```liquid Liquid theme={null}
{% for item in message.custom_data.cart_items %}
- {{ item.item_name }} — {{ item.img_url }}
{% endfor %}
```

**Requete API :**

```json theme={null}
{
  "app_id": "YOUR_APP_ID",
  "template_id": "YOUR_TEMPLATE_ID",
  "include_email_tokens": ["user@example.com"],
  "custom_data": {
    "cart_items": [
      {
        "item_name": "sweater",
        "img_url": "https://.../sweater.png"
      },
      {
        "item_name": "socks",
        "img_url": "https://.../socks.png"
      }
    ]
  }
}
```

**Ce que le client voit :**

```liquid Text theme={null}
Your sweater is waiting for you!
Image: https://.../sweater.png

- sweater — https://.../sweater.png
- socks — https://.../socks.png
```

**Proprietes utiles des tableaux :**

* `{{message.custom_data.cart_items.size}}` — Nombre d'elements dans le tableau (retourne `2` dans cet exemple)
* `{{message.custom_data.cart_items.first.item_name}}` — Nom du premier element (equivalent a `[0]`)
* `{{message.custom_data.cart_items.last.item_name}}` — Nom du dernier element

***

### Exemple de personnalisation en masse

Envoyez une seule requete API a plusieurs utilisateurs ou chaque destinataire voit un contenu personnalise base sur son `external_id`.

**Comment ca fonctionne :**

1. Structurez `custom_data` comme un objet ou **les cles sont des external\_ids** et **les valeurs sont des donnees specifiques a l'utilisateur**
2. Dans le template, utilisez `subscription.external_id` pour rechercher les donnees du destinataire actuel
3. OneSignal effectue le rendu du template une fois par destinataire avec ses donnees specifiques

**Template :**

```liquid theme={null}
{% assign user = message.custom_data.users[subscription.external_id] %}
Hi {{ user.first_name }}, you have {{ user.points }} points. Your level is {{ user.level }}.
```

**Ce qui se passe :**

* `subscription.external_id` contient l'external\_id du destinataire actuel (par exemple, "user123")
* `message.custom_data.users[subscription.external_id]` recherche les donnees de cet utilisateur dans l'objet custom\_data
* `user` devient une variable raccourci pour les donnees de cet utilisateur
* Chaque destinataire ne voit que son propre contenu personnalise

**Requete API :**

```json theme={null}
{
  "app_id": "YOUR_APP_ID",
  "template_id": "YOUR_TEMPLATE_ID",
  "include_aliases": {
    "external_id": ["user123", "user456"]
  },
  "custom_data": {
    "users": {
      "user123": { "first_name": "John", "points": "150", "level": "Gold" },
      "user456": { "first_name": "Sarah", "points": "200", "level": "Platinum" }
    }
  }
}
```

**Ce que chaque utilisateur voit :**

<Check>
  * **John** (user123) : "Hi John, you have 150 points. Your level is Gold."
  * **Sarah** (user456) : "Hi Sarah, you have 200 points. Your level is Platinum."
</Check>

<Info>
  **Conditions requises pour la personnalisation en masse :**

  * Tous les destinataires doivent avoir un `external_id` defini dans OneSignal
  * Chaque `external_id` dans `include_aliases` doit avoir une cle correspondante dans `custom_data.users`
  * Si l'external\_id d'un destinataire est absent de `custom_data`, son message contiendra des champs vides
</Info>

***

## Exemple : Panier abandonne avec custom\_data

Comment creer des messages de panier abandonne pour l'email et le push en utilisant `custom_data`.

**Quand utiliser cette approche :**

* Votre serveur detecte l'abandon de panier (par exemple, 1 heure apres la derniere activite)
* Les donnees du panier en temps reel sont dans votre base de donnees
* Vous souhaitez afficher plusieurs produits avec images, noms et prix
* Chaque utilisateur peut avoir des articles et des quantites differents
* Vous souhaitez orchestrer le message depuis votre backend

### Exemple de payload `custom_data`

Ceci est la requete [API Create Message](/reference/create-message) pour cet exemple.

```json JSON theme={null}
{
  "custom_data": {
    "cart_url": "https://yourdomain.com/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"
      }
    ]
  },
  "app_id": "YOUR_APP_ID",
  "template_id": "YOUR_TEMPLATE_ID",
  "include_aliases": {
    "external_id": ["YOUR_EXTERNAL_ID"]
  }
}
```

**Explication des champs :**

| Champ              | Type   | Objectif                                                                       |
| ------------------ | ------ | ------------------------------------------------------------------------------ |
| `cart_url`         | string | Lien unique vers le panier du client (pour les boutons/URLs de lancement)      |
| `cart`             | array  | Liste de produits — permet le comptage, les boucles et l'affichage des details |
| `product_image`    | string | Image du produit (par element dans le tableau)                                 |
| `product_name`     | string | Nom du produit (par element)                                                   |
| `product_quantity` | string | Quantite (par element)                                                         |
| `product_price`    | string | Prix avec formatage (par element)                                              |

<Note>
  Vous pouvez nommer les champs comme vous le souhaitez — assurez-vous simplement que la syntaxe Liquid de votre template correspond.
</Note>

<Warning>
  **Restez en dessous de 2 Ko :** Si vous avez de grands paniers, envisagez de limiter aux 3 a 5 premiers articles ou d'envoyer uniquement les champs essentiels pour eviter de depasser la limite de taille.
</Warning>

### Template email

Cet exemple montre comment creer un template email qui affiche :

* Le nombre d'articles dans le panier
* Chaque produit avec son image, son nom, sa quantite et son prix en utilisant une boucle for
* Un bouton qui renvoie vers l'URL unique du panier du client

<Frame caption="Exemple de template email pour panier abandonne">
  <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="Creer le template email">
    Naviguez vers **Messages > Templates > New Email Template** et ouvrez l'editeur Drag & Drop.
  </Step>

  <Step title="Ajouter la structure de mise en page">
    Creez cinq lignes :

    * Lignes 1, 2 et 4 : une colonne avec un bloc **Paragraph**
    * Ligne 3 : quatre colonnes avec **HTML | Paragraph | Paragraph | Paragraph**
    * Ligne 5 : une colonne avec un bloc **Button**

    <Frame caption="Template email de depart pour panier abandonne">
      <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="Afficher le nombre d'articles">
    Dans la ligne 1, ajoutez :

    ```liquid Liquid theme={null}
    We're holding onto {{message.custom_data.cart.size}} items in your cart, but don't wait too long, other squirrels are getting ahead!
    ```

    Pour une meilleure grammaire, vous pourriez utiliser une condition pour dire "1 item" vs "2 items", mais pour les emails de panier abandonne, le pluriel est generalement acceptable.

    ```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="Demarrer la boucle">
    Utilisez une [boucle for](./using-liquid-syntax#for-loops) pour repeter la ligne d'affichage du produit pour chaque article du panier.

    Dans la ligne 2 (debut de la boucle), ajoutez ceci dans le bloc texte :

    ```liquid Text theme={null}
    {% for product in message.custom_data.cart %}
    ```

    **Ce que cela fait :**

    * Demarre une boucle qui itere sur chaque objet dans le tableau `cart`
    * Cree une variable temporaire appelee `product` qui represente l'element actuel
    * Tout ce qui se trouve entre `{% for %}` et `{% endfor %}` se repete une fois par article du panier
    * Vous pouvez nommer `product` comme vous le souhaitez (par exemple, `item`, `cartItem`) — restez simplement coherent

    <Warning>
      Placement de la boucle for : Assurez-vous que la syntaxe `{% for %}` est dans son propre bloc texte dans une ligne separee. Ne la placez pas dans une ligne multi-colonnes avec d'autre contenu, car cela peut casser le rendu de l'email dans certains clients.
    </Warning>
  </Step>

  <Step title="Afficher les details du produit">
    Cette ligne a 4 colonnes affiche l'image, le nom, la quantite et le prix. Puisqu'elle se trouve a l'interieur de la boucle, elle se repete pour chaque article du panier.

    Dans la ligne 3 (details du produit), configurez :

    **Colonne 1 - Bloc HTML** (image du produit) :

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

    **Colonnes 2 a 4 - Blocs texte** (nom du produit, quantite, prix) :

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

    **Comment la boucle fonctionne :**

    * A la premiere iteration, `product` = premier objet dans le tableau cart
    * `{{product.product_image}}` recupere l'URL de l'image du premier article
    * A la deuxieme iteration, `product` = deuxieme objet
    * La ligne se repete automatiquement pour tous les articles du panier

    <Warning>
      **Correspondance des noms de champs :** Les cles comme `product_image` doivent correspondre exactement a votre payload d'evenement (sensible a la casse). Les noms non concordants s'affichent comme des chaines vides.
    </Warning>
  </Step>

  <Step title="Terminer la boucle">
    Fermez la boucle pour marquer ou la repetition s'arrete.

    Dans la ligne 4 (fin de la boucle), ajoutez :

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

    <Note>
      Chaque `{% for %}` doit avoir un `{% endfor %}` correspondant. L'absence de celui-ci cassera le rendu de l'email.
    </Note>
  </Step>

  <Step title="Ajouter un bouton de lien vers le panier">
    Dans le bloc **Button** de la ligne 5, definissez l'URL d'action sur :

    ```liquid Text theme={null}
    {{message.custom_data.cart_url}}
    ```

    <Frame caption="Template email de base termine pour panier abandonne sans stylisation">
      <img src="https://mintcdn.com/onesignal/v-hm59YoewwF90UX/images/email/finished-template-abandoned-cart-custom-data.png?fit=max&auto=format&n=v-hm59YoewwF90UX&q=85&s=d26b638eb17878bb51c28a5e08f77724" width="2968" height="1716" data-path="images/email/finished-template-abandoned-cart-custom-data.png" />
    </Frame>
  </Step>

  <Step title="Tester le template">
    * Configurez votre requete API en utilisant l'[Exemple de payload `custom_data`](#exemple-de-payload-custom_data)
    * Envoyez-vous l'email.
    * Verifiez que les donnees s'affichent correctement.

    <Check>Succes ! Vous pouvez maintenant appliquer votre propre style au template. Consultez [Concevoir des emails avec le glisser-deposer](./design-emails-with-drag-and-drop).</Check>
  </Step>
</Steps>

### Template push

Les notifications push ont des limites de caracteres et des restrictions liees au systeme d'exploitation, donc au lieu d'afficher tous les articles, affichez le premier produit et indiquez le nombre total avec une grammaire correcte.

Voici un exemple de notification push que nous allons creer :

<Frame caption="Exemple de template push pour panier abandonne">
  <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>

**Champ du message :**

```liquid Liquid theme={null}
{% assign cart = message.custom_data.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 %}
```

<Info>
  Consultez [Utilisation de la syntaxe Liquid](./using-liquid-syntax#if-elsif-else) pour plus d'informations.
</Info>

**Champ de l'image :**

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

<Info>
  Consultez [Images de notification et media enrichi](./rich-media) pour plus d'informations.
</Info>

**Champ de l'URL de lancement :**

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

<Check>
  Succes ! Enregistrez le template et utilisez son `template_id` dans votre requete [API Create message](/reference/create-message) avec la propriete `custom_data` pour tester.
</Check>

***

## Depannage et bonnes pratiques

* **Restez simple** : N'incluez que les donnees que vous utiliserez reellement dans le template
* **Restez en dessous de 2 Ko** : Surveillez la taille de votre payload, surtout avec les tableaux
* **Utilisez un nommage coherent** : Tenez-vous au `snake_case` ou au `camelCase` de maniere constante
* **Validez avant d'envoyer** : Verifiez les valeurs nulles, les tableaux vides et les champs obligatoires

**Conception du template :**

* **Utilisez toujours les filtres par defaut** pour les champs optionnels :
  ```liquid Liquid theme={null}
  {{message.custom_data.user_name | default: "there"}}
  ```
* **Verifiez la taille du tableau avant de boucler** :
  ```liquid Liquid theme={null}
  {% if message.custom_data.items.size > 0 %}
    {% for item in message.custom_data.items %}
      {{item.name}}
    {% endfor %}
  {% endif %}
  ```
* **Testez avec des cas limites** : tableaux vides, champs manquants, nombre maximum d'elements

**Gestion des erreurs :**

* Enregistrez les reponses API cote serveur pour detecter les erreurs de validation
* Surveillez les taux de livraison des messages — des baisses soudaines peuvent indiquer des erreurs Liquid
* Gardez des templates de secours prets pour les messages transactionnels critiques

**Performance :**

* **Pre-formatez les donnees complexes** dans votre backend plutot que d'utiliser une logique Liquid complexe
* **Mettez en cache les templates** et reutilisez-les pour de nombreux appels API
* Envisagez de separer les messages transactionnels a fort volume des campagnes marketing

<Accordion title="Le message est envoye mais le contenu est vide">
  **Cause :** Erreurs de syntaxe Liquid ou noms de champs non concordants

  **Solutions :**

  * Verifiez que les noms de champs correspondent exactement entre `custom_data` et le template (sensible a la casse)
  * Verifiez les fautes de frappe : `{{message.custom_data.name}}` et non `{{message.custm_data.name}}`
  * Utilisez les [filtres par defaut](./using-liquid-syntax#default) pour gerer les champs manquants
  * Testez les templates avec la structure `custom_data` reelle avant la mise en production
</Accordion>

<Accordion title="Erreur API : Corps de la requete trop volumineux">
  **Cause :** `custom_data` depasse la limite de 2 Ko

  **Solutions :**

  * Supprimez les champs inutiles de votre payload
  * Raccourcissez les noms de champs et les valeurs lorsque c'est possible
  * Limitez les tableaux aux 3 a 5 premiers elements
  * Deplacez le contenu statique volumineux (comme le HTML complet) dans votre template a la place
</Accordion>

***

## Pages associees

<Columns cols={2}>
  <Card title="Personnalisation des messages" href="./message-personalization" icon="sparkles">
    Apercu de toutes les options de personnalisation dans OneSignal, y compris les Tags, les attributs utilisateur et la segmentation.
  </Card>

  <Card title="API Create Message" href="/reference/create-message" icon="code">
    Reference complete de l'API pour l'envoi de messages avec custom\_data, les options de ciblage et tous les champs disponibles.
  </Card>

  <Card title="Utilisation de la syntaxe Liquid" href="./using-liquid-syntax" icon="droplet">
    Reference complete de la syntaxe Liquid incluant les filtres, les conditions, les boucles et la manipulation de chaines.
  </Card>

  <Card title="Templates" href="./templates" icon="file">
    Creez et gerez des templates de messages reutilisables pour les canaux Push, Email, SMS et In-App.
  </Card>
</Columns>

<Info>
  Besoin d'aide ?

  Discutez avec notre équipe d'assistance ou envoyez un e-mail à `support@onesignal.com`

  Veuillez inclure :

  * Les détails du problème que vous rencontrez et les étapes de reproduction si disponibles
  * Votre OneSignal App ID
  * L'External ID ou le Subscription ID le cas échéant
  * L'URL du message que vous avez testé dans le OneSignal Dashboard le cas échéant
  * Tous les [journaux ou messages d'erreur](/docs/en/capturing-a-debug-log) pertinents

  Nous serons ravis de vous aider !
</Info>

***
