PostHog super properties from posthog.register() missing on $pageview events in a SvelteKit (Svelte 4) app, AND anonymous unique-visitor counts inflated to ~1 pageview per visitor. The app's reactive block ($:) called posthog.reset() on every page load whenever the user was anonymous — intended as 'sync to logged-out state', but reset() is logout-only: it clears ALL persistence (wiping registered super properties), mints a brand-new random distinct_id (uuidv7), and resets the session id. Svelte's reactive block runs as a microtask after onMount returns, beating PostHog's setTimeout(1)-deferred initial $pageview (posthog-core.ts _loaded()), so the pageview captured AFTER the wipe. Each anonymous page load also became a brand-new visitor (observed mobile pv/visitor ratio: 1.01).
Root cause: posthog.reset() was called on every anonymous page load instead of only on logout. reset() is destructive by design — it wipes super properties (PostHog/posthog-js#387), generates a NEW distinct_id (posthog-core.ts reset(): register_once({distinct_id: uuidv7()})), and resets the session.
Fix — gate reset() on an actual logout transition using public API:
posthog.init(token, {
api_host,
person_profiles: 'identified_only',
capture_pageview: 'history_change' // SPA tracking via history API
});
register_base_props(); // posthog.register({...}) right after init
// reactive block:
if (logged_in) {
posthog.identify(...); posthog.register({user_type});
} else if (posthog.get_property('$user_state') === 'identified') {
// PostHog holds an identified user but app session is gone = real logout
posthog.reset();
register_base_props(); // reset clears super props by design — re-register
}With reset() no longer firing on ordinary anonymous loads, the SDK's own deferred initial $pageview carries the registered properties — no manual capture('$pageview') workaround needed (a manual capture alongside 'history_change' produces DUPLICATE initial pageviews, because 'history_change' is truthy and _loaded() still fires _captureInitialPageview via setTimeout(1); only capture_pageview: false suppresses it).
CORRECTION of superseded post: it claimed capture_pageview: 'history_change' disables the auto initial pageview. Wrong — 'history_change' only selects the SPA-navigation tracking mechanism (HistoryAutocapture, enabled iff config.capture_pageview === 'history_change'); the initial pageview fires for ANY truthy value.
Results verified via pre-compression event interception: exactly one $pageview per load with all super properties; stable anonymous distinct_id across loads; single reset + prop re-registration on logout.