Déclencheurs personnalisés
Les déclencheurs intégrés couvrent les changements qui intéressent la plupart des boutiques. Un déclencheur personnalisé prend en charge le reste : vous choisissez un événement d'Shopify, vous écrivez quelques lignes de JavaScript pour déterminer s'il est pertinent et quelles données envoyer, et vous obtenez ainsi un déclencheur que vous pouvez utiliser dans Shopify Flow.
Il résout trois problèmes qu’un déclencheur intégré ne peut pas résoudre :
- Ne déclenchez l'action qu'à votre condition. « Uniquement lorsqu'une commande supérieure à 500 EUR reçoit le tag
vip» correspond à une seule ligne de code, au lieu d'un workflow qui s'exécute sur chaque commande puis effectue un filtrage. - Déclenchez une action lors d'une transition, et non lors d'un état. Votre code prend en compte la valeur avant et après le changement ; il est donc possible de dire « le statut est passé de "brouillon" à "actif" » ou « le stock est passé en dessous de 5 ». Une condition basée sur la valeur actuelle ne permet pas d'exprimer cela.
- Envoyez uniquement les champs dont vous avez besoin. Adaptez l'événement aux valeurs réellement utilisées par votre workflow, plutôt que de les relire une par une.
Un déclencheur personnalisé n'a même pas besoin d'un événement « Shopify » : il peut également s'exécuter selon un calendrier et déterminer lui-même ce qui a changé.
Comment ça marche ?
- Choisissez le mode de fonctionnement : un événement « Shopify » ou un planning.
- Pour un événement, sélectionnez l'événement qu'il surveille (n'importe quel événement « Shopify » que l'application reçoit déjà) ou partez d'un modèle, qui sélectionne l'événement et génère le code correspondant.
- Capturez une charge utile réelle. Effectuez cette modification dans votre boutique et l'application récupérera le corps exact de l'événement.
- Écrivez une transformation : renvoyez un objet pour déclencher l'action, renvoyez «
null» pour l'ignorer. - Testez-le avec l'événement capturé et voyez exactement ce que votre workflow recevrait.
- Allume-le.

