Proactive Engagement Triggers for Shopify Chat: When to Greet, When Not To
Three behavior-based trigger conditions for chat widget rules — time on page, scroll depth, exit intent — and how to combine them with format and template overrides without making the widget annoying.
A chat widget has two modes. The first is opt-in: it sits in the corner, the visitor clicks if they want to engage, the widget stays out of the way until they do. The second is proactive: the widget initiates engagement based on visitor behavior — pops open after a dwell, shows a banner on exit intent, surfaces a greeting after the visitor has scrolled through the catalog.
Both modes have their place. Opt-in respects visitor autonomy. Proactive captures attention from visitors who wouldn't have engaged on their own. Done badly, proactive is annoying — the chat-window-jumping-out-at-you pattern that every B2B SaaS site abused in the 2010s. Done well, it catches a meaningful slice of intent that would otherwise bounce. v2.0.4 added three trigger conditions for the proactive side, composed with the existing conditional-rules system so merchants can be specific about when the widget speaks first.
Three behavior-based triggers
Each trigger has a single tunable parameter, no fancy state machine, and exits cleanly when the visitor leaves or the condition fires:
time_on_page— fires after a configurable number of seconds. Implementation is a singlesetTimeouton rule mount; cleared on unmount. Common use: "If the visitor has been on a product page for 30 seconds, open the widget with a product-specific greeting."scroll_depth— fires when the visitor has scrolled past a configurable percentage of the page. The handler computesscrollY / (scrollHeight - innerHeight)and listens for the threshold. Common use: "If they scroll past 60% of a collection page, surface a search bar so they can narrow down faster."exit_intent— fires when the mouse leaves the viewport through the top edge (clientY <= 0). The classic about-to-close-the-tab signal. Common use: "If they show exit intent on the cart page, open the widget with a prompt about checkout questions or hesitation reasons."
Each trigger fires at most once per page session — once the threshold is hit, the listener detaches. A visitor scrolling back up doesn't re-fire scroll_depth; a visitor whose mouse leaves the viewport twice doesn't get two proactive opens.
Composing with conditional rules
The triggers don't live alone. They're condition types within the existing conditional-rules system, which means they compose with the rest of the condition library (URL paths, devices, time-of-day, visit count, etc.) using AND logic.
Practical examples of composition:
- URL path + time on page — "On
/products/*ANDtime_on_page >= 30s, open the widget with a product-aware greeting." Doesn't fire on collection pages or the homepage; doesn't fire on product pages where the visitor bounced quickly. - Device + exit intent — "On desktop AND exit intent on
/cart, surface the smart-banner format with a checkout-question greeting." Mobile doesn't fire because mouseleave doesn't map cleanly to mobile behavior. - Visit count + scroll depth — "Returning visitor (visit_count > 1) AND scrolled past 50%, switch the widget to slideout format with a welcome-back greeting." First-time visitors stay on the default; returning visitors get the active treatment.
The composition isn't novel — every conditional-rules system uses AND logic — but pairing behavior triggers with the rest of the condition library is what makes the proactive mode targeted instead of universal.
Format and template overrides per matching visitor
Beyond visibility (show/hide), each rule can also override:
- Widget format — chat bubble, search bar, slideout panel, smart banner. The matching visitor sees the format the rule specifies, not the merchant's default format.
- Presentation template — greeting copy, quick-question pills, AI instructions. The rule can reference one of the templates from the v1.5.0 library and apply its full content as overrides for the duration of the matching visitor's session.
Combining triggers + overrides means a single rule can say: "On exit intent on the cart page, switch to smart-banner format AND swap in the cart-abandonment template." The visitor doesn't see the corner chat bubble — they see a banner with the merchant's cart-abandonment-flavored greeting, formatted appropriately for an attention-grabbing moment.
How to use these without being annoying
The proactive triggers are easy to overuse. Three rules of thumb that hold up:
- Pair with a URL constraint. Don't fire
time_on_pageon every page — fire it on the pages where staying long actually means hesitation (PDPs, cart). Homepage dwell is too noisy; trigger from there mostly catches users reading. - Use longer thresholds than feel right. 15 seconds feels short; in practice, 30-45 seconds catches actual hesitation without firing for casual browsers. Same for scroll_depth — 50-60% catches people who've seen most of the page; 30% fires before the visitor has had a chance to engage on their own.
- Layer with visit_count or local_storage. If a visitor has already opened the chat once on this device, they don't need a proactive open on the next visit. Add a condition like
local_storage milly_chat_opened != trueorvisit_count == 1to scope proactive behavior to first-time engagement only.
Done with that discipline, proactive triggers are a small addition to the rules system but a meaningful one — the widget gets an active mode without abandoning its opt-in default everywhere else.