Alle Artikel
/18 Min. Lesezeit

INP in Angular messen und optimieren | Core Web Vitals

Interaction to Next Paint in Angular richtig messen und optimieren: Schwellenwerte, DevTools, Zoneless, OnPush, @defer und Web Worker.

Benjamin Tietz
Benjamin TietzFreelance Angular & DevSecOps Engineer
INP in Angular messen und optimieren | Core Web Vitals

Interaction to Next Paint (INP) hat FID am 12. März 2024 als Core Web Vital abgelöst. Dieser Technikzeitpunkt ist nicht das Publikationsdatum: Der Artikel erschien am 20. März 2026 und wurde am 13. August 2026 fachlich aktualisiert. Ein guter INP-Wert liegt bei höchstens 200 ms im 75. Perzentil. Für Angular sind vor allem kurze Event-Handler, gezielte Change Detection und entkoppelte schwere Arbeit relevant.

Was sich im März 2024 geändert hat: FID ist weg

Seit März 2024 gilt: First Input Delay (FID) ist Geschichte. Interaction to Next Paint (INP) ist das neue Core Web Vital für Interaktivität — und es misst etwas fundamental anderes.

FID maß nur die Verzögerung bis zur ersten Eingabeverarbeitung. INP misst die gesamte Latenz jeder Interaktion auf der Seite: die Zeit vom Klick oder Tastendruck bis zum nächsten sichtbaren Frame im Browser. Das ist deutlich strenger.

INP umfasst Input Delay, Verarbeitungszeit und Presentation Delay bis zum nächsten sichtbaren Frame.
INP umfasst Input Delay, Verarbeitungszeit und Presentation Delay bis zum nächsten sichtbaren Frame.

Felddaten und Labormessungen beantworten unterschiedliche Fragen: Chrome UX Report und Search Console zeigen reale Nutzung über Zeit, während DevTools und Lighthouse einzelne reproduzierbare Abläufe analysieren. Deshalb sollte eine Optimierung nie aus einer isolierten Labormessung abgeleitet werden.

Was ist INP genau?

INP steht für Interaction to Next Paint. Der Wert misst die Zeit vom Beginn einer Benutzerinteraktion (Klick, Touch, Tastendruck) bis zu dem Moment, an dem der Browser den nächsten Frame malt.

  • Input Delay — Zeit bis der Event Handler startet (blockiert durch anderen JS-Code auf dem Haupt-Thread)
  • Processing Time — Zeit, die der Event Handler selbst benötigt
  • Presentation Delay — Zeit bis das Rendering abgeschlossen ist

Für die Feldbewertung zählt der 75.-Perzentil-Wert der Seitenaufrufe, getrennt nach Mobilgeräten und Desktop. Innerhalb eines Seitenaufrufs repräsentiert INP annähernd die langsamste qualifizierte Interaktion; Ausreißer werden bei vielen Interaktionen begrenzt.

Schwellenwerte

Unter 200 ms gilt als gut. Werte zwischen 200–500 ms signalisieren Verbesserungsbedarf. Über 500 ms ist schlecht — hier muss sofort gehandelt werden.

INP messen: Die richtigen Tools

Bevor optimiert wird, muss gemessen werden. Es gibt mehrere Ansätze, die sich ergänzen.

Chrome DevTools — Performance Panel

Das Performance Panel zeigt INP-Kandidaten direkt an. Seit Chrome 122 wird INP als eigenständige Metrik hervorgehoben.

  • DevTools öffnen → Performance-Tab
  • Seite neu laden und mit der App interagieren
  • Aufnahme stoppen → "Interactions"-Lane prüfen
  • Lange Interaktionen (orange/rot markiert) identifizieren

web-vitals.js direkt einbinden

Für Real User Monitoring (RUM) in der eigenen App:

typescript
import { onINP } from 'web-vitals';

onINP(({ value, rating, entries }) => {
  console.log(`INP: ${value}ms (${rating})`);
  // An eigenen Analytics-Endpoint senden
  sendToAnalytics({ metric: 'INP', value, rating });
});

Warum Angular mit Zone.js anfällig ist

