fix(surveys): hold captures until the survey event receiver is hooked
trial_urgency_banner_viewed fires ~1s into the page load and raced the lazy surveys extension — events captured before its hook exists can never activate an event-triggered survey (affects real users, not just e2e). capture() now awaits surveysReceiverReady() (onSurveysLoaded, 3s safety timeout) and runs the eligibility check after the event has gone through. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
// PostHog — lazily loaded so it doesn't land in the initial bundle.
|
||||
// All exported functions are fire-and-forget; analytics loss on failure is acceptable.
|
||||
|
||||
import { resetSurveySession, scheduleSurveyCheck } from "./surveys";
|
||||
import { resetSurveySession, scheduleSurveyCheck, surveysReceiverReady } from "./surveys";
|
||||
|
||||
type PostHog = import("posthog-js").PostHog;
|
||||
|
||||
@@ -79,10 +79,13 @@ export function resetUser(): void {
|
||||
}
|
||||
|
||||
export function capture(event: string, properties?: Record<string, unknown>): void {
|
||||
load().then((ph) => ph.capture(event, properties));
|
||||
// Event-triggered surveys: posthog-js's event receiver sees the capture
|
||||
// above; the debounced check then asks for newly eligible surveys.
|
||||
scheduleSurveyCheck();
|
||||
// Hold captures until the surveys extension's event receiver is hooked (≤3s)
|
||||
// so event-triggered surveys never miss their trigger, then re-check
|
||||
// eligibility once the event has actually gone through.
|
||||
Promise.all([load(), surveysReceiverReady()]).then(([ph]) => {
|
||||
ph.capture(event, properties);
|
||||
scheduleSurveyCheck();
|
||||
});
|
||||
}
|
||||
|
||||
export function capturePageView(path: string): void {
|
||||
|
||||
@@ -149,6 +149,25 @@ function show(ph: PostHog, survey: Survey): void {
|
||||
notify();
|
||||
}
|
||||
|
||||
let _readyPromise: Promise<void> | null = null;
|
||||
|
||||
/** Resolves once posthog-js's surveys extension has installed its capture hook
|
||||
* (or after a 3s safety timeout). Events captured before that hook exists are
|
||||
* invisible to event-triggered surveys — the trial survey's
|
||||
* trial_urgency_banner_viewed fires ~1s into the page load and was racing the
|
||||
* extension's lazy <script>, so posthog.ts awaits this before every capture. */
|
||||
export function surveysReceiverReady(): Promise<void> {
|
||||
if (!ENABLED || typeof window === "undefined") return Promise.resolve();
|
||||
if (_readyPromise) return _readyPromise;
|
||||
_readyPromise = new Promise((resolve) => {
|
||||
setTimeout(resolve, 3000);
|
||||
loadPh()
|
||||
.then((ph) => ph.surveys?.onSurveysLoaded?.(() => resolve()))
|
||||
.catch(() => resolve());
|
||||
});
|
||||
return _readyPromise;
|
||||
}
|
||||
|
||||
/** Debounced eligibility check — called after captures, route changes and identify. */
|
||||
export function scheduleSurveyCheck(): void {
|
||||
if (!ENABLED || typeof window === "undefined") return;
|
||||
|
||||
Reference in New Issue
Block a user