- 0.4.2: Fix nonce_invalid refusals after a sign-in and on stale cached pages. A visitor who signs in on a page sends that page's logged-out nonce at pagehide, by which time the browser already holds the new login cookie, so the nonce failed against the new user. The collect route now falls back to accepting a logged-out nonce and dispatches the beacon as user 0, never as the user who just signed in. The script also refreshes the nonce at load when the page came from an old cache, instead of waiting until something is queued, so an error reported just before the tab hides no longer goes out with a stale nonce. The 30-minute check now calls the refresh through a wrapper so no timer argument can force it.
- 0.4.1: Stop LiteSpeed caching the nonce route. LiteSpeed's REST cache was serving one stored response from /lh-beacon/v1/nonce to every logged-out visitor despite the no-cache headers, so the script's refresh brought back a nonce that was itself stale and beacons from long-lived cached pages were refused as nonce_invalid. The route now opts out through LiteSpeed Cache's litespeed_control_set_nocache action and the X-LiteSpeed-Cache-Control: no-cache response header.
- 0.4.0: Beacons from pages that stay open for hours, or are served from the page cache, no longer fail with an expired nonce. The beacon script now fetches a fresh nonce from a new GET route, lh-beacon/v1/nonce, once the page's nonce is more than a quarter of the nonce lifetime old (6 hours by default, filterable with lh_beacon_return_nonce_refresh_after). It checks when a plugin queues a beacon, when the tab becomes visible again, and every 30 minutes while it stays open, and only on pages that have something queued. The page settings now carry the nonce's issue time so a cached page knows how old its nonce is. The nonce route answers only same-origin requests, shares the beacon rate limit, is never cached, and creates the nonce for the visitor its login cookie identifies, exactly as beacons are checked. Beacons still always require a valid nonce.
- 0.3.1: Refused beacons are now written to the debug log, so a missing or expired nonce shows up there like other nonce failures. Until now a refusal was a silent 403: LH WP Die Logger only reports nonce failures when wp_die() runs, which a REST refusal never does, and WordPress does not even announce a missing nonce. Each refusal is logged as a Warning tagged [lh_beacon] in the standard LH format: event beacon_refused, a reason (too_large, origin, rate_limited, invalid_shape, nonce_missing or nonce_invalid), the site, the Origin and Referer headers and the body size. Nonce refusals add the user ID from the login cookie and the beacon keys, and rate-limit refusals add the IP address. Payloads and the nonce itself are never logged. Logging only happens when WP_DEBUG is on, and can be switched off with the lh_beacon_return_plugin_debugging_status filter.
- 0.3.0: Every beacon must now carry a valid nonce, for logged-out visitors as well as logged-in ones. LH Beacon prints a nonce into the page with its settings and sends it in the request body. The collect route verifies it against the visitor the login cookie identifies (user 0 when logged out) and refuses the request with a 403 (lh_beacon_invalid_nonce) when it is missing or invalid; nothing is dispatched. The nonce goes in the body rather than the X-WP-Nonce header so that a stale one is refused by LH Beacon with its own error, not by the REST API's cookie check. This is defence in depth on top of the existing same-origin, size and rate checks: a beacon now has to come from a page this site served to that visitor within the nonce's lifetime. That lifetime is 12 to 24 hours, so pages must not be served from cache for longer than 12 hours: on LocalHero the LiteSpeed public cache TTL was cut from 7 days to 12 hours alongside this release. A beacon from a page left open past its nonce's lifetime is refused, so a little long-tail data is lost. The lh_beacon_require_nonce filter can switch the check off in an emergency. The lh_beacon_get_user_id filter now runs after the nonce has been checked against the real cookie user, so anonymising the ID no longer affects verification.
- 0.2.0: LH Beacon now tells consumers who sent a beacon. When the visitor is logged in, their user ID is passed as a new last argument to both the lh_beacon_received and lh_beacon_received_{key} actions, so existing listeners keep working unchanged; it is 0 for logged-out visitors. During dispatch it is also available from LH_Beacon_plugin::return_current_user_id(). The visitor is identified from their logged_in cookie rather than a REST nonce, because a page served from cache cannot carry a valid nonce and a stale one would make the REST API refuse the whole request. The cookie is only read for requests that have already passed the same-origin check. The ID is an identity only: LH Beacon does not switch the current user, so consumers do not gain that user's capabilities. A new lh_beacon_get_user_id filter can change or anonymise the ID (return 0).
- 0.1.0: First release. Plugins queue payloads in the browser with lhBeacon.set( key, payload ), and LH Beacon sends everything queued in one sendBeacon request (fetch keepalive fallback) when the page is hidden or closed, once per hide. On the server the lh-beacon/v1/collect route checks only the request envelope (same origin, at most 8192 bytes, at most 300 requests per IP per minute, all filterable) and passes each payload unread to the lh_beacon_received and lh_beacon_received_{key} actions, so every consumer validates and stores its own data. The script is registered but never enqueued on its own: it loads only where a plugin's script depends on lh-beacon.