Ältere Angular-Anwendungen nutzen häufig Zone.js für Change Detection. Zone.js patcht verbreitete asynchrone Browser-APIs und signalisiert Angular nach Tasks, dass Anwendungszustand verändert sein könnte.

Das Problem ist nicht, dass Zone.js selbst DOM-Updates erzeugt. Es kann jedoch häufiger Anwendungssynchronisation anstoßen als nötig. Wie teuer das wird, hängt von Komponentenbaum, Change-Detection-Strategie und der eigentlichen Arbeit im Event-Handler ab.

bash
[Benutzerinteraktion]
  → Zone.js plant Anwendungssynchronisation
  → Angular durchläuft die relevanten Views
  → geänderte Bindings werden aktualisiert
  → Browser malt den nächsten Frame

OnPush kann Teilbäume überspringen; Signals benachrichtigen Angular gezielt über verwendete Zustände. Zoneless entfernt Zone.js als globalen Task-Trigger, ersetzt aber weder saubere Zustandsgrenzen noch die Messung konkreter Interaktionen.

RUM-Felddaten zeigen reale Nutzung; ein Performance-Trace erklärt anschließend die langsame Interaktion.
RUM-Felddaten zeigen reale Nutzung; ein Performance-Trace erklärt anschließend die langsame Interaktion.

Optimierung 1: Zoneless Change Detection

Seit Angular 20.2 ist Zoneless als stable markiert — seit Angular 21 ist es der Standard für neue Projekte.

In Angular 21 ist Zoneless für neue Anwendungen der Standard. Bestehende Angular-20-Anwendungen aktivieren es mit dem stabilen Provider; bei Angular 21 darf provideZoneChangeDetection() die Voreinstellung nicht wieder überschreiben:

typescript
// Angular 20: app.config.ts
import { provideZonelessChangeDetection } from '@angular/core';

export const appConfig: ApplicationConfig = {
  providers: [provideZonelessChangeDetection()]
};

// Angular 21+: Zoneless ist Standard.
// Danach zone.js aus build/test-Polyfills und Abhängigkeiten entfernen.

Zoneless plant Change Detection über konkrete Angular-Benachrichtigungen, etwa aktualisierte Signals, Template-Listener, gesetzte Inputs oder markForCheck(). Ob INP dadurch sinkt, muss für dieselbe Interaktion vor und nach der Migration in Feld- und Labordaten belegt werden; eine unbelegte Erfolgszahl wäre keine belastbare Fallstudie.

Optimierung 2: OnPush als Sofortmaßnahme

Falls eine vollständige Zoneless-Migration noch nicht möglich ist: ChangeDetectionStrategy.OnPush für alle Komponenten ist die schnellste Einzelmaßnahme.

  • Ein @Input()-Wert (per Referenz) sich ändert
  • Ein Event innerhalb der Komponente ausgelöst wird
  • Explizit markForCheck() aufgerufen wird
  • Ein gebundenes Observable einen neuen Wert emittiert
