Preis und Vergleichspreis automatisch aktualisieren, wenn sich die Lieferantenkosten ändern
September 3, 2026
Ihr Lieferant erhöht den Preis einer Variante von 4,00 auf 5,20. In Shopify passiert daraufhin nichts. Der Verkaufspreis bleibt unverändert, und die von Ihnen geplante Marge schwindet still und leise dahin, bis jemand dies Wochen später bei einer Bestandsaufnahme bemerkt.
Shopify Flow Das allein reicht hier nicht aus, da „Shopify“ keinen integrierten Trigger für eine Änderung der Kosten pro Artikel bietet. Es gibt auch keine Aktion, die den Preis auf dieser Grundlage neu berechnet.
Dieser Leitfaden schließt beide Lücken. Sobald sich der Stückpreis einer Variante ändert, wird ein Flow gestartet, und eine kurze Funktion schreibt den neuen Preis und den Vergleichspreis zurück in Shopify. Die Einrichtung dauert etwa zehn Minuten, danach läuft der Flow bei jeder Preisänderung – und zwar dauerhaft.
Was Sie entwickeln werden
- Workflow Trigger Extensions erkennt die Kostenänderung und startet einen Flow, der die Variante, ihre Artikelnummer sowie den alten und den neuen Preis enthält.
- Shopify Flow übergibt diese Werte als JSON an eine Funktion.
- Workflow Functions führt einige Zeilen JavaScript aus, die die neuen Preise berechnen und diese über die Admin-API zurückschreiben.
Die Preisregel ist an einer einzigen Stelle im Code hinterlegt, den Sie selbst kontrollieren. Wenn Sie sie später ändern möchten, müssen Sie daher lediglich eine Zeile bearbeiten, anstatt einen gesamten Workflow neu erstellen zu müssen.
Schritt 1: Aktivieren Sie den Kostenauslöser
Öffnen Sie in „Workflow Trigger Extensions“ die Seite „Trigger“, suchen Sie die Gruppe „Bestand“ und aktivieren Sie „Kostenänderung bei Produktvariante“.
Dieser Trigger benötigt Zugriff auf Bestandsdaten, da die Kosten pro Artikel dem Bestandsartikel und nicht der Variante selbst zugeordnet sind. Falls die Berechtigung noch nicht erteilt wurde, wird beim Aktivieren des Triggers in einem einzigen Dialogfeld eine entsprechende Abfrage angezeigt. Solange die Berechtigung nicht erteilt wurde, bleibt der Trigger zwar aktiviert, zeigt jedoch die Meldung „Berechtigung erforderlich“ an und wird nicht ausgelöst.
Was Ihnen der Auslöser bietet
Sobald es ausgelöst wird, hat Ihr Flow Zugriff auf:
| Feld | Beispiel |
|---|---|
variantCostChange.variantId |
gid://shopify/ProductVariant/54589751394579 |
variantCostChange.variantTitle |
Medium / Black |
variantCostChange.sku |
TSHIRT-M-BLK |
variantCostChange.oldCost.amount |
4.00 |
variantCostChange.newCost.amount |
5.20 |
variantCostChange.newCost.currencyCode |
EUR |
Das Produkt selbst ist ebenfalls als Produktreferenz enthalten, sodass Sie Flow-Bedingungen hinsichtlich Anbieter, Typ, Tags oder Kollektion hinzufügen können, bevor der Preis überhaupt berücksichtigt wird.
Schritt 2: Erstellen Sie die Funktion
Erstellen Sie in „Workflow Functions“ eine neue Funktion und fügen Sie den folgenden Code ein.
Aktivieren Sie vor dem Speichern die Option** „Shopify-Daten erforderlich**“. Dadurch wird ctx.shopify.graphql(...) für Ihren Code freigeschaltet, sodass dieser die Shop-Daten lesen und ändern kann. Öffnen Sie anschließend die Seite „Berechtigungen“ unter Workflow Functions und erteilen Sie die Berechtigung zum Schreiben von Produkten – dies ist der Geltungsbereich, den diese Funktion benötigt, um einen Preis zu ändern.
Ohne diese Umschaltfunktion ist das Objekt ctx.shopify nicht verfügbar, und die Funktion schlägt beim ersten Admin-API-Aufruf fehl.
export default async function (input, ctx) {
const toGid = (value, type) => {
if (value === undefined || value === null) return null;
const str = String(value).trim();
if (!str) return null;
if (str.startsWith('gid://')) return str;
if (/^\d+$/.test(str)) return `gid://shopify/${type}/${str}`;
return str;
};
try {
const variantId = toGid(input.variantId || input.variant_id || input.id, 'ProductVariant');
if (!variantId) throw new Error('Missing "variantId" in input.');
const hasPrice = input.price !== undefined && input.price !== null && String(input.price).trim() !== '';
const hasCompareAt = Object.prototype.hasOwnProperty.call(input, 'compareAtPrice') || Object.prototype.hasOwnProperty.call(input, 'compare_at_price');
const rawCompareAt = input.compareAtPrice !== undefined ? input.compareAtPrice : input.compare_at_price;
if (!hasPrice && !hasCompareAt) throw new Error('Nothing to update: provide "price" and/or "compareAtPrice".');
const asMoney = (value) => {
const num = Number(value);
if (!Number.isFinite(num) || num < 0) throw new Error(`Invalid money value: ${JSON.stringify(value)}`);
return num.toFixed(2);
};
let productId = toGid(input.productId || input.product_id, 'Product');
if (!productId) {
const readQuery = `
query VariantForPriceUpdate($id: ID!) {
productVariant(id: $id) { id product { id } }
}`;
const readRes = await ctx.shopify.graphql(readQuery, { id: variantId });
if (readRes.errors) throw new Error('Failed to read variant: ' + JSON.stringify(readRes.errors));
const variant = readRes.data && readRes.data.productVariant;
if (!variant) throw new Error(`Variant not found: ${variantId}`);
productId = variant.product && variant.product.id;
if (!productId) throw new Error('Could not resolve the parent product id for the variant.');
}
const variantInput = { id: variantId };
if (hasPrice) variantInput.price = asMoney(input.price);
if (hasCompareAt) {
variantInput.compareAtPrice = rawCompareAt === null || String(rawCompareAt).trim() === '' ? null : asMoney(rawCompareAt);
}
ctx.log('Updating variant', variantId, 'on product', productId, variantInput);
const mutation = `
mutation UpdateVariantPrice($productId: ID!, $variants: [ProductVariantsBulkInput!]!) {
productVariantsBulkUpdate(productId: $productId, variants: $variants) {
productVariants { id }
userErrors { field message }
}
}`;
const res = await ctx.shopify.graphql(mutation, { productId, variants: [variantInput] });
if (res.errors) throw new Error('GraphQL error updating variant: ' + JSON.stringify(res.errors));
const payload = res.data && res.data.productVariantsBulkUpdate;
if (!payload) throw new Error('Unexpected empty response from productVariantsBulkUpdate.');
if (payload.userErrors && payload.userErrors.length) {
throw new Error('Variant update failed: ' + payload.userErrors.map(e => `${(e.field || []).join('.')}: ${e.message}`).join('; '));
}
return { success: true };
} catch (err) {
ctx.log('Error updating variant price:', err.message);
return { success: false };
}
}Ein paar Dinge, die man beim Code beachten sollte:
- Es akzeptiert eine reine numerische ID oder eine vollständige GID.
toGidnormalisiert beide Formate, sodass Sie sich keine Gedanken darüber machen müssen, welche Form Flow Ihnen übergibt. - Das übergeordnete Produkt wird nur dann abgerufen, wenn es unbedingt erforderlich ist. Die Funktion
productVariantsBulkUpdatebenötigt eine Produkt-ID; wenn Sie keine übergeben, ruft die Funktion diese ab. Durch die Übergabe vonproductIdin der Eingabe wird dieser Hin- und Rückweg übersprungen. - Es werden nicht nur Transportfehler, sondern auch
userErrorsüberprüft. Ein GraphQL-Aufruf kann den HTTP-Status 200 zurückgeben und den Schreibvorgang dennoch ablehnen. Dies ist der häufigste Grund dafür, dass eine Preisaktualisierung scheinbar erfolgreich verläuft, sich aber nichts ändert. - Das Löschen von „compare-at“ ist beabsichtigt. Durch die Übergabe von
compareAtPrice: nulloder einer leeren Zeichenkette wird es entfernt und nicht als Fehler gewertet.
Schritt 3: Testen Sie die Funktion, bevor Sie sie anschließen
Verwenden Sie die Registerkarte „Test“ mit einer echten Varianten-ID aus Ihrem Shop. Entnehmen Sie diese einer beliebigen Produkt-URL im Admin-Bereich oder dem Ereignisverlauf des Triggers.
Legen Sie einen Preis fest, den Sie wiedererkennen, damit Sie bestätigen können, dass die Nachricht angekommen ist.
{
"variantId": "gid://shopify/ProductVariant/54589751394579",
"price": "24.99",
"compareAtPrice": "39.99"
}Schritt 4: Den Durchfluss verkabeln
Erstellen Sie einen Workflow in Shopify Flow:
- Auslöser: Kosten der Produktvariante geändert
- Aktion: „Funktion aus Workflow Functions ausführen“ und die soeben erstellte Funktion auswählen
Fügen Sie dies in das JSON-Eingabefeld ein. Der Flow ersetzt das Liquid bei jeder Ausführung durch tatsächliche Werte.
{
"variantId": "{{variantCostChange.variantId}}",
"price": "{{variantCostChange.newCost.amount | times: 5}}",
"compareAtPrice": "{{variantCostChange.newCost.amount | times: 7}}"
}Das ist die gesamte Preisregel: Das Fünffache der Kosten als Verkaufspreis, das Siebenfache der Kosten als Vergleichspreis, damit das Produkt stets einen einheitlichen Rabatt anzeigt.
Diese Multiplikatoren dienen nur als Beispiel und stellen keine Empfehlung dar. Ändern Sie times: 5 entsprechend den tatsächlichen Möglichkeiten Ihrer Kategorie. Liquid übernimmt die Berechnung, sodass ein fester Aufschlag anstelle eines Multiplikators wie folgt lautet: plus: 12, und eine prozentuale Marge wie folgt: times: 1.6.
Wenn Sie in mehreren Währungen verkaufen, beachten Sie bitte, dass newCost.amount in der Währung des Shops angegeben ist. Markets übernimmt die Umrechnung zum Zeitpunkt der Anzeige, sodass Sie dies nicht tun müssen.
Überprüfen Sie, ob es durchgehend funktioniert
- Öffnen Sie eine beliebige Produktvariante im Shopify-Adminbereich und ändern Sie den Stückpreis.
- Speichern
- Innerhalb weniger Sekunden werden der Preis und der Vergleichspreis automatisch aktualisiert.
Falls nichts passiert, gehen Sie in dieser Reihenfolge vor, da jeder Schritt den vorherigen ausschließt:
| Überprüfen | Wo |
|---|---|
| Ist der Abzug ausgelöst worden? | Ereignisverlauf in Workflow Trigger Extensions |
| Ist der Flow gelaufen? | Shopify Flow Aktivitätsprotokoll |
| Wurde die Funktion ausgeführt, und was wurde protokolliert? | Ausführungsverlauf in Workflow Functions |
Die häufigste Ursache für einen Lauf, der als fehlgeschlagen gemeldet wird, ist ein fehlender Scope. ctx.shopify ist nur verfügbar, wenn die Option „Shopify-Daten erforderlich“ aktiviert ist, und der Schreibvorgang gelingt erst, wenn die Berechtigung zum Schreiben von Produkten erteilt wurde.
Wohin geht es als Nächstes?
Das gleiche Muster lässt sich auf alles anwenden, was von einer Kostenänderung betroffen ist. Tauschen Sie einfach den Funktionskörper aus, und schon können Sie ein Produkt zur Überprüfung markieren, wenn die Kosten um mehr als 10 Prozent steigen, die alte und die neue Marge in Slack veröffentlichen oder die Änderung zur Berichterstellung in ein Metafeld schreiben.
Der Trigger ist der Teil, den Shopify nicht bereitstellt. Was danach folgt, ist ganz normaler Code.
Workflow Functions Dokumentation
- Berechtigungen und Zugriff auf Speicherdaten – Aktivieren der Funktion Shopify, die Daten von benötigt, und Gewähren von Zugriffsbereichen
- Variablen an Ihre Funktion übergeben – so funktionieren die JSON-Eingabe und Liquid
- Richten Sie die Aktion „Funktion ausführen“ unter Shopify Flowein:
- Ausführungsverlauf und Fehlerbehebung

