Benutzerdefinierte Auslöser
Die integrierten Trigger decken die Änderungen ab, die für die meisten Shops von Bedeutung sind. Ein benutzerdefinierter Trigger deckt den Rest ab: Sie wählen ein Ereignis aus Shopify aus, schreiben ein paar Zeilen JavaScript, um zu entscheiden, ob es relevant ist und welche Daten gesendet werden sollen, und schon wird daraus ein Trigger, den Sie in Shopify Flow verwenden können.
Drei Probleme, die damit gelöst werden, was ein integrierter Trigger nicht kann:
- Feuer nur unter deiner Bedingung. „Nur wenn eine Bestellung über 500 EUR das Tag
viperhält“ ist eine einzige Codezeile - statt eines Workflows, der bei jeder Bestellung ausgeführt wird und dann filtert. - Wende den Übergang aus, nicht den Zustand. Dein Code erkennt den Wert vor und nach der Änderung, daher sind Aussagen wie „Der Status hat sich von ‚Entwurf‘ zu ‚aktiv‘ geändert“ oder „Der Lagerbestand ist unter 5 gefallen“ möglich. Eine Bedingung, die sich auf den aktuellen Wert bezieht, kann dies nicht ausdrücken.
- Senden Sie genau die Felder, die Sie benötigen. Passen Sie das Ereignis an die Werte an, die Ihr Workflow tatsächlich verwendet, anstatt diese einzeln wieder auszulesen.
Ein benutzerdefinierter Trigger benötigt nicht einmal ein Shopify-Ereignis: Er kann auch nach einem Zeitplan ausgeführt werden und selbst entscheiden, was sich geändert hat.
So funktioniert es
- Wählen Sie aus, wie die Ausführung gesteuert werden soll: einmalig als Shopify-Ereignis oder nach Zeitplan.
- Wählen Sie für ein Ereignis das Ereignis aus, auf das es reagiert - jedes Shopify-Ereignis, das die App bereits empfängt - oder beginnen Sie mit einer Vorlage, die das Ereignis auswählt und den Code ausfüllt.
- Erfassen Sie eine echte Nutzlast. Nehmen Sie diese Änderung in Ihrem Shop vor, und die App erfasst den genauen Ereignisinhalt.
- Schreibe eine Transformation - gib ein Objekt zurück, um die Aktion auszulösen, und gib
nullzurück, um sie zu überspringen. - Testen Sie es anhand des erfassten Ereignisses und sehen Sie genau, was Ihr Workflow erhalten würde.
- Schalte es ein.

