-
Notifications
You must be signed in to change notification settings - Fork 12
feat: add exit_intent trigger #246
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: web/page-triggers-1
Are you sure you want to change the base?
Conversation
Add exit_intent trigger and publish
|
|
|
||
| // Install listener after minimum time requirement | ||
| if (minTimeOnPageMs > 0) { | ||
| setTimeout(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
setupExitIntentPublisher leaks state: re-init can leave a stale setTimeout, add duplicate mouseout handlers, and allow exit_intent to fire multiple times. Suggest making it one-shot by tracking a single handler and timeout on the instance, clearing/removing them on re-init and after first publish, and nulling refs to prevent duplicates.
🚀 Reply to ask Macroscope to explain or update this suggestion.
👍 Helpful? React to give us feedback.
|
📝 Documentation updates detected! Updated existing suggestion: Document new page trigger types for Web Experiment |
|
|
||
| private setupExitIntentPublisher = () => { | ||
| // Check if any page objects use exit_intent trigger | ||
| const hasExitIntentTriggers = Object.values(this.pageObjects).some( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not familiar with the flow but does this pageObjects already filter only the active page objects?
nit: if you're using pages multiple times, you could assign it at the top first:
const pages = Object.values(this.pageObjects).flatMap((pages) => Object.values(pages));There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pageObjects here is static, so it includes all page objects for all experiments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tyiuhc so then should all these functions be checking isPageObjectActive?
| minTimeOnPageMs = | ||
| minTimeOnPageMs === 0 | ||
| ? triggerValue.minTimeOnPageMs | ||
| : Math.min(minTimeOnPageMs, triggerValue.minTimeOnPageMs); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it looks like you can shorten this to minTimeOnPageMs = Math.min(minTimeOnPageMs, triggerValue.minTimeOnPageMs)
| // Install listener after minimum time requirement | ||
| if (minTimeOnPageMs > 0) { | ||
| setTimeout(() => { | ||
| this.globalScope.document.addEventListener('mouseout', handleMouseOut); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you definitely want mouseleave since mouseout fires on any descendant
|
|
||
| // Install listener after minimum time requirement | ||
| if (minTimeOnPageMs > 0) { | ||
| setTimeout(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These timeouts also need to be cancelled when user navigates to another page etc. It looks like you can already use addPageChangeSubscriber() for this or we could use a pattern of returning and/or collecting cleanup functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noted - I will add this in a follow up PR so we can centralize cleanup logic across all triggers
| let minTimeOnPageMs = 0; | ||
| for (const page of pages) { | ||
| const triggerValue = page.trigger_value as ExitIntentTriggerValue; | ||
| minTimeOnPageMs = Math.min( | ||
| minTimeOnPageMs, | ||
| triggerValue.minTimeOnPageMs ?? 0, | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minTimeOnPageMs always resolves to 0 because it starts at 0 and uses Math.min(...). Consider initializing to Infinity and defaulting to 0 if none are set so configured delays take effect.
- let minTimeOnPageMs = 0;
+ let minTimeOnPageMs = Infinity;
for (const page of pages) {
const triggerValue = page.trigger_value as ExitIntentTriggerValue;
minTimeOnPageMs = Math.min(
minTimeOnPageMs,
triggerValue.minTimeOnPageMs ?? 0,
);
}
+ if (minTimeOnPageMs === Infinity) { minTimeOnPageMs = 0; }🚀 Reply to ask Macroscope to explain or update this suggestion.
👍 Helpful? React to give us feedback.
Summary
Add
exit_intentpage trigger. This trigger will fire when the upward cursor movement near viewport top is detected, and the user has spent at leastminTimeOnPage(if specified).Checklist