Back

Hintergrunddaten mit der Beacon API senden

Hintergrunddaten mit der Beacon API senden

Die Seitennavigation sollte nicht von Analytics-Anfragen als Geisel genommen werden. Wenn Benutzer auf einen Link klicken oder einen Tab schließen, können traditionelle HTTP-Anfragen blockieren oder vollständig fehlschlagen, was zu unvollständigen Daten und frustrierten Benutzern führt. Die Beacon API-Lösung ändert dies, indem sie Anfragen im Hintergrund in die Warteschlange einreiht und sicherstellt, dass Ihre Daten den Server erreichen, ohne die Performance zu beeinträchtigen.

Dieser Artikel zeigt, wie Sie navigator.sendBeacon() für zuverlässige Hintergrunddatenübertragung implementieren. Sie lernen praktische Anwendungen wie Analytics-Tracking und Fehlerberichterstattung kennen, verstehen, warum es fetch() während Seitenübergängen übertrifft, und sehen eine vollständige Implementierung mit modernem JavaScript.

Wichtige Erkenntnisse

  • Die Beacon API reiht Anfragen im Hintergrund in die Warteschlange ein, ohne die Seitennavigation zu blockieren
  • Verwenden Sie navigator.sendBeacon() für Analytics, Fehlerberichterstattung und Benutzeraktions-Tracking
  • Beacons sind zuverlässiger als fetch() während Page-Unload-Events
  • Halten Sie Payloads klein und bündeln Sie mehrere Events für optimale Performance
  • Implementieren Sie Fallbacks für ältere Browser, die die Beacon API nicht unterstützen
  • Die API gibt einen Boolean zurück, der eine erfolgreiche Einreihung in die Warteschlange anzeigt, nicht die Zustellungsbestätigung

Was die Beacon API anders macht

Der Beacon API-Ansatz löst ein grundlegendes Problem: traditionelle HTTP-Anfragen blockieren die Seitennavigation. Wenn Sie fetch() oder XMLHttpRequest während Unload-Events verwenden, muss der Browser warten, bis die Anfrage abgeschlossen ist, bevor die Navigation fortgesetzt werden kann. Dies führt zu einer schlechten Benutzererfahrung und unzuverlässiger Datenübertragung.

Die Beacon API funktioniert anders. Sie reiht Anfragen asynchron in die Warteschlange ein und übernimmt die Übertragung im Hintergrund, sogar nachdem die Seite geschlossen wurde. Der Browser verwaltet den gesamten Prozess, ohne die Navigation zu blockieren oder zu erfordern, dass Ihr JavaScript aktiv bleibt.

Warum traditionelle Methoden während Seitenübergängen versagen

Betrachten Sie dieses häufige Szenario mit fetch():

window.addEventListener('beforeunload', () => {
  // Dies kann fehlschlagen oder die Navigation blockieren
  fetch('/analytics', {
    method: 'POST',
    body: JSON.stringify({ event: 'page_exit' })
  })
})

Dieser Ansatz hat mehrere Probleme:

  • Die Anfrage kann abgebrochen werden, wenn die Seite entladen wird
  • Die Navigation wird blockiert, bis die Anfrage abgeschlossen ist
  • Keine Garantie, dass die Daten den Server erreichen
  • Schlechte Benutzererfahrung mit verzögerten Seitenübergängen

Wie navigator.sendBeacon() funktioniert

Die navigator.sendBeacon()-Methode akzeptiert zwei Parameter: einen URL-Endpunkt und optionale Daten. Sie gibt einen Boolean zurück, der anzeigt, ob die Anfrage erfolgreich in die Warteschlange eingereiht wurde (nicht, ob sie den Server erreicht hat).

const success = navigator.sendBeacon(url, data)

Der Browser übernimmt die tatsächliche Übertragung und optimiert für Netzwerkbedingungen und Systemressourcen. Dieser Fire-and-Forget-Ansatz ist perfekt für Analytics, Logging und Diagnosedaten, bei denen Sie keine Antwort benötigen.

Praktische Implementierungsbeispiele

Grundlegendes Analytics-Tracking

Hier ist eine minimale Implementierung für das Tracking von Benutzersitzungen:

// Session-Daten tracken
const sessionData = {
  userId: 'user123',
  sessionDuration: Date.now() - sessionStart,
  pageViews: pageViewCount,
  timestamp: new Date().toISOString()
}

// Daten senden, wenn die Seite ausgeblendet wird oder der Benutzer wegnavigiert
document.addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'hidden') {
    const payload = JSON.stringify(sessionData)
    navigator.sendBeacon('/log', payload)
  }
})

window.addEventListener('beforeunload', () => {
  const payload = JSON.stringify(sessionData)
  navigator.sendBeacon('/log', payload)
})

Fehlerberichterstattungssystem

Die Beacon API eignet sich hervorragend zum Erfassen und Melden von JavaScript-Fehlern:

