Anpassade utlösare
Skapa en anpassad utlösare i Shopify Flow från valfri Shopify-händelse eller ett schema, med värden före och efter och egna villkor i JavaScript.
De inbyggda utlösarna täcker de förändringar som de flesta butiker bryr sig om. En anpassad utlösare täcker resten: du väljer en Shopify-händelse, skriver några rader JavaScript för att avgöra om den är relevant och vad som ska skickas, och så blir den en utlösare som du kan använda i Shopify Flow.
Tre saker som den klarar av, men som en inbyggd utlösare inte klarar:
- Skjut endast enligt dina villkor. ”Endast när en beställning på över 500 EUR får taggen
vip” är en enda kodrad, istället för ett arbetsflöde som körs för varje beställning och sedan filtrerar. - Utlös vid en övergång, inte vid ett tillstånd. Din kod ser värdet både före och efter förändringen, så det är möjligt att säga att ”statusen gick från utkast till aktiv” eller att ”lagernivån sjönk under 5”. Ett villkor baserat på det aktuella värdet kan inte uttrycka detta.
- Skicka exakt de fält du vill ha. Omforma händelsen till de värden som ditt arbetsflöde faktiskt använder, istället för att läsa ut dem ett efter ett.
En anpassad utlösare behöver inte ens en Shopify-händelse: den kan också köras enligt ett schema och själv avgöra vad som har ändrats.
Så här fungerar det
- Välj hur det ska köras: en enskild Shopify-händelse eller en tidsplan.
- För en händelse väljer du den händelse som appen lyssnar på - vilken som helst Shopify-händelse som appen redan tar emot - eller utgår från en mall, som väljer händelsen och fyller i koden.
- Hämta en verklig nyttolast. Gör den ändringen i din butik så hämtar appen exakt händelsens innehåll.
- Skriv en transformering - returnera ett objekt för att utlösa händelsen, returnera
nullför att hoppa över den. - Testa det mot den inspelade händelsen och se exakt vad ditt arbetsflöde skulle ta emot.
- Sätt på den.

