
Shopify Automatisierung: 10 Prozesse, die kein Plugin automatisieren kann
Sie haben Shopify Flow eingerichtet, drei Automatisierungs-Apps installiert und Zapier mit zehn Zaps verbunden. Trotzdem sitzen Ihre Mitarbeiter jeden Morgen zwei Stunden an manuellen Aufgaben, die "eigentlich automatisch laufen sollten". Kommt Ihnen das bekannt vor?
Das Problem ist nicht, dass Sie die falschen Plugins gewählt haben. Das Problem ist, dass Standard-Plugins für Standard-Probleme gebaut werden — und Ihr Business längst über den Standard hinausgewachsen ist.
In diesem Artikel zeige ich Ihnen 10 konkrete Prozesse, bei denen Plugins an ihre Grenzen stoßen, und wie Custom-Automatisierung diese Lücken schließt. Mit echten Code-Beispielen, realistischen Kostenvergleichen und klaren Entscheidungshilfen.
Warum Standard-Plugins nicht ausreichen
Bevor wir in die 10 Prozesse einsteigen: Verstehen Sie, warum Plugins strukturell limitiert sind.
Die drei fundamentalen Plugin-Limitierungen
| Limitierung | Erklärung | Konsequenz |
|---|---|---|
| One-size-fits-all | Plugins müssen für tausende Shops funktionieren | Ihre spezifische Logik passt nicht rein |
| API-Rate-Limits | Jede App teilt sich ein Kontingent | Bei vielen Apps: Konflikte und Fehler |
| Keine System-übergreifende Logik | Plugins kennen nur Shopify | ERP, PIM, WMS bleiben außen vor |
Die versteckten Kosten von Plugin-Stacking
Ein typisches Szenario, das ich bei Shopify-Händlern sehe:
Bestandsmanagement-App: $49/Monat
Pricing-App: $79/Monat
Fulfillment-App: $39/Monat
Returns-App: $59/Monat
B2B-App: $99/Monat
Sync-App: $29/Monat
Automatisierungs-App: $49/Monat
─────────────────────────────────────
Gesamt: $403/Monat = $4.836/Jahr
Das sind fast 5.000 $ pro Jahr — und trotzdem bleiben Lücken. Jede App hat ihr eigenes Dashboard, ihre eigene Logik, ihre eigenen Bugs. Und wenn zwei Apps denselben Webhook abfangen, beginnt das Chaos.
Die Faustregel: Wenn Sie mehr als 4 Apps für zusammenhängende Workflows einsetzen, ist eine Custom-Lösung oft günstiger und zuverlässiger.
Prozess 1: Multi-Warehouse Bestandsabgleich mit unterschiedlichen ERP-Systemen
Das Problem
Sie betreiben drei Lager: eines in Deutschland (angebunden an SAP), eines in Polen (mit eigenem WMS) und ein Dropshipping-Lager beim Lieferanten (CSV-Export per E-Mail). Jedes System spricht eine andere Sprache, hat andere Update-Zyklen und andere Datenformate.
Warum Plugins hier scheitern
Standard-Inventory-Apps wie Stocky oder Katana unterstützen eine Datenquelle. Multi-ERP-Setups mit verschiedenen Protokollen (REST, SOAP, SFTP, E-Mail-Anhänge) sind schlicht nicht vorgesehen. Außerdem kennen diese Apps keine Priorisierungslogik — also welches Lager bei einem Bestelleingang zuerst bedient werden soll.
Die Custom-Lösung
Ein zentraler Sync-Service, der als Middleware zwischen allen Systemen vermittelt:
// Zentraler Bestandsabgleich-Service
async function syncInventoryFromAllSources() {
// 1. SAP-Bestand abrufen (REST API)
const sapStock = await fetchSAPInventory({
endpoint: process.env.SAP_API_URL,
credentials: process.env.SAP_CREDENTIALS,
warehouse: 'DE-MAIN'
});
// 2. WMS Polen (SOAP)
const wmsStock = await fetchWMSInventory({
wsdl: process.env.WMS_WSDL_URL,
warehouse: 'PL-FULFILLMENT'
});
// 3. Dropshipper (CSV per SFTP)
const dropshipStock = await fetchDropshipCSV({
host: process.env.SFTP_HOST,
path: '/exports/stock_daily.csv',
mapping: { sku: 'Artikelnummer', qty: 'Verfuegbar' }
});
// 4. Bestände zusammenführen mit Priorisierung
const mergedInventory = mergeInventory([
{ source: sapStock, priority: 1, locationId: 'gid://shopify/Location/1001' },
{ source: wmsStock, priority: 2, locationId: 'gid://shopify/Location/1002' },
{ source: dropshipStock, priority: 3, locationId: 'gid://shopify/Location/1003' }
]);
// 5. Shopify Inventory Levels aktualisieren
for (const item of mergedInventory) {
await shopify.rest.InventoryLevel.set({
session,
inventory_item_id: item.inventoryItemId,
location_id: item.locationId,
available: item.available
});
}
}
Business Impact
- Vorher: 3 Stunden tägliche manuelle Bestandspflege, regelmäßige Überverkäufe
- Nachher: Echtzeit-Sync alle 15 Minuten, Überverkäufe um 94% reduziert
- ROI: Amortisierung der Entwicklungskosten innerhalb von 8 Wochen
Prozess 2: Automatische Preisanpassung basierend auf Wettbewerber-Daten
Das Problem
Sie verkaufen 2.000 Produkte und möchten bei den Top-100-Artikeln immer 2–5% unter dem günstigsten Wettbewerber liegen — aber nur, wenn Ihre Marge dabei über 15% bleibt. Außerdem sollen bestimmte Marken von der Anpassung ausgenommen werden.
Warum Plugins hier scheitern
Repricing-Apps wie Prisync oder Competera arbeiten mit festen Regeln. Mehrstufige Bedingungslogik (Marge + Wettbewerberpreis + Markenausnahmen + Tageszeit + Lagerbestand) übersteigt deren Regelwerk. Und eine direkte Anbindung an Ihre spezifische Margen-Kalkulation aus dem ERP? Fehlanzeige.
Die Custom-Lösung
// Preisanpassungslogik mit mehrstufigen Bedingungen
async function adjustPrices() {
const products = await getCompetitiveProducts(); // Top-100 Artikel
const competitorPrices = await scrapeCompetitorPrices(); // Datenquelle
const marginData = await getMarginDataFromERP(); // Einkaufspreise
for (const product of products) {
const competitor = competitorPrices[product.sku];
const margin = marginData[product.sku];
if (!competitor || !margin) continue;
// Ausnahme: Premium-Marken nicht anpassen
if (product.vendor === 'PremiumBrand') continue;
// Zielpreis: 3% unter günstigstem Wettbewerber
const targetPrice = competitor.lowestPrice * 0.97;
// Marge prüfen: Mindestens 15%
const effectiveMargin = (targetPrice - margin.purchasePrice) / targetPrice;
if (effectiveMargin < 0.15) {
// Mindestmarge einhalten → Preis auf Mindestmarge setzen
const minPrice = margin.purchasePrice / 0.85;
await updateShopifyPrice(product.id, roundToNine(minPrice));
} else {
await updateShopifyPrice(product.id, roundToNine(targetPrice));
}
}
}
// Shopify Admin API: Preis aktualisieren
async function updateShopifyPrice(productId, newPrice) {
const mutation = `
mutation productVariantUpdate($input: ProductVariantInput!) {
productVariantUpdate(input: $input) {
productVariant {
id
price
}
userErrors { field, message }
}
}
`;
await shopifyGraphQL(mutation, {
input: { id: productId, price: String(newPrice) }
});
}
function roundToNine(price) {
return (Math.floor(price) + 0.99).toFixed(2);
}
Business Impact
- Vorher: Wöchentliche manuelle Preisprüfung für 100 Artikel (4h/Woche)
- Nachher: Tägliche automatische Anpassung, 12% höhere Conversion bei preissensiblen Artikeln
- ROI: +3,2% Gesamtumsatz bei gleichbleibender Marge
Prozess 3: Custom Fulfillment-Routing nach Produkttyp, Standort und Gewicht
Das Problem
Ihre Bestellung enthält drei Zeilen: ein Sperrgut-Produkt (Speditionsversand), zwei Normalpakete (DHL) und ein digitales Produkt (sofortiger Download). Die Bestellung muss automatisch in drei Fulfillment-Aufträge aufgeteilt, an verschiedene Carrier übergeben und dem Kunden als eine einheitliche Sendungsverfolgung präsentiert werden.
Warum Plugins hier scheitern
Shipping-Apps wie ShipStation oder Sendcloud können Multi-Carrier-Versand. Aber die automatische Aufteilung einer Bestellung nach Produkteigenschaften (Typ, Gewicht, Gefahrgut-Status, Lager-Zuweisung) in verschiedene Fulfillments — inklusive Speditionslogik — liegt außerhalb ihres Funktionsumfangs.
Die Custom-Lösung
// Fulfillment-Routing bei neuer Bestellung
async function routeOrderFulfillment(order) {
const lineItems = order.line_items;
// Routing-Regeln definieren
const routes = {
SPERRGUT: { carrier: 'spedition_api', locationId: 'LOC_WAREHOUSE_DE' },
STANDARD: { carrier: 'dhl_api', locationId: 'LOC_WAREHOUSE_DE' },
DIGITAL: { carrier: null, locationId: null }, // Sofort-Fulfillment
DROPSHIP: { carrier: 'supplier_api', locationId: 'LOC_SUPPLIER' }
};
// Line-Items klassifizieren
const grouped = {};
for (const item of lineItems) {
const category = classifyProduct(item);
if (!grouped[category]) grouped[category] = [];
grouped[category].push(item);
}
// Fulfillment-Orders erstellen
for (const [category, items] of Object.entries(grouped)) {
const route = routes[category];
if (category === 'DIGITAL') {
// Digitale Produkte: Sofort als erfüllt markieren + Download-Link senden
await fulfillDigitalItems(order.id, items);
continue;
}
// Fulfillment-Request an entsprechenden Carrier
const fulfillment = await createFulfillmentOrder({
orderId: order.id,
lineItems: items.map(i => ({
id: i.id,
quantity: i.quantity
})),
locationId: route.locationId
});
// Carrier-spezifische Übergabe
await route.carrier && submitToCarrier(route.carrier, fulfillment);
}
}
function classifyProduct(lineItem) {
if (lineItem.requires_shipping === false) return 'DIGITAL';
if (lineItem.grams > 31500) return 'SPERRGUT'; // > 31,5 kg
if (lineItem.vendor === 'DropshipSupplier') return 'DROPSHIP';
return 'STANDARD';
}
Business Impact
- Vorher: Manuelle Fulfillment-Aufteilung, durchschnittlich 8 Minuten pro Mixed-Bestellung
- Nachher: Vollautomatische Aufteilung in < 2 Sekunden
- ROI: Bei 50 Mixed-Bestellungen/Tag = 6,6 Stunden Zeitersparnis täglich
Prozess 4: Automatische Metafield-Generierung aus externen Datenquellen
Das Problem
Ihre Produktdaten leben in einem PIM-System (z.B. Akeneo, Pimcore). Dort sind detaillierte technische Spezifikationen hinterlegt: Materialzusammensetzungen, Pflegehinweise, Zertifizierungen, CE-Kennzeichnungen. Diese Daten müssen als Metafields in Shopify landen — strukturiert, validiert und in der richtigen Sprache.
Warum Plugins hier scheitern
PIM-Integrationen wie Akeneo Connector for Shopify synchronisieren Basisdaten. Aber komplexe Mapping-Logik (ein PIM-Feld → mehrere Shopify-Metafields mit Transformation), bedingte Generierung (Metafield X nur wenn Produkttyp = Y) und Validierung gegen externe Schemas gehen weit über Plugin-Fähigkeiten hinaus.
Die Custom-Lösung
// PIM-zu-Shopify Metafield-Sync mit Transformation
async function syncMetafieldsFromPIM() {
const pimProducts = await fetchPIMProducts();
for (const pimProduct of pimProducts) {
const shopifyProductId = await findShopifyProduct(pimProduct.sku);
if (!shopifyProductId) continue;
// Metafield-Definitionen basierend auf Produkttyp
const metafields = generateMetafields(pimProduct);
// Batch-Update über GraphQL
const mutation = `
mutation metafieldsSet($metafields: [MetafieldsSetInput!]!) {
metafieldsSet(metafields: $metafields) {
metafields { key, namespace, value }
userErrors { field, message }
}
}
`;
await shopifyGraphQL(mutation, { metafields });
}
}
function generateMetafields(pimProduct) {
const metafields = [];
// Basis-Metafields für alle Produkte
metafields.push({
ownerId: pimProduct.shopifyGid,
namespace: 'specs',
key: 'material',
type: 'single_line_text_field',
value: pimProduct.attributes.material?.de || ''
});
// Bedingte Metafields: Nur für Textilien
if (pimProduct.category === 'textiles') {
metafields.push({
ownerId: pimProduct.shopifyGid,
namespace: 'specs',
key: 'care_instructions',
type: 'json',
value: JSON.stringify(
transformCareSymbols(pimProduct.attributes.care)
)
});
metafields.push({
ownerId: pimProduct.shopifyGid,
namespace: 'compliance',
key: 'textile_composition',
type: 'single_line_text_field',
value: formatTextileComposition(pimProduct.attributes.composition)
});
}
// Zertifizierungen als Rich-Text
if (pimProduct.certifications?.length > 0) {
metafields.push({
ownerId: pimProduct.shopifyGid,
namespace: 'compliance',
key: 'certifications',
type: 'list.single_line_text_field',
value: JSON.stringify(pimProduct.certifications.map(c => c.name))
});
}
return metafields;
}
Tipp: Wenn Sie allgemein mehr über Custom Shopify Apps erfahren möchten — inklusive OAuth, Webhooks und Hosting — lesen Sie meinen ausführlichen Guide: Shopify App entwickeln: Eine ehrliche Anleitung.
Business Impact
- Vorher: Manuelle Metafield-Pflege in Shopify, 2 Mitarbeiter × 3 Stunden/Woche
- Nachher: Automatischer Sync alle 4 Stunden, Fehlerrate von 12% auf 0,3% gesenkt
- ROI: 312 Arbeitsstunden/Jahr eingespart
Prozess 5: Cross-Store Synchronisation (Multi-Brand Betrieb)
Das Problem
Sie betreiben drei Shopify-Stores für verschiedene Marken. Einige Produkte existieren in allen Stores (mit unterschiedlichen Preisen und Beschreibungen), der Gesamtbestand wird aber zentral verwaltet. Bestellungen aus allen Stores sollen in einem einheitlichen Dashboard erscheinen und gemeinsam fulfilled werden.
Warum Plugins hier scheitern
Multi-Store-Plugins wie Syncio können Produkte zwischen Stores synchronisieren. Aber selektive Synchronisation (nur bestimmte Felder, unterschiedliche Preise pro Store), konsolidierte Bestandslogik (Store A hat Priorität über Store B bei knappem Bestand) und einheitliches Order-Management übersteigen den Plugin-Umfang.
Die Custom-Lösung
// Cross-Store Inventar-Sync mit Priorisierung
async function crossStoreInventorySync() {
const stores = [
{ name: 'Brand A', client: shopifyClientA, priority: 1, reserveStock: 5 },
{ name: 'Brand B', client: shopifyClientB, priority: 2, reserveStock: 3 },
{ name: 'Brand C', client: shopifyClientC, priority: 3, reserveStock: 0 }
];
// Zentralen Bestand aus ERP holen
const centralStock = await getCentralInventory();
for (const sku of Object.keys(centralStock)) {
const totalAvailable = centralStock[sku].quantity;
let remaining = totalAvailable;
// Bestand nach Priorität verteilen
for (const store of stores) {
const productMapping = await getProductMapping(store.name, sku);
if (!productMapping) continue;
// Reservebestand für höher priorisierte Stores
const allocated = Math.max(0, remaining - store.reserveStock);
remaining -= allocated;
await store.client.rest.InventoryLevel.set({
session: store.session,
inventory_item_id: productMapping.inventoryItemId,
location_id: productMapping.locationId,
available: allocated
});
}
}
}
// Konsolidiertes Order-Dashboard
async function getConsolidatedOrders(dateFrom, dateTo) {
const allOrders = [];
for (const store of stores) {
const orders = await store.client.rest.Order.all({
session: store.session,
created_at_min: dateFrom,
created_at_max: dateTo,
status: 'any'
});
allOrders.push(
...orders.data.map(order => ({
...order,
storeName: store.name,
storeId: store.id
}))
);
}
return allOrders.sort((a, b) =>
new Date(b.created_at) - new Date(a.created_at)
);
}
Business Impact
- Vorher: 3 separate Dashboards, manuelle Bestandsverteilung, häufige Überverkäufe
- Nachher: Ein zentrales System, automatische Allokation, Überverkäufe eliminiert
- ROI: 40% weniger Operations-Aufwand, 15% weniger entgangener Umsatz durch Stockouts
Prozess 6: Automatisierte B2B-Preislogik mit kundenspezifischen Rabatten
Das Problem
Sie haben 200 B2B-Kunden mit individuellen Rabattstrukturen: Kunde A bekommt 25% auf Kategorie X, aber nur 10% auf Kategorie Y. Kunde B hat Festpreise für seine Top-50-Artikel. Kunde C bekommt gestaffelte Mengenrabatte ab 100 Stück. Und das Ganze muss mit Shopify B2B und den Katalog-Funktionen zusammenarbeiten.
Warum Plugins hier scheitern
Shopify B2B bietet seit 2024 integrierte Preis-Kataloge. Aber die Logik ist statisch: Sie legen Prozentsätze pro Katalog fest. Dynamische Staffelpreise, kombinierte Rabattregeln (Menge + Kundenstatus + Saison) und automatische Preisübertragung aus bestehenden ERP-Verträgen gehen darüber hinaus.
Die Custom-Lösung
// Dynamische B2B-Preisberechnung
async function calculateB2BPrice(companyId, variantId, quantity) {
// Kundenvertrag laden
const contract = await getB2BContract(companyId);
const variant = await getVariant(variantId);
const basePrice = parseFloat(variant.price);
let finalPrice = basePrice;
let appliedRules = [];
// Regel 1: Kategoriebasierter Rabatt
if (contract.categoryDiscounts?.[variant.product_type]) {
const discount = contract.categoryDiscounts[variant.product_type];
finalPrice *= (1 - discount / 100);
appliedRules.push(`Kategorie-Rabatt: ${discount}%`);
}
// Regel 2: Festpreise (überschreibt Kategorierabatt)
if (contract.fixedPrices?.[variant.sku]) {
finalPrice = contract.fixedPrices[variant.sku];
appliedRules = [`Festpreis: ${finalPrice}€`];
}
// Regel 3: Mengenstaffel (kumulativ)
if (contract.volumeTiers) {
const tier = contract.volumeTiers
.sort((a, b) => b.minQty - a.minQty)
.find(t => quantity >= t.minQty);
if (tier) {
finalPrice *= (1 - tier.discount / 100);
appliedRules.push(`Mengenstaffel ab ${tier.minQty}: ${tier.discount}%`);
}
}
// Regel 4: Saisonaler Bonus
const now = new Date();
const seasonalBonus = contract.seasonalBonuses?.find(
b => now >= new Date(b.start) && now <= new Date(b.end)
);
if (seasonalBonus) {
finalPrice *= (1 - seasonalBonus.extraDiscount / 100);
appliedRules.push(`Saison-Bonus: ${seasonalBonus.extraDiscount}%`);
}
return {
originalPrice: basePrice,
finalPrice: Math.round(finalPrice * 100) / 100,
appliedRules,
savings: ((1 - finalPrice / basePrice) * 100).toFixed(1) + '%'
};
}
Business Impact
- Vorher: Excel-basierte Preispflege, fehleranfällig, 1 Tag/Woche Verwaltungsaufwand
- Nachher: Echtzeit-Preisberechnung, Self-Service-Portal für B2B-Kunden
- ROI: 60% weniger Pricing-Fehler, 3× schnellere Angebotserstellung
Prozess 7: Custom Webhook-Chains für komplexe Order-Workflows
Das Problem
Wenn eine Bestellung eingeht, soll eine Kette von Aktionen ausgelöst werden — aber nicht linear, sondern bedingt und parallel:
- Bestellung geht ein → Betrugsprüfung
- Betrugsprüfung bestanden? → Parallel: Rechnung erzeugen + Fulfillment starten + CRM aktualisieren
- Betrugsprüfung fehlgeschlagen? → Bestellung halten + Support benachrichtigen
- Fulfillment gestartet? → Wenn B2B-Kunde: Lieferschein mit Custom-Template erzeugen
- Bestellung versendet → Tracking-Seite mit Upsells personalisieren
Warum Plugins hier scheitern
Shopify Flow kann einfache Wenn-Dann-Ketten. Aber parallele Ausführung, Fehlerbehandlung mit Retry-Logik, bedingte Verzweigungen über externe Systeme hinweg und transaktionale Sicherheit (wenn Schritt 3 fehlschlägt, Schritt 2 rückgängig machen) sind in Flow nicht abbildbar.
Die Custom-Lösung
// Webhook-Chain-Orchestrator
class OrderWorkflowOrchestrator {
async handleNewOrder(order) {
const context = { order, steps: [], errors: [] };
try {
// Schritt 1: Betrugsprüfung
const fraudCheck = await this.checkFraud(order);
context.steps.push({ name: 'fraud_check', result: fraudCheck });
if (fraudCheck.risk === 'high') {
// Verdächtig: Bestellung halten
await Promise.all([
this.holdOrder(order.id),
this.notifySupport(order, fraudCheck),
this.logEvent('order_held', context)
]);
return;
}
// Schritt 2: Parallele Verarbeitung (nicht blockierend)
const [invoice, fulfillment, crmUpdate] = await Promise.allSettled([
this.generateInvoice(order),
this.initiateFulfillment(order),
this.updateCRM(order)
]);
// Fehler einzelner Schritte verarbeiten (nicht gesamte Chain abbrechen)
for (const result of [
{ name: 'invoice', result: invoice },
{ name: 'fulfillment', result: fulfillment },
{ name: 'crm', result: crmUpdate }
]) {
if (result.result.status === 'rejected') {
context.errors.push(result.name);
await this.scheduleRetry(result.name, order.id);
}
}
// Schritt 3: B2B-spezifische Logik
if (order.customer?.tags?.includes('b2b')) {
await this.generateCustomDeliveryNote(order, {
template: 'b2b-lieferschein',
includePurchaseOrderNumber: true
});
}
await this.logEvent('order_processed', context);
} catch (error) {
await this.handleCriticalError(error, context);
}
}
async scheduleRetry(stepName, orderId, attempt = 1) {
const delay = Math.min(1000 * Math.pow(2, attempt), 60000); // Exponential Backoff
setTimeout(async () => {
try {
await this[`retry_${stepName}`](orderId);
} catch (e) {
if (attempt < 5) {
await this.scheduleRetry(stepName, orderId, attempt + 1);
} else {
await this.escalateToSupport(stepName, orderId);
}
}
}, delay);
}
}
Business Impact
- Vorher: 5 separate Automatisierungstools, fragile Ketten, keine Fehlerbehandlung
- Nachher: Eine orchestrierte Pipeline mit Logging, Retry und Fallback
- ROI: 99,7% Verarbeitungsquote (vorher 91%), 4 Apps eingespart
Prozess 8: Automatische Retouren-Verarbeitung mit Condition-Checking
Das Problem
Der Kunde meldet eine Retoure an. Je nach Produktzustand (ungeöffnet, geöffnet, beschädigt), Retourengrund (Umtausch, Rücksendung, Garantie), Produktkategorie (Hygieneartikel, Elektronik, Textil) und Kundenhistorie (wie viele Retouren in den letzten 12 Monaten?) sollen unterschiedliche Workflows ausgelöst werden.
Warum Plugins hier scheitern
Returns-Apps wie Loop oder ReturnGO bieten regelbasierte Retouren. Aber Condition-Logik über mehrere Dimensionen (Zustand × Grund × Kategorie × Kundenhistorie × Warenwert) mit unterschiedlichen Outcomes (Sofort-Erstattung vs. Inspektion vs. Ablehnung vs. Teilerstattung) und Anbindung an das eigene Retourenlager-System ist zu komplex für vorgefertigte Lösungen.
Die Custom-Lösung
// Retouren-Entscheidungsengine
async function processReturn(returnRequest) {
const { orderId, lineItemId, reason, condition, customerId } = returnRequest;
// Daten sammeln
const [order, customer, product, returnHistory] = await Promise.all([
getOrder(orderId),
getCustomer(customerId),
getProductFromLineItem(lineItemId),
getReturnHistory(customerId, 12) // Letzte 12 Monate
]);
const itemValue = parseFloat(order.line_items
.find(li => li.id === lineItemId)?.price || '0');
// Entscheidungsmatrix
const decision = evaluateReturnPolicy({
condition, // 'sealed' | 'opened' | 'damaged' | 'defective'
reason, // 'exchange' | 'refund' | 'warranty' | 'wrong_item'
productCategory: product.product_type,
isHygiene: product.tags.includes('hygiene'),
itemValue,
returnRate: returnHistory.count / 12, // Durchschnittliche Retouren/Monat
customerLifetimeValue: parseFloat(customer.total_spent),
daysSinceDelivery: getDaysSinceDelivery(order)
});
// Entscheidung ausführen
switch (decision.action) {
case 'INSTANT_REFUND':
// Bei Stammkunden mit niedrigem Warenwert → Sofort-Erstattung
await createRefund(orderId, lineItemId, decision.amount);
await sendEmail(customer.email, 'return_instant_refund', decision);
break;
case 'INSPECT_THEN_REFUND':
// Retourenlabel erstellen, Inspektion bei Wareneingang
const label = await generateReturnLabel(order.shipping_address);
await createReturnOrder(orderId, lineItemId, label.trackingNumber);
await sendEmail(customer.email, 'return_label', { label, decision });
break;
case 'PARTIAL_REFUND':
// Geöffnete Ware: Teilerstattung anbieten
await createRefund(orderId, lineItemId, decision.amount);
await sendEmail(customer.email, 'return_partial', decision);
break;
case 'DENY':
// Hygieneartikel geöffnet oder zu hohe Retourenquote
await sendEmail(customer.email, 'return_denied', {
reason: decision.denyReason
});
await flagCustomer(customerId, 'high_return_rate');
break;
}
// Buchhaltung aktualisieren
await syncReturnToAccounting(decision);
return decision;
}
Business Impact
- Vorher: Jede Retoure manuell bewertet (Ø 12 Min.), inkonsistente Entscheidungen
- Nachher: 85% aller Retouren vollautomatisch verarbeitet in < 5 Sekunden
- ROI: 2 Vollzeit-Support-Mitarbeiter entlastet, Kundenzufriedenheit +18%
Prozess 9: Dynamische Collection-Sortierung basierend auf Echtzeit-KPIs
Das Problem
Ihre "Bestseller"-Collection soll nicht einfach nach Verkaufszahlen sortiert sein. Das Ranking soll auf einem zusammengesetzten Score basieren: 40% Umsatz der letzten 7 Tage, 30% Conversion-Rate, 20% Lagerumschlag und 10% Marge. Produkte mit weniger als 10 Stück Restbestand sollen herabgestuft werden, und saisonale Produkte sollen einen temporären Boost bekommen.
Warum Plugins hier scheitern
Collection-Sortierungs-Apps sortieren nach vorgegebenen Metriken (Verkaufszahl, Umsatz, Datum). Einen gewichteten Multi-Faktor-Score mit externen Datenquellen (GA4 Conversion-Rate, ERP-Marge) und dynamischen Boosts gibt es nicht als Plugin.
Die Custom-Lösung
// Dynamische Collection-Sortierung
async function sortCollectionByScore(collectionId) {
const products = await getCollectionProducts(collectionId);
// KPIs für jedes Produkt laden
const scoredProducts = await Promise.all(
products.map(async (product) => {
const [sales, analytics, inventory, margin] = await Promise.all([
getSalesData(product.id, 7), // Letzte 7 Tage
getGA4ConversionRate(product.handle), // Google Analytics 4
getInventoryLevel(product.id), // Aktueller Bestand
getMarginFromERP(product.sku) // Marge aus ERP
]);
// Gewichteter Score
let score =
sales.revenue * 0.4 +
analytics.conversionRate * 100 * 0.3 + // Normalisiert
inventory.turnoverRate * 0.2 +
margin.percentage * 0.1;
// Penalty: Niedriger Bestand
if (inventory.available < 10) {
score *= 0.5; // 50% Abzug
}
// Boost: Saisonale Produkte
if (isInSeason(product.tags)) {
score *= 1.3; // 30% Boost
}
return { productId: product.id, score };
})
);
// Nach Score sortieren und Position aktualisieren
scoredProducts.sort((a, b) => b.score - a.score);
// Shopify Collection-Sortierung setzen (manuell)
const moves = scoredProducts.map((p, index) => ({
id: p.productId,
newPosition: (index + 1).toString()
}));
const mutation = `
mutation collectionReorderProducts(
$id: ID!, $moves: [MoveInput!]!
) {
collectionReorderProducts(id: $id, moves: $moves) {
job { id }
userErrors { field, message }
}
}
`;
await shopifyGraphQL(mutation, { id: collectionId, moves });
}
Relevant: Die Performance Ihrer Collections beeinflusst direkt die Ladezeiten. Mehr dazu in meinem Deep-Dive: Shopify Performance Optimierung.
Business Impact
- Vorher: Manuelle Collection-Pflege, veraltete Sortierungen, Bauchgefühl
- Nachher: Tägliche automatische Sortierung basierend auf echten KPIs
- ROI: +22% Revenue per Visit auf Top-Collections, 5 Stunden/Woche weniger Merchandising-Aufwand
Prozess 10: Automatisierte Compliance-Prüfung (WEEE, Verpackungsgesetz, etc.)
Das Problem
Als deutscher E-Commerce-Händler müssen Sie eine Vielzahl regulatorischer Anforderungen erfüllen: WEEE-Registrierung für Elektrogeräte, Verpackungsgesetz (VerpackG) Lizenzierung, Produktsicherheitsverordnung, CE-Kennzeichnung, GPSR (General Product Safety Regulation seit 2024), Textilkennzeichnung und mehr. Bei 500+ Produkten aus verschiedenen Quellen ist die manuelle Prüfung ein Vollzeitjob.
Warum Plugins hier scheitern
Es gibt schlicht keine Standard-Plugins für deutsche E-Commerce-Compliance. Die Anforderungen sind zu spezifisch, zu dynamisch (Gesetzesänderungen) und zu stark von Produktkategorie und Lieferkette abhängig. Internationale App-Entwickler bauen keine Apps für das deutsche Verpackungsgesetz.
Die Custom-Lösung
// Compliance-Prüfungs-Engine
async function runComplianceCheck() {
const products = await getAllActiveProducts();
const issues = [];
for (const product of products) {
const productIssues = [];
// WEEE-Prüfung: Elektrogeräte brauchen WEEE-Registrierung
if (isElectrical(product)) {
const weeeReg = product.metafields?.compliance?.weee_number;
if (!weeeReg) {
productIssues.push({
severity: 'critical',
type: 'WEEE',
message: 'WEEE-Registrierungsnummer fehlt',
action: 'Produkt muss bei stiftung ear registriert werden'
});
}
}
// VerpackG: Alle physischen Produkte brauchen Lizenzierung
if (product.requires_shipping) {
const verpackLicense = product.metafields?.compliance?.verpackg_licensed;
if (!verpackLicense) {
productIssues.push({
severity: 'warning',
type: 'VerpackG',
message: 'Verpackungslizenz nicht hinterlegt',
action: 'Verpackungsmengen bei LUCID registrieren'
});
}
}
// GPSR: Seit 13.12.2024 Pflicht — Verantwortliche Person in der EU
const gpsrContact = product.metafields?.compliance?.gpsr_responsible;
if (!gpsrContact) {
productIssues.push({
severity: 'critical',
type: 'GPSR',
message: 'Verantwortliche Person nach GPSR fehlt',
action: 'EU-Verantwortlichen auf Produkt und im Listing angeben'
});
}
// Textilkennzeichnung
if (isTextile(product)) {
const composition = product.metafields?.specs?.textile_composition;
if (!composition) {
productIssues.push({
severity: 'critical',
type: 'TextilKennzG',
message: 'Materialzusammensetzung fehlt',
action: 'Fasergehalt in % angeben (z.B. "80% Baumwolle, 20% Polyester")'
});
}
}
// CE-Kennzeichnung
if (requiresCE(product)) {
const ceMarking = product.metafields?.compliance?.ce_declaration;
if (!ceMarking) {
productIssues.push({
severity: 'critical',
type: 'CE',
message: 'CE-Konformitätserklärung fehlt',
action: 'Konformitätserklärung vom Hersteller anfordern und hinterlegen'
});
}
}
if (productIssues.length > 0) {
issues.push({ product: product.title, sku: product.sku, issues: productIssues });
// Produkt taggen für einfaches Filtern im Admin
await tagProduct(product.id, productIssues.map(i =>
`compliance:${i.type.toLowerCase()}:missing`
));
}
}
// Compliance-Report generieren
const report = generateComplianceReport(issues);
await sendReportEmail(report);
await saveReportToDashboard(report);
return report;
}
Beispiel-Report
Der automatisch generierte Report könnte so aussehen:
| Schweregrad | Typ | Betroffene Produkte | Handlungsbedarf |
|---|---|---|---|
| 🔴 Kritisch | GPSR | 47 Produkte | EU-Verantwortlichen angeben |
| 🔴 Kritisch | WEEE | 12 Produkte | WEEE-Nummer nachtragen |
| 🟡 Warnung | VerpackG | 8 Produkte | Lizenz prüfen |
| 🟢 OK | CE | 0 Produkte | Alle vollständig |
Business Impact
- Vorher: Keine systematische Prüfung, Compliance-Risiken unbekannt
- Nachher: Wöchentlicher automatischer Audit, sofortige Benachrichtigung bei neuen Produkten
- ROI: Vermeidung von Bußgeldern (WEEE: bis 100.000€, VerpackG: bis 200.000€)
Vergleichstabelle: Plugin vs. Custom Automatisierung
| Kriterium | Standard-Plugin | Custom-Automatisierung |
|---|---|---|
| Einrichtungszeit | Minuten bis Stunden | Tage bis Wochen |
| Monatliche Kosten | $20–$200/App | Hosting: $5–$50 |
| Entwicklungskosten | $0 | $2.000–$15.000+ |
| Flexibilität | Begrenzt auf vorgesehene Funktionen | Unbegrenzt |
| Multi-System-Integration | Kaum (meist nur Shopify) | Voll (ERP, PIM, WMS, etc.) |
| Skalierung | App-abhängig | Selbst kontrollierbar |
| Fehlerbehandlung | Generisch | Auf Ihren Workflow zugeschnitten |
| API-Rate-Limits | Geteilt mit anderen Apps | Dediziert für Ihre Prozesse |
| Datenschutz/DSGVO | Daten bei Drittanbieter | Daten in Ihrer Infrastruktur |
| Support | Ticket-System des Anbieters | Direkter Draht zum Entwickler |
| Langfristige Kosten (3 Jahre) | $720–$7.200/App | $180–$1.800 + einmalig Entwicklung |
Wann lohnt sich Custom?
Die einfache Faustregel:
Wenn (monatliche Plugin-Kosten × 18 Monate) > Custom-Entwicklung
→ Custom lohnt sich fast immer
Beispiel: Sie zahlen $400/Monat für 5 Apps, die zusammen Ihren Order-Workflow abdecken. In 18 Monaten sind das $7.200. Eine Custom-Lösung für $6.000 amortisiert sich innerhalb von 15 Monaten — und danach sparen Sie dauerhaft.
Wann sollten Sie in Custom-Automatisierung investieren?
Nicht jeder Shop braucht Custom-Automatisierung. Hier ist eine ehrliche Einschätzung:
✅ Custom lohnt sich, wenn:
- Sie mehr als $300/Monat für Automatisierungs-Apps ausgeben
- Sie regelmäßig manuelle Workarounds für Plugin-Limitierungen nutzen
- Ihre Processes mehrere Systeme (ERP, PIM, WMS, CRM) einbeziehen
- Sie spezifische deutsche Compliance-Anforderungen haben
- Sie Multi-Store oder Multi-Brand betreiben
- Ihre B2B-Preislogik zu komplex für Standard-Kataloge ist
- Sie mehr als 500 Bestellungen/Monat verarbeiten
❌ Standard-Plugins reichen, wenn:
- Sie einen einzelnen Store mit Standardprozessen betreiben
- Ihre Fulfillment-Logik ein Lager, ein Carrier umfasst
- Sie unter 200 Bestellungen/Monat haben
- Ihre Preis- und Rabattlogik einfach und einheitlich ist
- Sie keine ERP-Integration benötigen
Der Hybrid-Ansatz
In der Praxis empfehle ich oft eine Mischstrategie:
- Standard-Plugins für isolierte, gut gelöste Probleme (z.B. E-Mail-Marketing mit Klaviyo)
- Shopify Flow für einfache interne Automatisierungen (Tags setzen, Benachrichtigungen)
- Custom-Automatisierung für system-übergreifende, geschäftskritische Workflows
Die technische Umsetzung: So gehe ich vor
Wenn Sie sich für Custom-Automatisierung entscheiden, ist ein strukturiertes Vorgehen entscheidend:
Phase 1: Prozess-Audit (1–2 Tage)
- Alle bestehenden Automatisierungen dokumentieren
- Manuelle Workarounds identifizieren
- Betroffene Systeme und APIs erfassen
- Prioritäten nach Business Impact definieren
Phase 2: Architektur-Design (2–3 Tage)
- System-Landkarte erstellen
- API-Kompatibilität prüfen
- Fehlerszenarien durchspielen
- Hosting und Infrastruktur planen
Phase 3: Entwicklung (1–4 Wochen)
- Iterative Entwicklung mit wöchentlichen Demos
- Umfangreiche Error-Handling und Logging
- Monitoring und Alerting einbauen
- Dokumentation parallel erstellen
Phase 4: Testing & Go-Live (3–5 Tage)
- Shadow-Mode: Parallel zum bestehenden Prozess laufen lassen
- Ergebnisse vergleichen und validieren
- Schrittweise Umstellung
- Monitoring der ersten Wochen
Fazit: Automatisierung ist kein Plugin-Problem
Die meisten Shopify-Händler starten richtig: Sie nutzen Apps für Standard-Aufgaben. Aber ab einem gewissen Wachstumspunkt werden die Lücken zwischen den Apps größer als die Funktionalität der Apps selbst.
Custom-Automatisierung ist kein Luxus — es ist die logische nächste Stufe für Shops, die skalieren wollen, ohne proportional mehr Personal für manuelle Prozesse einzustellen.
Die 10 Prozesse in diesem Artikel sind keine theoretischen Szenarien. Es sind genau die Herausforderungen, die mir Shopify-Händler täglich beschreiben. Und in jedem Fall war die Custom-Lösung am Ende günstiger, zuverlässiger und wartbarer als der Plugin-Stack, den sie ersetzte.
Ihr nächster Schritt
Sie erkennen Ihren Shop in einem oder mehreren dieser Szenarien wieder? In einem kostenlosen 15-Minuten-Audit analysiere ich Ihre aktuellen Automatisierungen und zeige Ihnen, wo Custom-Lösungen den größten Impact hätten.
Kein Verkaufsgespräch. Keine Verpflichtung. Nur eine ehrliche Einschätzung, ob Custom-Automatisierung für Ihren Shop sinnvoll ist.

Über den Autor
Justin Kreutzmann ist Experte für Shopify-Entwicklung und E-Commerce-Skalierung. Er hilft Marken dabei, technische Grenzen zu überwinden und performante Online-Shops zu bauen.
Zusammenarbeiten →