window.addEventListener('error', (event) => {
  const errorData = {
    message: event.message,
    filename: event.filename,
    line: event.lineno,
    column: event.colno,
    stack: event.error?.stack,
    userAgent: navigator.userAgent,
    timestamp: Date.now()
  }

  if (navigator.sendBeacon) {
    navigator.sendBeacon('/log', JSON.stringify(errorData))
  }
})

Benutzeraktions-Tracking

Verfolgen Sie spezifische Benutzerinteraktionen, ohne die Benutzeroberfläche zu blockieren:

function trackUserAction(action, details) {
  const actionData = {
    action,
    details,
    timestamp: Date.now(),
    url: window.location.href
  }

  if (navigator.sendBeacon) {
    navigator.sendBeacon('/log', JSON.stringify(actionData))
  }
}

// Verwendungsbeispiele
document.getElementById('cta-button').addEventListener('click', () => {
  trackUserAction('cta_click', { buttonId: 'cta-button' })
})

document.addEventListener('scroll', throttle(() => {
  const scrollPercent = Math.round(
    (window.scrollY / (document.body.scrollHeight - window.innerHeight)) * 100
  )
  trackUserAction('scroll', { percentage: scrollPercent })
}, 1000))

Vollständige Analytics-Implementierung

Hier ist ein umfassendes Beispiel, das mehrere Tracking-Szenarien kombiniert:

class AnalyticsTracker {
  constructor(endpoint = '/log') {
    this.endpoint = endpoint
    this.sessionStart = Date.now()
    this.events = []
    
    this.setupEventListeners()
  }

  setupEventListeners() {
    // Sichtbarkeitsänderungen der Seite verfolgen
    document.addEventListener('visibilitychange', () => {
      if (document.visibilityState === 'hidden') {
        this.sendBatch()
      }
    })

    // Seiten-Unload verfolgen
    window.addEventListener('beforeunload', () => {
      this.sendBatch()
    })

    // Fehler verfolgen
    window.addEventListener('error', (event) => {
      this.trackEvent('error', {
        message: event.message,
        filename: event.filename,
        line: event.lineno
      })
    })
  }

  trackEvent(type, data) {
    this.events.push({
      type,
      data,
      timestamp: Date.now()
    })

    // Batch senden, wenn wir zu viele Events haben
    if (this.events.length >= 10) {
      this.sendBatch()
    }
  }

  sendBatch() {
    if (this.events.length === 0) return

    const payload = {
      sessionId: this.generateSessionId(),
      sessionDuration: Date.now() - this.sessionStart,
      events: this.events,
      url: window.location.href,
      userAgent: navigator.userAgent
    }

    if (navigator.sendBeacon) {
      const success = navigator.sendBeacon(
        this.endpoint, 
        JSON.stringify(payload)
      )
      
      if (success) {
        this.events = [] // Gesendete Events löschen
      }
    }
  }

  generateSessionId() {
    return Math.random().toString(36).substring(2, 15)
  }
}

// Tracker initialisieren
const tracker = new AnalyticsTracker('/log')

// Benutzerdefinierte Events verfolgen
tracker.trackEvent('page_view', { page: window.location.pathname })

Browser-Unterstützung und Fallbacks

Die Beacon API hat ausgezeichnete Browser-Unterstützung in modernen Browsern. Für ältere Browser implementieren Sie einen graceful Fallback:

function sendData(url, data) {
  if (navigator.sendBeacon) {
    return navigator.sendBeacon(url, data)
  }
  
  // Fallback für ältere Browser
  try {
    const xhr = new XMLHttpRequest()
    xhr.open('POST', url, false) // Synchron für Unload-Events
    xhr.setRequestHeader('Content-Type', 'application/json')
    xhr.send(data)
    return true
  } catch (error) {
    console.warn('Fehler beim Senden der Daten:', error)
    return false
  }
}

Best Practices für die Beacon-Implementierung

Payloads klein halten

Die Beacon API ist für kleine Datenpakete konzipiert. Beschränken Sie Payloads auf wesentliche Informationen:

// Gut: Fokussierte, wesentliche Daten
const essentialData = {
  event: 'conversion',
  value: 29.99,
  timestamp: Date.now()
}

// Vermeiden: Große, unnötige Daten
const bloatedData = {
  event: 'conversion',
  value: 29.99,
  timestamp: Date.now(),
  entireDOMState: document.documentElement.outerHTML,
  allCookies: document.cookie,
  completeUserHistory: getUserHistory()
}

Mehrere Events bündeln

Anstatt einzelne Beacons für jedes Event zu senden, bündeln Sie sie zusammen:

const eventBatch = []

function addEvent(eventData) {
  eventBatch.push(eventData)
  
  // Batch senden, wenn er eine bestimmte Größe erreicht
  if (eventBatch.length >= 5) {
    sendBatch()
  }
}