typescript
@Component({
  selector: 'app-product-list',
  templateUrl: './product-list.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ProductListComponent {}

Faustregel: Jede Komponente ohne OnPush ist eine potenzielle INP-Bombe.

Weniger Overhead, mehr Performance: Zoneless Change Detection.
Weniger Overhead, mehr Performance: Zoneless Change Detection.

Optimierung 3: @defer für nicht-kritische Inhalte

@defer ist eines der am meisten unterschätzten Performance-Features seit Angular 17. Es ermöglicht es, Teile des Templates lazy zu laden — und hält damit den Haupt-Thread beim initialen Render frei.

html
<!-- Kommentarsektion erst laden wenn im Viewport sichtbar -->
@defer (on viewport) {
  <app-comments [postId]="post.id" />
} @placeholder {
  <div class="comments-skeleton">Kommentare werden geladen…</div>
}

<!-- Schwere Chart-Komponente erst nach Nutzer-Interaktion -->
@defer (on interaction) {
  <app-performance-chart [data]="metrics" />
} @placeholder {
  <button class="btn btn--secondary">Chart anzeigen</button>
}

Optimierung 4: Schwere Berechnungen in Web Workers

Algorithmen, die viel CPU benötigen, blockieren den Haupt-Thread direkt. Das Ergebnis: Input Delay steigt, INP verschlechtert sich.

typescript
// product-filter.worker.ts
self.onmessage = ({ data }) => {
  const { products, filters } = data;
  const filtered = products.filter(p => matchesFilters(p, filters));
  self.postMessage(filtered);
};

// component.ts
private readonly worker = new Worker(
  new URL('./product-filter.worker', import.meta.url),
  { type: 'module' }
);

filterProducts(filters: Filters) {
  this.worker.postMessage({ products: this.allProducts(), filters });
  this.worker.onmessage = ({ data }) => this.filteredProducts.set(data);
}

Die Filterlogik läuft jetzt parallel im Worker-Thread — der Haupt-Thread bleibt für Rendering frei.

Optimierung 5: Event Handler schlank halten

Ein häufiger INP-Killer ist zu viel Logik direkt im Event Handler. Alles was nach dem ersten Frame passiert, sollte verschoben werden.

typescript
// ❌ Problematisch
onClick() {
  this.processLargeDataset();     // 200ms
  this.updateMultipleSignals();   // 50ms
  this.triggerAnimations();       // 30ms
  // INP: ~280ms
}
typescript
// ✅ Besser — Hauptthread sofort freigeben
onClick() {
  // Sofortiges visuelles Feedback
  this.isLoading.set(true);

  // Schwere Arbeit nach dem Frame verschieben
  setTimeout(() => {
    this.processLargeDataset();
    this.updateMultipleSignals();
    this.isLoading.set(false);
  }, 0);
}

setTimeout(0) verschiebt Arbeit in eine neue Task und kann frühes visuelles Feedback ermöglichen. Es ist aber kein pauschaler INP-Fix: Lange Folge-Tasks müssen weiter aufgeteilt oder in einen Web Worker ausgelagert und anschließend erneut gemessen werden.

Infrastruktur-Performance: Vom Server bis zum Browser — jede Millisekunde zählt.
Infrastruktur-Performance: Vom Server bis zum Browser — jede Millisekunde zählt.

Zusammenfassung: INP-Checkliste für Angular

  • OnPush für alle Komponenten — Aufwand: mittel, Wirkung: hoch
  • Signals statt Observables für UI-State — Aufwand: mittel, Wirkung: hoch
  • Zoneless Migration — Aufwand: hoch, Wirkung: sehr hoch
  • @defer für nicht-kritische Blöcke — Aufwand: niedrig, Wirkung: mittel–hoch
  • Web Workers für CPU-intensive Arbeit — Aufwand: hoch, Wirkung: situationsabhängig
  • Event Handler entschlacken — Aufwand: niedrig, Wirkung: mittel

FAQ

Ja. Im März 2024 hat Interaction to Next Paint (INP) den First Input Delay (FID) als Core Web Vital für Interaktivität abgelöst — FID wird von Google nicht mehr gemessen oder bewertet. FID maß nur die Verzögerung bis zur ersten Eingabeverarbeitung; INP misst die gesamte Latenz jeder Interaktion und wird im 75. Perzentil berichtet. Unter 200 ms gilt als gut, 200–500 ms als verbesserungswürdig, über 500 ms als schlecht.
Ja. INP misst clientseitige Interaktionen nach dem initialen Load. SSR verbessert LCP (Largest Contentful Paint), hilft aber nicht bei INP — die Change Detection läuft nach der Hydration weiterhin im Browser.
Bis 200 ms gilt als gut. Werte über 200 bis 500 ms gelten als verbesserungswürdig, Werte über 500 ms als schlecht. Diese Schwellen klassifizieren die Nutzererfahrung; eine konkrete Conversion-Wirkung muss separat mit eigenen Daten belegt werden.
Ja. Bei SSR wird der @placeholder-Inhalt serverseitig gerendert. Die eigentliche Komponente lädt erst clientseitig, wenn der definierte Trigger ausgelöst wird.
Nein — aber die Kombination wirkt am stärksten. Komponenten mit OnPush + Signals profitieren sofort von Zoneless. Komponenten ohne OnPush erfordern nach der Migration manuelle markForCheck()-Aufrufe.

Primärquellen

Fragen zu Angular, DevSecOps oder Infrastruktur? Ich baue und betreibe solche Systeme.

Projekt besprechen