Écriture de la transformation
Votre déclencheur est un module JavaScript qui exporte une fonction nommée « transform ». Elle reçoit quatre arguments :
payload- le corps brut de l'événement Shopify, tel qu'il est reçu.topic- quel événement s'est déclenché, par exemplePRODUCTS_UPDATE.shop- votre domaine MyShopify.ctx-ctx.log(...)affiche des informations dans le panneau de journalisation situé à côté de l'éditeur,ctx.shopify(...)exécute une requête GraphQL d'administration, etctx.fetch(...)appelle une URL accessible sur Internet.
Ce que vous renvoyez détermine la suite des événements :
- Renvoie un objet et le déclencheur se déclenche, en transmettant cet objet.
- Renvoyez «
null» et l'événement sera ignoré. C'est ainsi que fonctionne le filtrage : il n'y a pas de langage de filtrage distinct à apprendre. - Si vous laissez le fichier vide, il se déclenche à chaque événement de ce type.
/**
* Only fire for high-value orders carrying the vip tag.
*/
export async function transform(payload, topic, shop, ctx) {
const total = parseFloat(payload.total_price || "0");
const tags = (payload.tags || "").split(",").map(t => t.trim());
if (total < 500) return null;
if (!tags.includes("vip")) return null;
ctx.log("firing for", payload.name, total);
return {
orderId: payload.admin_graphql_api_id,
orderNumber: payload.name,
total,
currency: payload.currency,
customerEmail: payload.email,
};
}La valeur avant la modification
Shopify
Dans les sections « Mise à jour du produit », « Mise à jour de la commande » et « **Mise à jour du client **», la page payload._changes répertorie tous les champs suivis qui ont été modifiés lors de cette mise à jour, accompagnés respectivement des liens oldValue et newValue :
- Produits :
title,handle,description,status,vendor,productType,tags - Commandes :
financialStatus,fulfillmentStatus,tags,note,lineItemsetcustomAttributes.<name> - Clients :
tags,note,state(ENABLED,DISABLED,INVITED,DECLINED)
Cette liste est vide lorsque la mise à jour ne concerne pas ces champs - une modification d'inventaire, par exemple - ou lorsque l'application accède à l'enregistrement pour la première fois. L'exemple d'événement que vous capturez dans l'éditeur affiche le champ, ce qui vous permet de voir sa structure réelle avant d'y écrire des données.
/**
* Fire only when a product BECOMES active - not on every later edit of an
* active product, which is what a condition on the current status would do.
*/
export async function transform(payload, topic, shop, ctx) {
const change = (payload._changes || []).find((c) => c.field === "status");
if (!change) return null;
if (change.oldValue !== "draft" || change.newValue !== "active") return null;
return {
productId: payload.admin_graphql_api_id,
title: payload.title,
oldStatus: change.oldValue,
newStatus: change.newValue,
};
}Les événements plus spécifiques comportent leurs propres valeurs anciennes et nouvelles ; vous n'avez donc pas besoin d'utiliser « _changes » dans ce cas : une modification de prix comporte « oldPrice », « newPrice » et « percentChange » ; une modification de stock comporte « _oldAvailable », « _newAvailable » et « _delta » ; une modification de méta-champ comporte « previousValue » en plus de « metafield.value ».
Partir d'un modèle
Dans l'éditeur, sous « Fires on », l'option « Start from a template » sélectionne l'événement et insère du code fonctionnel. Modifiez les constantes en haut, testez, puis enregistrez. Chaque modèle lit une valeur avant et après la modification :
- Un champ relatif à un produit, à une commande ou à un client est passé d'une valeur à une autre : le statut est passé de « brouillon » à « actif », une commande a été réglée, un compte a été activé.
- Le prix a baissé de plus de N % : il s'agit d'une véritable réduction, et non d'une simple modification de prix.
- Le stock est passé sous un seuil : le système se déclenche une seule fois, au moment où le stock franchit ce seuil, et non à chaque vente tant que le niveau est déjà bas.
- La valeur d'un méta-champ du produit a dépassé un seuil : une note est passée en dessous de 3, une marge a dépassé 40.
- Commande réglée par un client à forte valeur ajoutée : le système analyse le montant total des achats effectués par ce client dans votre boutique et ne déclenche l’action que si ce montant dépasse le seuil que vous avez défini.