function sendBatch() {
  if (eventBatch.length > 0) {
    navigator.sendBeacon('/log', JSON.stringify(eventBatch))
    eventBatch.length = 0 // Batch leeren
  }
}

Netzwerkfehler graceful handhaben

Da Beacons kein Response-Feedback liefern, implementieren Sie clientseitige Validierung:

function validateAndSend(data) {
  // Datenstruktur validieren
  if (!data || typeof data !== 'object') {
    console.warn('Ungültige Daten für Beacon')
    return false
  }

  // Payload-Größe prüfen (Browser begrenzen typischerweise auf 64KB)
  const payload = JSON.stringify(data)
  if (payload.length > 65536) {
    console.warn('Payload zu groß für Beacon')
    return false
  }

  return navigator.sendBeacon('/log', payload)
}

Beacon API vs Fetch während Seitenübergängen

Der Hauptunterschied wird bei Page-Unload-Events deutlich:

// Beacon API: Nicht-blockierend, zuverlässig
window.addEventListener('beforeunload', () => {
  navigator.sendBeacon('/log', JSON.stringify(data)) // ✅ Zuverlässig
})

// Fetch API: Kann blockieren oder fehlschlagen
window.addEventListener('beforeunload', () => {
  fetch('/log', {
    method: 'POST',
    body: JSON.stringify(data),
    keepalive: true // Hilft, garantiert aber keinen Erfolg
  }) // ❌ Kann während der Navigation fehlschlagen
})

Das keepalive-Flag in Fetch-Anfragen bietet ähnliche Funktionalität, aber mit weniger Zuverlässigkeit als die Beacon API, die speziell für diesen Anwendungsfall entwickelt wurde.

Fazit

Die Beacon API bietet eine robuste Lösung für die Hintergrunddatenübertragung, ohne die Seitennavigation zu blockieren. Durch das asynchrone Einreihen von Anfragen in die Warteschlange gewährleistet sie zuverlässige Datenübertragung bei gleichzeitiger Aufrechterhaltung einer optimalen Benutzererfahrung. Ob Sie Analytics-Tracking, Fehlerberichterstattung oder Benutzeraktions-Logging implementieren - navigator.sendBeacon() bietet die Zuverlässigkeit und Performance, die traditionelle HTTP-Methoden während Seitenübergängen nicht bieten können.

Die Fire-and-Forget-Natur von Beacons macht sie ideal für Szenarien, in denen Sie Daten senden müssen, aber keine Antwort benötigen. In Kombination mit angemessenen Batching-Strategien und Payload-Optimierung wird die Beacon API zu einem unverzichtbaren Werkzeug für moderne Webanwendungen, die sowohl Datenerfassung als auch Benutzererfahrung priorisieren.

FAQs

Die Beacon API ist ein JavaScript-Webstandard, der kleine Datenmengen an einen Server sendet, ohne auf eine Antwort zu warten. Im Gegensatz zu fetch oder XMLHttpRequest werden Beacon-Anfragen vom Browser in die Warteschlange eingereiht und asynchron gesendet, was sie perfekt für Analytics und Logging während Seitennavigationsereignissen macht, bei denen traditionelle Anfragen fehlschlagen oder die Benutzererfahrung blockieren könnten.

Nein, die Beacon API ist für kleine Datenpakete konzipiert, die von den meisten Browsern typischerweise auf 64KB begrenzt sind. Wenn Sie größere Datenmengen senden müssen, erwägen Sie das Bündeln kleinerer Anfragen oder verwenden Sie alternative Methoden wie die Fetch API mit dem keepalive-Flag für nicht-kritische Timing-Szenarien.

Die Beacon API hat ausgezeichnete Unterstützung in allen modernen Browsern einschließlich Chrome, Firefox, Safari und Edge. Sie funktioniert nicht im Internet Explorer. Für die Unterstützung älterer Browser implementieren Sie einen Fallback mit XMLHttpRequest oder fetch, obwohl diese Alternativen möglicherweise nicht die gleiche Zuverlässigkeit während Page-Unload-Events bieten.

Die navigator.sendBeacon-Methode gibt einen Boolean zurück, der anzeigt, ob die Anfrage erfolgreich vom Browser in die Warteschlange eingereiht wurde, nicht ob sie den Server erreicht hat. Da Beacons Fire-and-Forget sind, können Sie nicht auf die Server-Antwort zugreifen oder definitiv wissen, ob die Daten empfangen wurden. Dies ist beabsichtigt für optimale Performance.

Verwenden Sie die Beacon API, wenn Sie Daten während Seitenübergängen, Unload-Events oder wenn die Seite ausgeblendet wird senden müssen und keine Antwort benötigen. Verwenden Sie fetch für reguläre API-Aufrufe, bei denen Sie Antworten, Fehler handhaben müssen oder wenn das Timing nicht kritisch für die Seitennavigation ist.

Listen to your bugs 🧘, with OpenReplay

See how users use your app and resolve issues fast.
Loved by thousands of developers