Die Transformation schreiben
Ihr Trigger ist ein JavaScript-Modul, das eine Funktion namens transform exportiert. Diese Funktion erhält vier Argumente:
payload- der Rohtext des Shopify-Ereigniskörpers, genau so, wie er eingeht.topic- welches Ereignis ausgelöst wurde, zum BeispielPRODUCTS_UPDATE.shop- Ihre MyShopify-Domain.ctx-ctx.log(...)gibt eine Meldung im Protokollbereich neben dem Editor aus,ctx.shopify(...)führt eine Admin-GraphQL-Abfrage aus undctx.fetch(...)ruft eine URL im öffentlichen Internet auf.
Was du zurückgibst, entscheidet darüber, was passiert:
- Gibt ein Objekt zurück, woraufhin der Trigger ausgelöst wird und dieses Objekt übergibt.
- Geben Sie
nullzurück, und das Ereignis wird übersprungen. So funktioniert die Filterung - es muss keine separate Filtersprache erlernt werden. - Lassen Sie die Datei leer, dann wird sie bei jedem Ereignis dieses Typs ausgelöst.
/**
* 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,
};
}Der Wert vor der Änderung
Shopify
Bei Produkt-, Bestell- und Kundenaktualisierungen listet payload._changes alle nachverfolgten Felder auf, die durch diese Aktualisierung geändert wurden, jeweils mit den Links oldValue und newValue:
- Produkte:
title,handle,description,status,vendor,productType,tags - Bestellungen:
financialStatus,fulfillmentStatus,tags,note,lineItemsundcustomAttributes.<name> - Kunden:
tags,note,state(ENABLED,DISABLED,INVITED,DECLINED)
Die Liste ist leer, wenn die Aktualisierung nicht diese Felder betraf - beispielsweise bei einer Bestandsänderung - oder wenn die App den Datensatz zum ersten Mal sieht. Das Beispielereignis, das Sie im Editor erfassen, zeigt das Feld an, sodass Sie dessen tatsächliche Struktur sehen können, bevor Sie Daten darin speichern.
/**
* 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,
};
}Die spezifischeren Ereignisse verfügen über eigene alte und neue Werte, sodass Sie dort _changes nicht benötigen: Eine Preisänderung hat oldPrice, newPrice und percentChange; eine Bestandsänderung hat _oldAvailable, _newAvailable und _delta; eine Metafeldänderung hat previousValue neben metafield.value.
Mit einer Vorlage beginnen
Wenn im Editor „Fires on“ ausgewählt ist, wählt die Option „Aus Vorlage starten“ das Ereignis aus und fügt funktionierenden Code ein. Bearbeiten Sie die Konstanten oben, testen Sie den Code und speichern Sie ihn anschließend. Jede Vorlage liest vor und nach der Änderung einen Wert aus:
- Ein Produkt-, Auftrags- oder Kundenfeld wurde von einem Wert auf einen anderen geändert - der Status wechselte von „Entwurf“ zu „Aktiv“, ein Auftrag wurde bezahlt, ein Konto wurde freigeschaltet.
- Der Preis ist um mehr als N Prozent gesunken - eine echte Preissenkung, nicht nur eine beliebige Preisänderung.
- Der Lagerbestand ist unter einen Schwellenwert gefallen - es wird einmal ausgelöst, sobald der Lagerbestand die Grenze unterschreitet, nicht bei jedem Verkauf, solange er bereits niedrig ist.
- Die Zahl eines Produkt-Metafeldes hat einen Schwellenwert überschritten - eine Bewertung ist unter 3 gefallen, eine Marge ist über 40 gestiegen.
- Bestellung, die von einem Großkunden bezahlt wurde - liest die Gesamtumsätze des Kunden in Ihrem Shop aus und löst erst ab dem von Ihnen festgelegten Betrag aus.

Abrufen zusätzlicher Daten mit ctx.shopify
Webhook-Inhalte enthalten ausschließlich die Felder, die von Shopify gesendet werden. Wenn Sie weitere Informationen benötigen - beispielsweise die Anzahl der Bestellungen eines Kunden, den Lagerbestand einer Variante oder ein Metafeld -, fragen Sie die Admin-API direkt aus Ihrer Transformation ab:
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,
};
}Sie gibt den data der Abfrage zurück und löst eine Ausnahme aus, wenn die Abfrage Fehler enthält, sodass in Ihrem Test ein Fehler angezeigt wird, anstatt stillschweigend keine Ausgabe zu erzeugen.
Drei wichtige Grenzwerte:
- Bis zu 10 Aufrufe pro Durchlauf. Für die Anreicherung reicht eine Handvoll; bei mehr ist in der Regel eine Schleife erforderlich. Holen Sie sich das, was Sie brauchen, nach Möglichkeit in einer einzigen Abfrage.
- Die App liest nur, sie schreibt nicht. Sie nutzt die von Ihnen erteilten Berechtigungen, und die App fordert ausschließlich Lesezugriff an. Eine Abfrage von Bestelldaten schlägt fehl, sofern auf der Seite „Berechtigungen“ kein Zugriff auf Bestelldaten gewährt wurde. Wenn Sie etwas in Ihrem Shop ändern möchten, tun Sie dies in den Flow-Aktionen, die auf den Auslöser folgen.
- Die Anmeldedaten Ihres Shops gelangen niemals in Ihren Code. Die Abfrage wird von der App in Ihrem Auftrag ausgeführt, sodass es in der Sandbox kein Zugriffstoken gibt, das offengelegt werden könnte.
ctx.fetch(url, options) Funktioniert wie die Funktion fetch des Browsers für alle Inhalte im öffentlichen Internet: den Bestandsfeed eines Anbieters, einen Wechselkurs, Ihre eigene API. Interne und private Netzwerkadressen werden abgelehnt. Wenn Ihr Trigger-Code auf GitHub gespeichert ist, fügen Sie dort keinen API-Schlüssel ein.
Trigger, die nach einem Zeitplan ausgeführt werden
Shopify Flow reagiert, wenn etwas passiert. Es kann nicht reagieren, wenn nichts passiert, und es kann nichts außerhalb Ihres Shops erkennen. Wählen Sie dazu unter „Was löst diesen Vorgang aus?“ die Option „Nach Zeitplan“ aus. Hinter einem solchen Auslöser steht kein Shopify-Ereignis: Ihr Code wird in bestimmten Intervallen ausgeführt - von alle 30 Sekunden bis zu einmal täglich - und entscheidet selbst, was als Änderung gilt.
Es handelt sich um dieselbe Funktion transform, allerdings mit einem anderen payload und einem anderen Rückgabewert:
payload.state- den Wert, den Ihr Code beim letzten Durchlauf alsstatezurückgegeben hat. Beim ersten Durchlauf ist diesnull.payload.nowsowiepayload.lastRunAt- Zeitstempel.- Gibt
{ state, events }zurück: den neuen zu speichernden Status (bis zu 32 KB) und eine Liste der auszulösenden Ereignisse (bis zu 100 pro Durchlauf). Jedes Ereignis löst den benutzerdefinierten Trigger einmal aus; dieresourceIdeines Ereignisses, sofern festgelegt, wird zur Datensatz-ID in Flow. Gibtnullzurück, wenn nichts zu melden ist.
Stellen Sie sicher, dass der Code beim ersten Durchlauf nur Daten erfasst, aber keine Ereignisse auslöst. Beim ersten Durchlauf hat Ihr Code noch keine Vergleichsdaten, sodass alles neu erscheint. Speichern Sie die erfassten Daten und geben Sie keine Ereignisse zurück; wenn Sie den Trigger aktivieren, werden Ihre Workflows niemals überflutet. Alle Vorlagen verfahren so.

// 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 }],
}
}Vorlagen für geplante Auslöser unter „Aus einer Vorlage starten“ auf der Karte „Zeitplan“:
- Produkt, Bestellung oder Kunde seit N Tagen nicht aktualisiert - veraltete Katalogbewertungen, festgefahrene Bestellungen, Rückgewinnung. Jeder Datensatz wird einmal pro Ruhephase ausgelöst, und bereits überfällige Einträge zum Zeitpunkt der Aktivierung werden nicht alle auf einmal ausgelöst.
- Ein Wert außerhalb von Shopify wurde geändert - ein Lieferantenbestandsfeed, ein Wechselkurs, eine Preisliste, wobei es sich bei den Zahlen um die Differenz und den Prozentsatz handelt.
- Neuer Eintrag in einem RSS- oder Atom-Feed - Nachrichten von Anbietern, ein Produktverzeichnis-Feed, eine Statusseite.
- Keine Bestellungen seit N Stunden - ein „Herzschlag“ für Ihren Shop. Wird einmal ausgelöst, wenn keine Bestellungen mehr eingehen, und einmal, wenn wieder Bestellungen eingehen.
„Test“ führt Ihren Code einmal aus, ohne etwas auszulösen und ohne den Zustand zu speichern, sodass Sie ihn so oft ausführen können, wie Sie möchten.
Verwendung in Shopify Flow
Jeder benutzerdefinierte Trigger wird in Flow als derselbe Trigger angezeigt: „Benutzerdefinierter Trigger“. Fügen Sie ihn einem Workflow hinzu und legen Sie anschließend die Bedingung „Trigger-Handle entspricht dem Handle Ihres Triggers“ fest.
Dieser Name wird auf der Seite des Triggers angezeigt und ändert sich nie, auch wenn Sie den Trigger umbenennen - so bleibt Ihr Arbeitsablauf weiterhin funktionsfähig.
Jeder Schlüssel, den Ihre Transformation zurückgibt, wird zu einem Feld im Trigger, und das gesamte Objekt steht auch als JSON zur Verfügung, falls Sie es lieber selbst auswerten möchten.
Speichere den Code auf GitHub
Sie können ein GitHub-Repository verknüpfen, damit Ihr Trigger-Code unter Versionskontrolle steht. Änderungen können dann in einem Pull-Request überprüft werden, Sie können sehen, wer was geändert hat, und Sie können eine Transformation zurücksetzen, die nicht mehr funktioniert.
Richten Sie die Verbindung auf der Entwickler-Seite unter „Verbindungen“ ein. Dort legen Sie fest, auf welche Repositorys die App zugreifen darf, und können diesen Zugriff jederzeit über GitHub widerrufen.
Sobald ein Repository ausgewählt wurde, werden alle vorhandenen Trigger sofort dorthin geschrieben, und die Synchronisation erfolgt in beide Richtungen:
| Was Sie tun | Was passiert? |
|---|---|
| Einen Trigger in der App erstellen, bearbeiten oder duplizieren | Die Datei wurde in Ihr Repository übertragen. |
| Einen Trigger in der App löschen | Die Datei wird aus Ihrem Repository entfernt |
| Eine Änderung an den verbundenen Zweig übertragen | Der Code des Triggers wird in der App aktualisiert |
Jeder Trigger ist eine Datei, die nach ihrem Handle benannt ist und genau das Modul enthält, das Sie im Editor sehen - ohne jeglichen zusätzlichen Code. Das bedeutet, dass Sie die Datei in Ihrem eigenen Editor öffnen, ausführen und wie jede andere JavaScript-Datei auf Fehler überprüfen können.
Zu einer früheren Version zurückkehren
Sie müssen sich nicht mit Git auskennen, um eine Änderung rückgängig zu machen. Sobald eine Verbindung zu einem Repository hergestellt ist, zeigt der Editor ein Dropdown-Menü „Version“ an, in dem alle früheren Versionen dieser Datei mit Datum und Autor aufgelistet sind. Wählen Sie eine davon aus, und sie wird als ungespeicherte Änderung in den Editor geladen, sodass Sie sie zunächst lesen können - erst durch das Speichern wird sie wiederhergestellt.
Testen Sie während der lokalen Bearbeitung
Wenn Sie die Datei in Ihrem eigenen Editor bearbeiten, können Sie sie mit dem erfassten Beispielereignis ausführen, ohne sie zuvor in der App zu speichern. Verwenden Sie dazu einen API-Schlüssel mit der Berechtigungsstufe „execute“ von der Entwicklerseite:
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}')"Sie erhalten dasselbe Ergebnis, das auch die Schaltfläche „Test“ der App anzeigt: ob die Funktion ausgelöst würde, das Ausgabeobjekt, Ihre ctx.log-Zeilen und die Ausführungszeit.
Dieser Endpunkt löst keine Aktionen aus und speichert keine Daten; außerdem verbraucht er kein Kontingent - daher kann er bedenkenlos bei jedem Speichervorgang eines Datei-Watchers ausgeführt werden. (Die Schaltfläche „Test ausführen“ in der App löst Ihren Flow-Workflow aus, sodass Sie dessen Ausführung von Anfang bis Ende verfolgen können; auch das ist kostenlos.)
Sie können die Beispiel-Nutzlast auch separat mit einem Leseschlüssel abrufen, lokal speichern und die Datei vollständig offline ausführen:
curl https://shopify.workflow-trigger-extensions.app/api/v1/triggers/custom/high-value-vip-order/test \
-H "Authorization: Bearer ftk_your_key_here"Wird bei einem benutzerdefinierten Trigger mein Kontingent aus meinem Tarif aufgebraucht?▾
Ja, und es zählt jedes Ereignis, das es überwacht - nicht nur diejenigen, bei denen es ausgelöst wird. Wenn Ihr Trigger auf „Produktaktualisierung“ reagiert und Ihr Shop monatlich 60.000 Produktaktualisierungen verzeichnet, sind das 60.000 Ereignisse, selbst wenn Ihr Code nur bei 100 davon ausgelöst wird.
Wir empfangen jedes dieser Ereignisse, entfernen Duplikate und stellen es in die Warteschlange, bevor wir Ihren Code in einer isolierten Sandbox ausführen - und zwar noch bevor Ihr Code entscheidet, ob er ausgelöst wird. Die Anzahl spiegelt diesen Arbeitsaufwand wider.
Anders ausgedrückt: Es kostet genauso viel wie der integrierte Trigger für dasselbe Ereignis. Für die Filterung fallen keine zusätzlichen Kosten an, und das Testen ist immer kostenlos. Ein geplanter Trigger wird einmal pro Durchlauf gezählt.
Ist der Test kostenlos?▾
Ja. Sowohl die Schaltfläche „Test ausführen“ in der App als auch der API-Endpunkt /test sind davon ausgenommen, obwohl „Test ausführen“ Ihren Flow-Workflow tatsächlich auslöst, sodass Sie dessen Ausführung beobachten können. Nur Live-Ausführungen werden auf Ihr Kontingent angerechnet, sodass Sie eine Transformation so oft wiederholen können, wie Sie möchten.
Warum ist „payload._changes“ leer?▾
Entweder lag die Aktualisierung außerhalb der erfassten Felder - beispielsweise eine Bestands- oder Variantenänderung bei einem Produkt - oder die App verfügt noch über keine Baseline für diesen Datensatz. Die Baseline wird gespeichert, sobald die App einen Datensatz zum ersten Mal erkennt; daher enthält die allererste Aktualisierung eines Datensatzes, den die App noch nie gesehen hat, keinen alten Wert. Jede nachfolgende Aktualisierung enthält jedoch einen alten Wert.
Kann mein Code Daten in meinem Speicher ändern?▾
Nr. ctx.shopify wird mit den von Ihnen gewährten Leserechten ausgeführt, und die App fordert niemals Schreibzugriff an. Das ist beabsichtigt: Ein Trigger, der den Datensatz bearbeitet, den er überwacht, löst sich selbst erneut aus - genau diese Endlosschleife verhindert Shopify, indem es Workflows deaktiviert. Ändern Sie die Daten in den Flow-Aktionen, die auf den Trigger folgen.
Kann ich den Griff später austauschen?▾
Nein, und das ist beabsichtigt. Ihr Flow-Workflow filtert anhand des Handles, sodass eine Änderung dieses Handles die Ausführung des Workflows stillschweigend unterbrechen würde. Sie können den Trigger beliebig umbenennen - das Handle bleibt unverändert.
Der Handle ist gleichzeitig der Dateiname in Ihrem GitHub-Repository, sodass auch dieser niemals wechselt.
Was passiert, wenn mein Code einen Fehler enthält?▾
Das Ereignis wird übersprungen und der Fehler wird im Trigger protokolliert, sodass Sie sehen können, was schiefgelaufen ist. Eine fehlgeschlagene Transformation blockiert niemals andere Vorgänge - Ihre anderen Trigger, ob benutzerdefiniert oder integriert, laufen unbeeinträchtigt weiter.
Wo wird mein Code ausgeführt?▾
In einer isolierten Sandbox, getrennt vom Rest der App, mit einem kurzen Zeitlimit und ohne Zugriff auf die Anmeldedaten Ihres Shops. Es sieht ausschließlich die von Ihnen erfasste Ereignis-Nutzlast sowie alles, was Sie über ctx.shopify oder ctx.fetch abrufen.
Was passiert, wenn ich die Datei gleichzeitig in GitHub und in der App bearbeite?▾
Was auch immer Sie zuletzt speichern, hat Vorrang. Das Speichern in der App führt zu einer Commit-Aktivität in der Datei, und das Pushen in den verbundenen Branch überschreibt den in der App gespeicherten Code. Wenn Sie überwiegend in Ihrem Repository arbeiten, sollten Sie den Editor der App als schreibgeschützt betrachten, um Überraschungen zu vermeiden.
Kann eine Datei in meinem Repository einen neuen Trigger auslösen?▾
Nein. Ein Trigger muss außerdem wissen, auf welches Shopify-Ereignis er reagiert, und die Datei enthält nur Code - würde man das Ereignis erraten, würde der Trigger auf das falsche Ereignis abgebunden werden. Erstellen Sie den Trigger zunächst in der App und bearbeiten Sie dann die Datei nach Belieben.
Kann es bei Ereignissen ausgelöst werden, die die App noch nicht erhält?▾
Nein. Ein benutzerdefinierter Trigger überwacht die Ereignisse, die die App bereits für Ihren Shop abonniert hat - dies hängt von den Berechtigungen ab, die Sie erteilt haben. Wenn Sie die Berechtigung für eine Ressource erteilen, stehen deren Ereignisse auch benutzerdefinierten Triggern zur Verfügung. Für alles andere sollten Sie einen Zeitplan festlegen.
Nächste Schritte
- Entwickler-API, MCP, GitHub und Triggersimulation - Trigger über Ihren eigenen Code oder einen KI-Assistenten verwalten und testen.
- Trigger-Code mit KI generieren - Beschreiben Sie den Trigger in einfacher Sprache und lassen Sie die KI den Code schreiben.
- Pläne und Nutzung - Was gilt als Ereignis und wie funktioniert die Beihilfe?
- So funktionieren Trigger - die integrierten Trigger und wie sie ausgelöst werden.

