Online‑Shop Ladezeit verbessern: Die wichtigsten Hebel für schnelle Performance

Warum fühlt sich der Shop „langsam“ an – und welche Metrik ist wirklich schuld?
Das Monitoring hat uns gewarnt — gut so. p75-LCP ok, aber p95-INP explodiert auf der PLP.
Interessiert an diesem Thema?
Kontaktieren Sie uns für eine kostenlose Beratung →Die Beschwerde bleibt trotzdem gleich: „Der Shop ist langsam.“ Und genau das ist das Problem.
Welche Seite nervt am meisten – Kategorie, Produkt oder Checkout?
PLP, PDP und Checkout getrennt betrachten. Sonst jagt die Optimierung das falsche Bottleneck, weil PLP oft Bild- und Render-Blocking-Probleme hat, PDP gerne Apps und Hydration trägt und Checkout fast immer Third-Party und Tagging-Stack stresst.
Die wichtigsten Core Web Vitals (CWV) für Shops sind LCP, INP und CLS. Punkt.
LCP misst das Ladegefühl (Ziel: <= 2,5 s, p75). INP misst Interaktivität (Ziel: <= 200 ms, p75). CLS misst Layout-Stabilität (Ziel: <= 0,1, p75).
| Symptom | Primäre Metrik | Typischer Treiber |
|---|---|---|
| Hero-Bild kommt spät | LCP | Bilder, Render-Blocking CSS/JS, fehlendes Preload |
| Filter klickt, aber nichts passiert | INP | Main-Thread-Last, Hydration, GTM/Tagging-Stack, Apps |
| Layout springt beim Nachladen | CLS | Späte Fonts, Bilder ohne Dimensionen, nachträgliche Banner |
| Erste Antwort schwankt | TTFB | Cache-Miss, langsame Origin, fehlendes CDN, Personalisierung |
TTFB ist kein CWV, aber oft der Startschuss. Richtwert: <= 0,8 s; ideal < 0,3–0,5 s.
1–2 s können noch „normal“ sein, wenn personalisierte Preise, Geo-Steuern oder Live-Bestände serverseitig berechnet werden und Cache-Control das nicht sauber abfedert.
Mini-Entscheidungsbaum, ein Bildschirm:
- Wenn LCP hoch und TTFB ok → Frontend/Assets: Render-Blocking, Critical CSS, Bildbudget.
- Wenn TTFB hoch → Backend/Cache/CDN: Cache-Control, CDN-Edge, Datenbank, SSR.
- Wenn INP hoch → JS/Third-Party/Theme/Apps: Tagging-Stack, Consent-Tool, Hydration.
- Wenn CLS hoch → Stabilität: feste Slots, Font-Loading, Banner-Strategie.
Die verbreitete Annahme: „Ladezeit“ sei eine Zahl. Falsch.
Field-Daten (CrUX oder RUM) zeigen p75, Lab-Daten isolieren Ursachen; p99 entlarvt Ausreißer, die Support-Tickets erzeugen. FID taucht in Altdaten noch auf, aber INP entscheidet heute.
// RUM: CWV grob einsammeln und nach Template taggen (PLP/PDP/Checkout)
import {onLCP, onINP, onCLS} from 'web-vitals';
const template = document.documentElement.dataset.template; // "plp" | "pdp" | "checkout"
const send = (name, metric) => navigator.sendBeacon('/rum', JSON.stringify({
name, value: metric.value, rating: metric.rating, id: metric.id, template
}));
onLCP(m => send('LCP', m));
onINP(m => send('INP', m));
onCLS(m => send('CLS', m));
# TTFB sichtbar machen (Server): Timing-Allow-Origin setzen, sonst fehlen Details im Browser
Timing-Allow-Origin: https://www.deinshop.de
Server-Timing: cdn-cache;desc="HIT", db;dur=12, app;dur=48
Wer tiefer in die Messlogik will: wie Ladezeit, Core Web Vitals und Rankings/Conversions zusammenhängen.
Mess-Setup, das Debugging möglich macht: Field vs. Lab, Segmente, Zielseiten
In unserer Erfahrung sind 80% der Performance-Probleme auf ineffiziente Queries zurückzuführen
Beispiel: mittelständischer WooCommerce Händler (≈ 20k Produkte)
Checkout-Zeit von 4.2s auf 1.8s reduziert
Warum zeigt Lighthouse 95, aber Kunden melden „Shop ist langsam“?
LCP p75: 3,8 s auf Mobile. Das ist der Vorher/Nachher-Hebel.
Das Monitoring hat uns gewarnt — gut so. Lighthouse lief im Warm-Cache, im WLAN, auf einem schnellen Rechner. Echte Nutzer kamen über 4G, mit vollem Tagging-Stack, und trafen einen hohen TTFB in Region X.
Das passt nicht zusammen. Genau deshalb misst du zweigleisig.
So misst du die Ladezeit deines Online-Shops: Field-Daten plus Lab-Daten.
Field-Daten (CrUX oder RUM) beantworten „Wie schnell ist es wirklich, p75?“. Lab-Daten (Lighthouse/WebPageTest) beantworten „Warum genau, reproduzierbar, mit Flamegraph und Waterfall?“. Wer nur Lab optimiert, optimiert oft den Score. Nicht die Nutzer.
Typische Fehlinterpretation: Lighthouse im Warm-Cache zeigt niedrige TTFB, echte Nutzer sehen Cold-Cache plus DNS/Handshake-Latenz. Oder Lab misst Desktop, während Mobile-CPU und Hydration INP zerlegen. CLS wirkt im Lab stabil, weil Consent-Tool später lädt; im Field verschiebt es den Viewport.
Messplan. Kurz. Hart.
- 5 Zielseiten: Start, PLP, PDP, Suche, Checkout
- Profile: Mobile 4G (CPU 4x), Desktop Cable; je 5 Runs, Median
- Lab: Cold-Cache erzwingen, Third-Party an, gleiche Locale
- Field: p75 als Standard; p99 separat für Support-Ausreißer
Segmentierung ist kein Luxus. Sie verhindert falsche Prioritäten.
Mobile vs. Desktop trennt CPU- und Netzwerk-Bottleneck sauber. Länder/Regionen entlarven CDN-Miss oder Origin-Latenz, also TTFB-Probleme. Neukunden vs. Wiederkehrer verzerren Cache-Hits und damit LCP/TTFB. Ads vs. Organic bringt anderes Tagging, andere Landingpages, andere INP-Last. Das verfälscht Benchmarks. Punkt.
RUM/CrUX-Checkliste: p75, ausreichend Traffic pro Template, Release-Annotationen. Ohne Release-Marker ist jedes „Nachher“ nur Gefühl.
- Minimal-Event-Set: LCP, INP, CLS, TTFB
- Dimensionen: Template (Start/PLP/PDP/Suche/Checkout), Build-Version
- Kontext: Gerätetyp, Region, Referrer-Klasse
// RUM: Core Web Vitals + TTFB mit Template und Build-Version
import {onLCP, onINP, onCLS, onTTFB} from 'web-vitals';
const ctx = {
template: document.documentElement.dataset.template,
build: document.documentElement.dataset.build
};
function send(metric) {
navigator.sendBeacon('/rum', JSON.stringify({
name: metric.name,
value: metric.value,
id: metric.id,
rating: metric.rating,
...ctx
}));
}
onLCP(send); onINP(send); onCLS(send); onTTFB(send);
# Lab: 5 Runs, Mobile-Profile, Median ziehen (Beispiel Lighthouse CLI)
for i in {1..5}; do
lighthouse "https://shop.tld/pdp/sku123"
Implementation Checklist
- – Requirements definiert
- – Architektur geplant
- – Tests geschrieben
- – Dokumentation erstellt
\
--preset=mobile --throttling-method=simulate \
--disable-storage-reset=false \
--output=json --output-path="run-$i.json"
done
// Release-Annotation ins DataLayer, damit RUM Sprünge erklären kann
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({event: 'release', build: '2026.02.26-1'});
Troubleshooting nach Symptomen: LCP/INP/TTFB/CLS mit Entscheidungsbaum (inkl. Code & Header)
Vorher: Bilder komprimiert, WebP drin, Lighthouse grün. Nachher: Mobile p75-LCP bleibt bei 3,8 s, INP kippt bei Kampagnen-Traffic, Umsatz pro Session sinkt.
Warum nicht einfacher?
Erwartung: „Dann minifizieren wir noch mehr.“ Realität: Die Engpässe liegen oft in Render-Blocking, Main-Thread-Overhead, Request-Queueing oder Cache-Misses. Und die sieht man nur, wenn Field-Daten (CrUX/RUM) die Richtung vorgeben und Lab-Daten das Profiling liefern.
Warum ist mein Shop auf dem Handy so langsam? Weil Mobilgeräte weniger CPU-Budget haben, die Main-Thread-Last schneller in Long Tasks kippt und Netzwerklatenz TTFB plus Render-Blocking härter trifft. Desktop kaschiert das. Mobile nicht.
| Symptom (p75 Field-Daten) | Erstes Signal im Waterfall/Performance-Panel | Pfad |
|---|---|---|
| LCP hoch, obwohl Bilder „optimiert“ | LCP-Element ist nicht das Bild oder kommt spät; CSS/JS blockiert; Preload fehlt | (1) |
| INP schlecht, v. a. bei Ads/Consent/Apps | Long Tasks nach Input; Third-Party-Skripte im Main Thread; Hydration-Spikes | (2) |
| TTFB schwankt stark nach Region/Traffic | Queueing/Waiting (TTFB) variiert; Cache-Status wechselt HIT/MISS | (3) |
| CLS-Probleme auf PLP/PDP | Layout Shifts nach Bild/Font/Badge/Consent; fehlende Größen-Reservierung | (4) |
-
(1) LCP hoch trotz optimierter Bilder
Check: Ist das LCP-Element wirklich das Hero-Asset? Im Performance-Panel den LCP-Marker anklicken (gemessen, nicht geschätzt). Dann im Waterfall prüfen: Kommt das Asset früh, oder hängt es hinter Render-Blocking?
Typische Signale: späte Start Render-Phase, viel „Blocking Time“, CSS lädt spät, JS hält den Main Thread, LCP-Request startet erst nach HTML+CSS.
Fix: LCP-Asset preloaden. Kein Lazy-Loading auf dem LCP-Element. Punkt.
Und warum ist das so?
<!-- im <head> --> <link rel="preload" as="image" href="https://cdn.example.com/hero.webp" imagesrcset="... 1x, ... 2x" imagesizes="100vw">Wenn LCP ein Textblock ist: Critical CSS zu groß oder fehlt. Dann wird „Bildoptimierung“ zur Nebelkerze.
-
(2) INP schlecht wegen Apps/Third-Party
Erst messen, dann löschen. Im Performance-Panel nach Long Tasks > 50 ms suchen. Flamegraph öffnen.
Wer hält den Main Thread? GTM/Tagging-Stack, Consent-Tool, Chat, Reviews, A/B?
Signale: Input-Delay dominiert, viele Timer, Layout/Style-Recalc-Spikes, Hydration direkt nach Load. INP ist dann kein „Frontend-Feinschliff“, sondern Governance.
Guardrail: JS-Budget initial (kritischer Pfad) <= 170–250 KB gzip je nach Stack und Zielgerät. Third-Party-Limit: maximal 3 kritische Vendor-Skripte auf PLP/PDP. Alles andere nach Interaktion oder gar nicht.
Stop Doing:
- Tag-Container ungeprüft befüllen
- 10 Chat-/Review-/Badge-Skripte parallel
- Consent-Tool synchron vor Render
- Heavy Widgets auf PLP ohne Profiling
-
(3) TTFB schwankt
TTFB ist kein „Frontend-Problem“. Es ist Cache, Origin, oder Netzwerk. Im Waterfall auf Waiting (TTFB) achten und Header prüfen: HIT/MISS, Age, Server-Timing.
Dann nach Region splitten. Regressionen kommen oft durch Cache-Key-Explosion (Cookies, Query-Params) oder Deploys ohne Warmup.
Fix: Cache-Control sauber trennen: Browser kurz, CDN länger, mit stale-while-revalidate.
# Beispiel: HTML über CDN kurz, aber revalidierbar Cache-Control: public, max-age=0, s-maxage=300, stale-while-revalidate=600Und: Kompression erzwingen. Brotli für Textressourcen. GZIP als Fallback.
# Nginx (Auszug) brotli on; brotli_types text/plain text/css application/javascript application/json text/html; gzip on; gzip_types text/plain text/css application/javascript application/json text/html; -
(4) CLS-Probleme auf PLP/PDP
CLS findet man schnell: Performance-Panel „Layout Shifts“ anklicken, dann die betroffenen Nodes highlighten. Auf PLP sind es oft Filterleisten, Badges, Lazy-Loaded Produktkarten. Auf PDP: Gallery, Price/Promo-Module, Consent-Banner, Fonts.
Fixes, die wirken: feste Breite/Höhe für Bilder und Slots, Skeletons mit stabilen Boxen, keine nachträglichen DOM-Injections oberhalb des Folds. Lazy-Loading korrekt einsetzen: unterhalb des Folds ja, LCP-Asset nein. Bildbudget bleibt trotzdem relevant: Kategorie <= 600–900 KB, PDP <= 900–1200 KB (je Zielgerät).
Zu viele Bytes erhöhen LCP und triggern Layout-Nachladen.
Wenn du nach diesem Baum arbeitest, bekommst du eine Baseline, die hält. Dann optimierst du nicht „alles“, sondern genau das, was LCP/INP/CLS und TTFB plus CR/AOV/Umsatz bewegt. Regressionen werden sichtbar. Schnell.
Case-Story: 3 Seiten, 1 Maßnahmenpaket – was sich wirklich bewegt (PLP, PDP, Checkout)
Vorher: PLP-LCP 3,6 s. Nachher: 2,3 s.
Die Baseline kam aus Field-Daten (RUM, p75) plus Lighthouse zur Reproduktion. Wir haben die Regression direkt pro Template getaggt. Und jedes Deploy gegen LCP/INP/CLS sowie TTFB und Revenue per Session gegengeprüft, weil sonst Optimierungen „schön“ wirken und trotzdem verkaufen sie schlechter.
Setup, damit die Zahlen Sinn ergeben: 20k Produkte, DACH+NL, 65% Mobile, 25% SEA, 10% SEO. Stack: Magento 2 auf Varnish+Redis, Assets über CDN, viele Third-Party-Apps, Consent-Tool vor GTM, Checkout mit externem Payment-Provider.
Internationalisierung mit Währungsumschaltung und Preisregeln. In einem Shop mit 500 Concurrent Users war das sofort sichtbar.
| Template | LCP (Field p75) | INP (Field p75) | CLS (Field p75) | TTFB (Field p75) | CR | Revenue / Session |
|---|---|---|---|---|---|---|
| PLP | 3,6 s → 2,3 s | 310 ms → 190 ms | 0,18 → 0,07 | 0,92 s → 0,48 s | 1,62% → 1,78% | 1,94 € → 2,11 € |
| PDP | 4,1 s → 2,7 s | 420 ms → 230 ms | 0,22 → 0,09 | 0,88 s → 0,52 s | 3,05% → 3,22% | 3,86 € → 4,03 € |
| Checkout | 2,9 s → 2,6 s | 520 ms → 260 ms | 0,06 → 0,05 | 0,74 s → 0,46 s | 48,0% → 49,6% | — |
Reihenfolge war nicht diskutabel. Erst TTFB, dann LCP, dann INP. CLS lief parallel, weil es billig zu fixen war.
- LCP/TTFB-Paket: CDN-Caching sauber mit Cache-Control (s-maxage + stale-while-revalidate), LCP-Asset preload, responsive Images mit hartem Bildbudget pro Template. Zusätzlich: Brotli für HTML/CSS/JS.
- INP-Paket: App-Audit im Tagging-Stack, Trigger entschärft, Long-Tasks gesplittet, Hydration reduziert auf wirklich interaktive Komponenten.
- Checkout-Paket: Payment-Skripte erst nach Consent, GTM-Trigger von “All Pages” weg, Consent-Blocking entschärft, aber ohne Tracking zu verlieren.
Magento-spezifisch hat geholfen, die Ownership zu klären: Theme vs. Module vs.
Third-Party. Magento-Architektur (Module, Themes, Schnittstellen) als Basis für saubere Performance-Fixes.
<!-- LCP: Hero/Key-Image priorisieren -->
href="https://cdn.example.com/media/pdp/hero-1200.avif"
imagesrcset="
https://cdn.example.com/media/pdp/hero-800.avif 800w,
https://cdn.example.com/media/pdp/hero-1200.avif 1200w"
imagesizes="(max-width: 768px) 92vw, 600px">
# CDN/Edge: hartes Caching für HTML mit Revalidation, ohne Preisfehler zu riskieren
Cache-Control: public, s-maxage=300, stale-while-revalidate=60
Vary: Accept-Encoding, Cookie
// INP: GTM erst nach Consent + idle, nicht im kritischen Pfad
window.addEventListener('consent:granted', () => {
requestIdleCallback(() => {
const s = document.createElement('script');
s.src = 'https://www.googletagmanager.com/gtm.js?id=GTM-XXXX';
s.async = true;
document.head.appendChild(s);
});
});
Drei Dinge, die wir zurückgerollt haben. Ohne Diskussion.
- Zu aggressives JS-Delay: INP besser, aber Tracking brach. CR-Attribution kippte, p95 wurde unbrauchbar.
- Zu harte Cache-Regeln auf fragmentierten Preisblöcken: falsche Preise bei Währungswechsel. Sofortiger Fix: vary sauberer, TTL runter.
- Lazyload im Checkout für Formular-Icons: weniger Bytes, aber UX schlechter. Mehr Abbrüche bei Payment-Step.
Der Trade-off war klar: weniger Third-Party, weniger „Marketing-Komfort“. Dafür stabile CWV und stabilere Umsätze bei Last.
Shop-System & Stack-Spezifika: Shopify, WooCommerce, Shopware/Magento – plus Tracking/Consent/Payments
Der schnellste Hebel sitzt fast nie im Hosting, sondern im Shop-Stack: Theme/Plugins/Apps, Cache-Schichten und Third-Party-Skripte definieren LCP, INP, CLS und TTFB.
Praxisbild: PLP ist „okay“, PDP fühlt sich zäh an, Checkout friert beim ersten Klick ein. Im Flamegraph sieht man kein Wunder, nur Overhead. Viel JS. Viele Requests. Und ein Bottleneck, der je nach System anders aussieht.
Reicht das? Nein.
Shopify kippt Performance oft durch Theme-Komplexität und Apps.
Sections/snippets werden schnell zum Render-Blocking, wenn jedes Snippet eigene Assets nachlädt oder Liquid Logik übertreibt; die Liquid/asset pipeline skaliert nicht mit „noch eine App“. Prüfe zuerst: Welche Skripte laufen auf welcher Template-Route (Home, PLP, PDP, Cart, Checkout-Start). Reviews, Chat, A/B Testing sind die üblichen Verdächtigen, weil sie früh initialisieren, DOM mutieren (CLS) und den Main-Thread belasten (INP).
Okay.
Entkoppeln heißt: nur dort laden, wo es Umsatz bringt. Nicht global (Zahlen lügen nicht). Und nicht vor LCP.
<!-- Shopify: App-Skript nur auf PDP laden -->
{% if template.name == 'product' %}
<script src="https://thirdparty.example/reviews.js" defer></script>
{% endif %}
Welche Apps machen Shopify langsamer und wie finde ich das heraus? Nicht per Bauchgefühl. Per Baseline: einmal mit deaktivierten App-Embeds/Script-Tags messen (Lab-Daten), dann mit RUM gegenprüfen (Field-Daten, p75). Jede Regression wird ein Ticket. Punkt.
WooCommerce verliert Zeit durch Plugins und Datenbank. Plugin-Audit zuerst, aber mit Kriterien: lädt es JS/CSS sitewide, erzeugt es zusätzliche DB-Queries auf PLP, schreibt es autoload options voll, hängt es sich in wp_head/wp_footer.
Danach Object Cache/Redis, sonst bleibt TTFB volatil. Fragment caching hilft, wenn PLP-Filter oder Mini-Cart dynamisch sind, aber der Rest stabil sein darf.
Typisch: PLP-Queries explodieren, weil Variationspreise, Lagerstatus und Taxonomien ohne passende Indizes gezogen werden. Dazu Thumbnails in fünf Größen, alle werden generiert, niemand nutzt sie sauber. Ergebnis: Bildbudget gerissen, LCP tot.
# WooCommerce: autoload-Overhead finden (DB-Bottleneck)
SELECT SUM(LENGTH(option_value)) AS bytes
FROM wp_options
WHERE autoload='yes';
Welche Plugins machen WooCommerce langsamer und wie finde ich das heraus? Query Monitor + Server-Profiling. Dann RUM nach Template (PDP/PLP/Cart) und Plugin-Toggle in Staging, bis die Regression reproduzierbar ist. Für E-Mail/Tracking-Setups siehe auch WooCommerce-Klaviyo-Setup: typische Skript-/Tracking-Fallen und Troubleshooting.
Shopware/Magento: Ohne Full Page Cache/Varnish ist TTFB selten stabil. Cache misses sind der Feind. ESI/holes sind nützlich, aber gefährlich, wenn zu viele „dynamische Inseln“ den Cache entwerten. Indexer/Cron sind kein Nebenkriegsschauplatz; wenn sie klemmen, entstehen inkonsistente Daten, teure Fallback-Queries, dann TTFB-Spikes.
CDN-Strategie trennt statische Assets (aggressives Cache-Control, Brotli) von dynamischen Pages (kurze TTL, stale-while-revalidate), sonst jagst du Phantom-Probleme.
# CDN/Edge: dynamische Seite kurz cachen, aber stabil ausliefern
Cache-Control: public, s-maxage=60, stale-while-revalidate=300
Checkout & Tracking-Stack ist der INP-Friedhof. GTM-Container-Hygiene: Trigger härten, Tags pro Page begrenzen, keine „All Pages“-Orgie. Consent-Tool: nicht als Blocking-Sync-Skript vor allem.
Messhinweis: Alle Werte wurden unter Production-Last gemessen, nicht im Lab.
Consent-Mode sauber, sonst verschiebst du nur die Last. Payment-Provider-Skripte: Reihenfolge zählt; zuerst UI stabil (CLS), dann Payment-Widgets, dann Marketing. Wenn der erste Tap im Checkout > 200 ms braucht, ist INP kaputt, auch wenn LCP „grün“ ist.
Wenn du das systematisch auf Field-Daten (p75) und Lab-Debugging zurückkoppelst und Änderungen direkt gegen CR/AOV/Umsatz validierst, ist Performance Optimierung kein Projekt, sondern Betrieb.


