Signatur
Beschreibung
navigator.sendBeacon() ist für Analyse-, Diagnose- und Protokolldaten gedacht, die der Browser noch nach dem Verlassen der Seite zuverlässig verschicken soll. Der Browser stellt die Anfrage in eine Warteschlange und sendet sie im Hintergrund. So werden weder das Entladen der Seite noch die Navigation zur nächsten Seite ausgebremst. Die Methode gibt sofort zurück und liefert nur einen Wahrheitswert: true, wenn die Daten zum Senden angenommen wurden.
Früher griff man für solche Aufgaben zu synchronen XMLHttpRequest-Aufrufen in unload-Handlern oder zu Tricks wie Zählpixeln. Das hat die Navigation spürbar verzögert. sendBeacon() ersetzt diese Muster. Heute gilt ein Aufruf im Ereignis visibilitychange (wenn document.visibilityState === "hidden") oder in pagehide als beste Praxis. Beide Ereignisse werden auf Mobilgeräten deutlich zuverlässiger ausgelöst als unload oder beforeunload.
Die Anfrage ist immer ein POST. Die Antwort des Servers lässt sich nicht auslesen, und es gibt keine Rückruffunktion und kein Promise. Welchen Content-Type die Anfrage bekommt, hängt vom Datentyp ab: Ein String wird als text/plain;charset=UTF-8 gesendet, FormData als multipart/form-data, URLSearchParams als application/x-www-form-urlencoded. Bei einem Blob gilt dessen type.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $url Pflicht | string | URL | Ziel-URL, an die die Daten gesendet werden. Relative URLs werden relativ zur Dokument-URL aufgelöst. | |
| $data | string | ArrayBuffer | TypedArray | DataView | Blob | FormData | URLSearchParams | null | null | Die zu sendenden Daten (Anfragekörper). Aus dem Typ ergibt sich der Content-Type der Anfrage. Ohne Angabe wird ein leerer POST gesendet. |
Rückgabewert
true, wenn der Browser die Daten erfolgreich in die Sende-Warteschlange aufgenommen hat, sonst false (z. B. weil das Größenlimit überschritten ist). Ob der Server die Daten tatsächlich erhalten hat, sagt der Wert nicht.Beispiele
Analysedaten beim Verlassen der Seite senden
const sessionStart = performance.now();
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
const payload = JSON.stringify({
page: location.pathname,
durationMs: Math.round(performance.now() - sessionStart),
});
// Blob mit passendem Typ, damit der Server JSON erkennt
const blob = new Blob([payload], { type: 'application/json' });
const queued = navigator.sendBeacon('/api/analytics', blob);
console.log('Beacon eingereiht:', queued);
}
});
Formulardaten ohne Preflight senden
const params = new URLSearchParams({
event: 'checkout_abandoned',
cartId: 'A-1042',
});
// application/x-www-form-urlencoded ist CORS-sicher, daher kein Preflight
const ok = navigator.sendBeacon('https://stats.example.com/collect', params);
console.log(ok);
Fallback auf fetch mit keepalive
const sendLog = (url, data) => {
const body = JSON.stringify(data);
if (navigator.sendBeacon && navigator.sendBeacon(url, body)) {
return true;
}
// Fallback, z. B. wenn die Daten zu groß sind oder die API fehlt
fetch(url, {
method: 'POST',
body,
keepalive: true,
headers: { 'Content-Type': 'text/plain' },
}).catch(() => {});
return false;
};
window.addEventListener('pagehide', () => {
sendLog('/api/log', { type: 'pagehide', ts: Date.now() });
});
Fehler melden (Error-Reporting)
window.addEventListener('error', (event) => {
const fd = new FormData();
fd.append('message', event.message);
fd.append('source', `${event.filename}:${event.lineno}`);
navigator.sendBeacon('/api/errors', fd);
});
// Wichtig · Fallstricke
- Größenlimit: Pro Seite dürfen alle noch ausstehenden Beacons zusammen nur eine begrenzte Datenmenge haben, meist rund 64 KiB (dasselbe Kontingent wie bei
fetch(..., { keepalive: true })). Ist das Limit überschritten, gibt die Methodefalsezurück. Den Rückgabewert solltet ihr deshalb prüfen und bei Bedarf auf eine Alternative ausweichen. - Keine Antwort: Weder Statuscode noch Antworttext sind zugänglich. Wenn ihr eine Rückmeldung vom Server braucht, nehmt
fetch(). - CORS: Ein
Blobmit dem Typapplication/jsonist kein „einfacher“ Anfragetyp. Bei Zielen auf einer anderen Herkunft (Cross-Origin) löst er einen CORS-Preflight aus, und manche Browser (vor allem ältere Chrome-Versionen) lehnen das ab. Für Cross-Origin-Ziele sindtext/plain,URLSearchParamsoderFormDatasicherer. Beacons senden Cookies mit, und der Server muss bei Cross-Origin passende CORS-Header setzen. - Richtiges Ereignis wählen:
unloadundbeforeunloadwerden besonders auf Mobilgeräten oft gar nicht ausgelöst, undunloadkann den Back/Forward-Cache verhindern. Verwendet stattdessenvisibilitychangeoderpagehide. - CSP: Das Ziel muss durch die
connect-src-Direktive der Content Security Policy erlaubt sein. - Werbe- und Tracking-Blocker blockieren Beacon-Anfragen häufig. Verlasst euch für geschäftskritische Daten also nicht allein darauf.
- Die Methode muss auf
navigatoraufgerufen werden. Wer sie herauslöst (const b = navigator.sendBeacon; b(url)), bekommt einenTypeErrorwegen „Illegal invocation“.