Skriva omvandlingen
Din trigger är en JavaScript-modul som exporterar en funktion med namnet transform. Den tar emot fyra argument:
payload- den obearbetade händelsekroppen från Shopify, precis som den anländer.topic- vilken händelse som utlöstes, till exempelPRODUCTS_UPDATE.shop- din myshopify-domän.ctx-ctx.log(...)skriver ut till loggpanelen bredvid redigeraren,ctx.shopify(...)kör en Admin GraphQL-fråga ochctx.fetch(...)anropar en URL på det öppna internet.
Det du returnerar avgör vad som händer:
- Returnera ett objekt så utlöses händelsen, och objektet överförs.
- Returnera
null, så hoppas händelsen över. Så här fungerar filtreringen - det finns inget separat filterspråk att lära sig. - Lämna fältet tomt så utlöses den vid varje händelse av den typen.
/**
* 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,
};
}Värdet före ändringen
Shopify
Vid produktuppdatering, orderuppdatering och kunduppdatering listar payload._changes alla spårade fält som har ändrats i samband med uppdateringen, var och ett med oldValue och newValue:
- Produkter:
title,handle,description,status,vendor,productType,tags - Beställningar:
financialStatus,fulfillmentStatus,tags,note,lineItemsochcustomAttributes.<name> - Kunder:
tags,note,state(ENABLED,DISABLED,INVITED,DECLINED)
Listan är tom när uppdateringen inte gäller dessa fält - till exempel vid en lagerförändring - eller när appen visar posten för första gången. Det exempel på händelse som du registrerar i redigeraren visar fältet, så att du kan se hur det faktiskt ser ut innan du skriver in data i det.
/**
* 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,
};
}De mer specifika händelserna har sina egna gamla och nya värden, så du behöver inte _changes där: en prisförändring har oldPrice, newPrice och percentChange; en lagerförändring har _oldAvailable, _newAvailable och _delta; en metafältförändring har previousValue bredvid metafield.value.
Börja med en mall
När ”Fires on” är aktiverat i redigeraren väljer alternativet ”Start from a template” händelsen och fyller i fungerande kod. Redigera konstanterna högst upp, testa och spara sedan. Varje mall läser av ett värde före och efter ändringen:
- Ett fält för en produkt, en order eller en kund ändrades från ett värde till ett annat - statusen ändrades från utkast till aktiv, en order markerades som betald, ett konto aktiverades.
- Priset sjönk med mer än N procent - en verklig prisnedsättning, inte vilken prisjustering som helst.
- Lagernivån sjönk under en tröskel - utlöses en gång, i det ögonblick då lagernivån passerar gränsen, inte vid varje försäljning när den redan är låg.
- Värdet för ett produktmetafält har överskridit ett tröskelvärde - ett betyg har sjunkit under 3, en marginal har överskridit 40.
- Beställning som betalas av en högvärdig kund - hämtar kundens sammanlagda köpbelopp i din butik och aktiveras endast när beloppet överstiger det värde du har angett.

Hämta ytterligare data med ctx.shopify
Webhook-innehållet innehåller endast de fält som Shopify skickar. Om du behöver någon annan information - till exempel antalet beställningar för en kund, lagerstatus för en variant eller ett metafält - kan du skicka en förfrågan till Admin API direkt från din 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,
};
}Den returnerar frågans data och genererar ett undantag om frågan innehåller fel, så att ett misstag syns i ditt test istället för att inget alls returneras utan förvarning.
Tre gränsvärden som är bra att känna till:
- Upp till 10 anrop per körning. Berikning kräver en handfull; fler än så brukar innebära en loop. Hämta det du behöver i en enda fråga när det är möjligt.
- Den läser, men skriver inte. Den använder de behörigheter du har beviljat, och appen begär endast läsbehörighet. En förfrågan om orderdata misslyckas om inte ”Order Data Access” har beviljats på sidan ”Behörigheter”. Om du vill ändra något i din butik gör du det i de Shopify Flow-åtgärder som följer efter utlösaren.
- Dina butiks inloggningsuppgifter når aldrig din kod. Förfrågan körs av appen å dina vägnar, så det finns inget åtkomsttoken i sandlådan som kan läcka ut.
ctx.fetch(url, options) fungerar på samma sätt som webbläsarens fetch-funktion för allt på det offentliga internet: en leverantörs lageruppdateringar, en valutakurs, ditt eget API. Interna och privata nätverksadresser avvisas. Om din triggerkod sparas på GitHub ska du inte ange någon API-nyckel i den.
Utlösare som körs enligt ett schema
Shopify Flow-funktionen reagerar när något händer. Den kan inte reagera när inget händer, och den kan inte se något utanför din butik. Välj därför ”Enligt schema” under ”Vad utlöser detta”. Det finns ingen Shopify-händelse bakom en sådan utlösare: din kod körs med ett visst intervall, från var 30:e sekund upp till en gång om dagen, och avgör själv vad som räknas som en förändring.
Det är samma transform-funktion, men med en annan payload och ett annat returvärde:
payload.state- det värde som din kod returnerade somstatevid föregående körning.nullvid den första körningen.payload.nowochpayload.lastRunAt- tidsstämplar.- Returnera
{ state, events }: det nya tillståndet som ska sparas (upp till 32 KB) och en lista över händelser som ska utlösas (upp till 100 per körning). Varje händelse utlöser Custom Trigger en gång; en händelsesresourceId, om du har angett ett sådant, blir post-ID:t i Shopify Flow. Returneranullnär det inte finns något att rapportera.
Se till att den första körningen endast lagrar information - aldrig utlöser något. Vid den första körningen har din kod inget att jämföra med, så allt ser nytt ut. Lagra det du ser och returnera inga händelser, och att aktivera utlösaren kommer aldrig att överbelasta dina arbetsflöden. Alla mallar fungerar på detta sätt.

// 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 }],
}
}Mallar för schemalagda utlösare, under ”Starta från en mall” på kortet ”Schema”:
- Produkt, order eller kund som inte har uppdaterats på N dagar - inaktuella kataloggranskningar, fastnade order, återvinningskampanjer. Varje post utlöses en gång per inaktivitetsperiod, och de poster som redan var försenade när funktionen aktiverades utlöses inte alla på en gång.
- Ett värde utanför Shopify har ändrats - ett lagerflöde från en leverantör, en växelkurs, en prislista, med skillnaden och procenttalet för siffrorna.
- Nyhet i ett RSS- eller Atom-flöde - leverantörsnyheter, ett produktlista-flöde, en statussida.
- Inga beställningar på N timmar - en pulsmätare för din butik. Aktiveras en gång när beställningarna upphör och en gång när de återkommer.
Test kör din kod en gång utan att utlösa något och utan att spara tillståndet, så att du kan köra den så ofta du vill.
Använda det i Shopify Flow
Varje anpassad utlösare registreras i Shopify Flow som samma utlösare: Anpassad utlösare. Lägg till den i ett arbetsflöde och lägg sedan till ett villkor som lyder: ”Utlösarens namn är lika med namnet på din utlösare”.
Det namnet visas på utlösarens sida och ändras aldrig, inte ens om du byter namn på utlösaren - så att ditt arbetsflöde fortsätter att fungera.
Varje nyckel som din transformering returnerar blir ett fält i triggern, och hela objektet finns även tillgängligt i JSON-format om du hellre vill analysera det själv.
Lägg upp koden på GitHub
Du kan koppla ett GitHub-repository så att din triggerkod hamnar under versionshantering. Ändringar blir tillgängliga för granskning i en pull-begäran, du kan se vem som har ändrat vad och du kan återställa en omvandling som slutat fungera.
Anslut den på utvecklarsidan, under ”Anslutningar”. Du väljer vilka repositorier appen ska ha åtkomst till, och du kan när som helst återkalla den åtkomsten från GitHub.
När ett arkiv har valts ut skrivs alla befintliga utlösare omedelbart till det, och synkroniseringen sker i båda riktningarna:
| Vad du gör | Vad händer? |
|---|---|
| Skapa, redigera eller duplicera en utlösare i appen | Filen har lagts in i ditt arkiv |
| Ta bort en utlösare i appen | Filen tas bort från ditt arkiv |
| Skicka en ändring till den anslutna grenen | Triggerns kod uppdateras i appen |
Varje trigger är en fil som har fått sitt namn efter sitt handtag och som innehåller exakt den modul du ser i redigeraren - utan något extra runt omkring. Det innebär att du kan öppna den i din egen redigerare, köra den och köra lint på den precis som vilken annan JavaScript-fil som helst.
Återgå till en tidigare version
Du behöver inte kunna Git för att ångra en ändring. När ett arkiv är anslutet visar redigeraren en rullgardinsmeny under ”Version” där alla tidigare versioner av filen listas med datum och upphovsman. Välj en version så laddas den in i redigeraren som en osparad ändring, så att du kan läsa igenom den först - det är först när du sparar som den återställs.
Testa medan du redigerar lokalt
Om du redigerar filen i din egen redigerare kan du köra den mot den inspelade exempelhändelsen utan att först spara den i appen. Använd en API-nyckel med behörighetsnivån ”execute” från utvecklarsidan:
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}')"Du får tillbaka samma resultat som visas på appens Test-knapp: om funktionen skulle utlösas, utdataobjektet, dina ctx.log-rader och körtiden.
Denna slutpunkt utlöser ingenting och sparar ingenting, och den förbrukar inte någon kvot - så det är säkert att köra den vid varje sparning från en filövervakare. (Knappen ”Kör test” i appen utlöser ditt Shopify Flow-arbetsflöde, så att du kan följa hela processen från början till slut; det är också gratis.)
Du kan också hämta exempelpayloaden separat med en läsnyckel, spara den lokalt och köra filen helt offline:
curl https://shopify.workflow-trigger-extensions.app/api/v1/triggers/custom/high-value-vip-order/test \
-H "Authorization: Bearer ftk_your_key_here"Räknas en anpassad utlösare in i min abonnemangskvot?
Ja, och den räknar varje händelse som den övervakar - inte bara de som utlöser din trigger. Om din trigger lyssnar på ”Product Update” och din butik har 60 000 produktuppdateringar per månad, blir det 60 000 händelser, även om din kod endast utlöses vid 100 av dem.
Vi tar emot, avduplicerar och placerar varje händelse i kö, och kör sedan din kod i en isolerad sandlåda - allt detta innan din kod avgör om den ska utlösas. Antalet återspeglar detta arbete.
Med andra ord: det kostar lika mycket som den inbyggda utlösaren skulle ha gjort för samma händelse. Du debiteras inte extra för filtrering, och testning är alltid gratis. En schemalagd utlösare räknas en gång per körning.
Är testet gratis?
Ja. Både knappen ”Kör test” i appen och API-ändpunkten /test är undantagna, även om ”Kör test” faktiskt aktiverar ditt Shopify Flow-arbetsflöde så att du kan se hur det körs. Endast live-körningar räknar på din kvot, så du kan testa en omvandling så många gånger du vill.
Varför är payload._changes tomt?
Antingen låg uppdateringen utanför de fält som spåras - till exempel en lager- eller variantändring för en produkt - eller så har appen ännu ingen referenspunkt för den posten. Referenspunkten sparas första gången appen stöter på en post, så den allra första uppdateringen av en post som appen aldrig tidigare har sett innehåller inget tidigare värde. Alla uppdateringar därefter gör det.
Kan min kod ändra data i min butik?
Nej. ctx.shopify körs med de läsbehörigheter du har beviljat, och appen begär aldrig skrivbehörighet. Det är avsiktligt: en utlösare som redigerar den post den övervakar startar om sig själv, vilket är den slinga som Shopify-arbetsflöden stängs av på grund av. Ändra data i de Shopify Flow-åtgärder som följer efter utlösaren.
Kan jag byta ut handtaget senare?
Nej, och det är avsiktligt. Ditt Shopify Flow-arbetsflöde filtrerar efter namnet, så om du ändrar det skulle arbetsflödet sluta köras utan att du märker det. Du kan döpa om utlösaren hur du vill - namnet förblir oförändrat.
Handtaget är också filnamnet i ditt GitHub-arkiv, så det flyttas aldrig heller.
Vad händer om det finns ett fel i min kod?
Händelsen hoppas över och felet loggas i triggern, så att du kan se vad som gick fel. En misslyckad omvandling blockerar aldrig något annat - dina övriga triggare, vare sig de är anpassade eller inbyggda, fortsätter att fungera som vanligt.
Var körs min kod?
I en isolerad sandlåda, åtskild från resten av appen, med en kort tidsgräns och utan åtkomst till din butiks inloggningsuppgifter. Den ser endast den händelseinformation som du har fångat upp, samt det du hämtar med ctx.shopify eller ctx.fetch.
Vad händer om jag redigerar filen på GitHub och i appen samtidigt?
Den som du sparar sist vinner. När du sparar i appen bekräftas ändringarna i filen, och när du pushar till den anslutna grenen skrivs koden i appen över. Om du främst arbetar i ditt repository bör du betrakta appens redigerare som skrivskyddad för att undvika överraskningar.
Kan en fil i mitt arkiv skapa en ny utlösare?
Nej. En trigger måste också veta vilken Shopify-händelse den lyssnar på, och filen innehåller endast kod - om man gissar på händelsen skulle det leda till att den kopplas till fel sak. Skapa först triggern i appen och redigera sedan filen fritt.
Kan den utlösas av händelser som appen inte redan tar emot?
Nej. En anpassad utlösare övervakar de händelser som appen redan prenumererar på för din butik, vilket beror på vilka behörigheter du har beviljat. Om du beviljar behörighet för en resurs blir dess händelser tillgängliga även för anpassade utlösare. För allt annat bör du köra det enligt ett schema.
Nästa steg
- Utvecklings-API, MCP, GitHub och simulering av utlösare - hantera och testa utlösare från din egen kod eller en AI-assistent.
- Skapa triggerkod med AI - beskriv utlösaren på vanlig engelska och låt AI skriva koden.
- Planer och användning - vad som räknas som en händelse och hur kvoten fungerar.
- Hur utlösare fungerar - de inbyggda triggarna och hur de aktiveras.