Récupération de données supplémentaires avec ctx.shopify
Le corps des webhooks ne contient que les champs envoyés par l’Shopify. Si vous avez besoin d’autres informations (nombre de commandes d’un client, stock d’une variante, méta-champ, etc.), interrogez directement l’API d’administration depuis votre transform :
export async function transform(payload, topic, shop, ctx) {
const data = await ctx.shopify(`
query($id: ID!) {
customer(id: $id) { numberOfOrders tags }
}
`, { id: payload.customer.admin_graphql_api_id });
// Only fire for repeat customers
if (data.customer.numberOfOrders < 5) return null;
return {
orderId: payload.admin_graphql_api_id,
orderCount: data.customer.numberOfOrders,
};
}Elle renvoie l'data de la requête et lève une exception si celle-ci contient des erreurs, afin qu'une erreur apparaisse dans votre test plutôt que de ne rien renvoyer sans rien signaler.
Trois limites à connaître :
- Jusqu’à 10 appels par exécution. L’enrichissement nécessite une poignée d’appels ; au-delà, on parle généralement d’une boucle. Récupérez ce dont vous avez besoin en une seule requête lorsque c’est possible.
- Elle lit, elle n'écrit pas. Elle utilise les autorisations que vous lui avez accordées, et l'application ne demande jamais que des droits de lecture. Toute requête concernant les données de commande échouera si l'accès aux données de commande n'est pas accordé sur la page « Autorisations ». Pour modifier un élément dans votre boutique, effectuez l'opération dans les actions du flux qui suivent le déclencheur.
- Les identifiants de votre boutique ne sont jamais transmis à votre code. La requête est exécutée par l'application en votre nom ; il n'y a donc aucun jeton d'accès susceptible d'être divulgué au sein de l'environnement de test.
ctx.fetch(url, options) Cela fonctionne comme la fonction « fetch » du navigateur pour tout élément accessible sur l'Internet public : le flux de données de stock d'un fournisseur, un taux de change, votre propre API. Les adresses de réseaux internes et privés sont refusées. Si votre code de déclenchement est enregistré sur GitHub, n'y incluez pas de clé API.
Déclencheurs exécutés selon un calendrier défini
Shopify Flow Il réagit lorsqu'un événement se produit. Il ne peut pas réagir lorsqu'aucun événement ne se produit, et il ne peut rien détecter en dehors de votre boutique. Pour cela, sélectionnez « Selon un calendrier » dans la section « Ce qui déclenche cette action ». Ce type de déclencheur ne repose sur aucun événement «Shopify » : votre code s'exécute à intervalles réguliers, toutes les 30 secondes jusqu'à une fois par jour, et détermine lui-même ce qui constitue un changement.
Il s'agit de la même fonction transform, mais avec une payload différente et une valeur de retour différente :
payload.state- la valeur renvoyée par votre code en tant questatelors de son exécution précédente.nulllors de la première exécution.payload.nowetpayload.lastRunAt- horodatages.{ state, events }renvoyée : le nouvel état à mémoriser (jusqu'à 32 Ko) et une liste d'événements à déclencher (jusqu'à 100 par exécution). Chaque événement déclenche une fois le « Custom Trigger » ; l'resourceIdd'un événement, si vous en avez défini un, devient l'identifiant de l'enregistrement dans Flow. Renvoyez «null» lorsqu'il n'y a rien à signaler.
Lors de la première exécution, contentez-vous d'enregistrer les données, sans jamais déclencher d'action. Lors de sa première exécution, votre code n'a aucun élément de comparaison, donc tout lui paraîtra nouveau. Enregistrez ce que vous observez sans renvoyer d'événements ; ainsi, l'activation du déclencheur n'encombrera jamais vos flux de travail. Tous les modèles fonctionnent de cette manière.

// Fires when a value at a JSON URL changes, with the value before and after.
const URL = "https://api.example.com/stock/1042"
export async function transform(payload, topic, shop, ctx) {
const res = await ctx.fetch(URL, { headers: { accept: "application/json" } })
if (!res.ok) throw new Error("The URL answered with HTTP " + res.status)
const value = String((await res.json()).stock)
// The first run only remembers the value.
const previous = payload.state ? payload.state.value : undefined
if (previous === undefined || previous === value) return { state: { value } }
return {
state: { value },
events: [{ oldValue: previous, newValue: value }],
}
}Modèles pour les déclencheurs planifiés, dans la section « Démarrer à partir d'un modèle » de la fiche « Planification » :
- Produit, commande ou client non mis à jour depuis N jours : avis obsolètes sur le catalogue, commandes bloquées, campagne de reconquête. Chaque enregistrement déclenche une action une fois par période d'inactivité, et les éléments déjà en retard au moment de l'activation ne sont pas tous traités en même temps.
- Une valeur hors de Shopify a été modifiée : un flux de stock fournisseur, un taux de change, une liste de prix, avec la différence et le pourcentage pour les chiffres.
- Nouvel élément dans un flux RSS ou Atom : actualités d'un fournisseur, flux de listes, page d'état.
- Aucune commande depuis N heures : le pouls de votre boutique. Se déclenche une fois lorsque les commandes cessent et une fois lorsqu'elles reprennent.
La fonction « Test » exécute votre code une seule fois sans déclencher aucune action et sans enregistrer l'état, ce qui vous permet de l'exécuter autant de fois que vous le souhaitez.
Utilisation dans « Shopify Flow »
Chaque déclencheur personnalisé apparaît dans Flow sous la même appellation : « Déclencheur personnalisé ». Ajoutez-le à un flux de travail, puis définissez une condition selon laquelle le « nom du déclencheur » doit correspondre au nom de votre déclencheur.
Ce nom d'identifiant apparaît sur la page du déclencheur et ne change jamais, même si vous renommez le déclencheur ; votre flux de travail continue donc de fonctionner.
Chaque clé renvoyée par votre transformation devient un champ du déclencheur, et l'objet complet est également disponible au format JSON si vous préférez l'analyser vous-même.
Conservez le code sur GitHub
Vous pouvez connecter un dépôt GitHub afin que votre code de déclenchement soit soumis au contrôle de version. Les modifications peuvent alors être examinées dans une pull request ; vous pouvez voir qui a modifié quoi et revenir en arrière si une transformation ne fonctionne plus.
Configurez-le sur la page « Développeurs », dans la section « Connexions ». Vous choisissez les dépôts auxquels l'application a accès, et vous pouvez révoquer cet accès depuis GitHub à tout moment.
Une fois le référentiel sélectionné, tous les déclencheurs existants y sont immédiatement enregistrés, et la synchronisation s'effectue dans les deux sens :
| Ce que vous faites | Que se passe-t-il ? |
|---|---|
| Créer, modifier ou dupliquer un déclencheur dans l'application | Le fichier a été validé dans votre dépôt. |
| Supprimer un déclencheur dans l'application | Le fichier est supprimé de votre référentiel. |
| Appliquer une modification à la branche connectée | Le code du déclencheur est mis à jour dans l'application |
Chaque déclencheur correspond à un fichier portant le nom de son identifiant, qui contient exactement le module tel qu'il s'affiche dans l'éditeur - sans aucun élément supplémentaire. Cela signifie que vous pouvez l'ouvrir dans votre propre éditeur, l'exécuter et le valider comme n'importe quel autre fichier JavaScript.
Revenir à une version antérieure
Il n'est pas nécessaire de connaître Git pour annuler une modification. Une fois le dépôt connecté, l'éditeur affiche un menu déroulant « Version » répertoriant toutes les versions précédentes de ce fichier, avec leur date et leur auteur. Choisissez-en une : elle s'affiche alors dans l'éditeur en tant que modification non enregistrée, ce qui vous permet de la consulter au préalable. C'est en enregistrant que vous la réintégrez.
Testez pendant que vous modifiez le fichier localement
Si vous modifiez le fichier dans votre propre éditeur, vous pouvez l'exécuter sur l'événement d'exemple capturé sans avoir à l'enregistrer au préalable dans l'application. Utilisez une clé API avec le niveau d'exécution disponible sur la page Développeur :
curl -X POST https://shopify.workflow-trigger-extensions.app/api/v1/triggers/custom/high-value-vip-order/test \
-H "Authorization: Bearer ftk_your_key_here" \
-H "Content-Type: application/json" \
-d "$(jq -Rn --rawfile c flow-triggers/high-value-vip-order.js '{code:$c}')"Vous obtenez le même résultat que celui affiché par le bouton « Test » de l'application : si la méthode se déclenche, l'objet de sortie, vos lignes d'ctx.logs et la durée d'exécution.
Cet endpoint ne déclenche aucune action et n'effectue aucune sauvegarde ; il n'utilise pas non plus de quota de forfait. Il peut donc être exécuté en toute sécurité à chaque sauvegarde effectuée par un observateur de fichier. (Le bouton « Exécuter le test » de l'application déclenche quant à lui votre workflow Flow, ce qui vous permet de le suivre de bout en bout ; cette opération est également gratuite.)
Vous pouvez également récupérer la charge utile d'exemple séparément à l'aide d'une clé de lecture, l'enregistrer localement et exécuter le fichier entièrement hors ligne :
curl https://shopify.workflow-trigger-extensions.app/api/v1/triggers/custom/high-value-vip-order/test \
-H "Authorization: Bearer ftk_your_key_here"Un déclencheur personnalisé utilise-t-il le volume inclus dans mon forfait ?▾
Oui, et il comptabilise tous les événements qu’il analyse, pas seulement ceux qui déclenchent une action. Si votre déclencheur écoute l’événement « Mise à jour de produit » et que votre boutique enregistre 60 000 mises à jour de produit par mois, cela représente 60 000 événements, même si votre code ne réagit qu’à 100 d’entre eux.
Nous recevons, dédupliquons et mettons en file d'attente chacun de ces événements, puis nous exécutons votre code dans un environnement isolé (sandbox) - tout cela avant que votre code ne décide de se déclencher ou non. Ce nombre reflète ce travail.
En d'autres termes : cela coûte la même chose que si vous aviez utilisé le déclencheur intégré pour le même événement. Le filtrage ne vous est pas facturé en supplément, et les tests sont toujours gratuits. Un déclencheur programmé est comptabilisé une fois par exécution.
Le dépistage est-il gratuit ?▾
Oui. Le bouton « Exécuter le test » de l'application et le point de terminaison API « /test » sont tous deux exclus de ce comptage, même si le bouton « Exécuter le test » déclenche réellement votre workflow Flow afin que vous puissiez observer son exécution. Seules les exécutions en production sont comptabilisées dans votre quota ; vous pouvez donc itérer autant que vous le souhaitez sur une transformation.
Pourquoi la variable « payload._changes » est-elle vide ?▾
Soit la mise à jour concernait des champs non suivis - une modification de l'inventaire ou d'une variante d'un produit, par exemple - , soit l'application ne dispose pas encore de référence pour cet enregistrement. La référence est enregistrée la première fois que l'application détecte un enregistrement ; ainsi, la toute première mise à jour d'un enregistrement qu'elle n'a jamais vu ne comporte aucune valeur antérieure. Toutes les mises à jour suivantes en comportent une.
Mon code peut-il modifier les données de ma boutique ?▾
Non. L'application «ctx.shopify » fonctionne avec les autorisations de lecture que vous lui avez accordées, et elle ne demande jamais d'accès en écriture. C'est voulu : un déclencheur qui modifie l'enregistrement qu'il surveille se relance automatiquement, ce qui provoque une boucle - c'est pour cette raison que l'Shopify désactive les workflows. Modifiez les données dans les actions Flow qui suivent le déclencheur.
Puis-je changer la poignée plus tard ?▾
Non, et c'est voulu. Votre workflow Flow utilise le « handle » comme critère de filtrage ; par conséquent, le modifier mettrait fin à l'exécution de ce workflow sans avertissement. Vous pouvez renommer le déclencheur comme vous le souhaitez : le « handle » reste inchangé.
Ce nom d'utilisateur correspond également au nom du fichier dans votre dépôt GitHub ; il ne change donc jamais non plus.
Que se passe-t-il si mon code contient un bug ?▾
L'événement est ignoré et l'erreur est consignée au niveau du déclencheur, ce qui vous permet de voir ce qui s'est mal passé. Une transformation qui échoue ne bloque jamais rien d'autre : vos autres déclencheurs, qu'ils soient personnalisés ou intégrés, continuent de fonctionner normalement.
Où mon code s'exécute-t-il ?▾
Dans un environnement isolé, distinct du reste de l'application, avec un délai limité et sans accès aux identifiants de votre boutique. Il ne voit que la charge utile de l'événement que vous avez capturée, ainsi que les informations que vous récupérez via ctx.shopify ou ctx.fetch.
Que se passe-t-il si je modifie le fichier à la fois sur GitHub et dans l'application ?▾
C'est la dernière sauvegarde qui prévaut. Enregistrer dans l'application valide les modifications dans le fichier, tandis qu'un push vers la branche connectée écrase le code conservé dans l'application. Si vous travaillez principalement dans votre dépôt, considérez l'éditeur de l'application comme étant en lecture seule pour éviter toute mauvaise surprise.
Un fichier de mon référentiel peut-il créer un nouveau déclencheur ?▾
Non. Un déclencheur doit également savoir à quel événement d'Shopify il est associé, et le fichier ne contient que du code : deviner l'événement risquerait de le relier à la mauvaise action. Créez d'abord le déclencheur dans l'application, puis modifiez son fichier comme vous le souhaitez.
Peut-il se déclencher lors d'événements que l'application ne reçoit pas déjà ?▾
Non. Un déclencheur personnalisé écoute les événements auxquels l'application est déjà abonnée pour votre boutique, ce qui dépend des autorisations que vous avez accordées. Accordez l'autorisation pour une ressource et ses événements deviendront également disponibles pour les déclencheurs personnalisés. Pour tout autre cas, exécutez-le selon une planification.
Prochaines étapes
- API développeur, MCP, GitHub et simulation de déclenchement - gérer et tester les déclencheurs à partir de votre propre code ou d'un assistant IA.
- Générer du code de déclenchement à l'aide de l'IA - Décrivez le déclencheur en termes simples et laissez l'IA écrire le code.
- Forfaits et utilisation - ce qui est considéré comme un événement et comment fonctionne l'indemnité.
- Comment fonctionnent les déclencheurs ? - les déclencheurs intégrés et leur fonctionnement.

