@affiliateo/web 2.3.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/dist/provider.js +32 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -171,12 +171,12 @@ attributes become metadata (kebab-case → snake_case, up to 10 params).
|
|
|
171
171
|
</section>
|
|
172
172
|
```
|
|
173
173
|
|
|
174
|
-
Fires
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
sections
|
|
178
|
-
|
|
179
|
-
|
|
174
|
+
Fires the first time any pixel of the section overlaps the viewport.
|
|
175
|
+
Maximum permissiveness — if the user scrolled enough to see even a sliver,
|
|
176
|
+
it counts. Earlier versions required 50% visibility, which was unreachable
|
|
177
|
+
for tall sections (a pricing page with comparison tables silently dropped
|
|
178
|
+
out of every funnel). Great for landing pages where you want to know
|
|
179
|
+
which sections convert.
|
|
180
180
|
|
|
181
181
|
### Goal naming rules
|
|
182
182
|
|
package/dist/provider.js
CHANGED
|
@@ -248,13 +248,33 @@ export function AffiliateoProvider({ campaignId, apiUrl, children, }) {
|
|
|
248
248
|
ended = true;
|
|
249
249
|
beacon({ type: 'session_end', campaign_id: campaignIdRef.current, visitor_id: vid, ref: ref || lsGet(LS_REF) || '' });
|
|
250
250
|
}
|
|
251
|
+
// Server-side session window. Matches STALE_VISITOR_MS in the
|
|
252
|
+
// tracking Durable Object — after this much idle time the server
|
|
253
|
+
// treats the visitor as a new session, rotates session_id, and
|
|
254
|
+
// expects a fresh pageview to anchor the new visit in
|
|
255
|
+
// campaign_events. Without that anchor, funnel steps starting on
|
|
256
|
+
// `page` matches (e.g. the homepage `/`) silently get skipped for
|
|
257
|
+
// visitors who keep a tab open and come back.
|
|
258
|
+
const SESSION_REFIRE_MS = 10 * 60 * 1000;
|
|
251
259
|
function onVisibilityChange() {
|
|
252
260
|
if (document.visibilityState === 'hidden') {
|
|
253
261
|
sendEnd();
|
|
254
262
|
}
|
|
255
263
|
else {
|
|
264
|
+
// Tab becomes visible again.
|
|
256
265
|
ended = false;
|
|
257
|
-
|
|
266
|
+
// If the SDK's last pageview was longer ago than the server's
|
|
267
|
+
// 10-min session window, the server has already rolled the
|
|
268
|
+
// visitor over to a new session_id. Refire pageview so the new
|
|
269
|
+
// session has a proper anchor — otherwise the next scroll /
|
|
270
|
+
// click / custom event arrives orphaned and the funnel overlay
|
|
271
|
+
// sees the visitor enter "mid-funnel" (e.g. on a scroll step)
|
|
272
|
+
// without ever passing through the page-step that should
|
|
273
|
+
// bracket the visit.
|
|
274
|
+
if (Date.now() - lastSendTime > SESSION_REFIRE_MS) {
|
|
275
|
+
sendPageview();
|
|
276
|
+
}
|
|
277
|
+
}
|
|
258
278
|
}
|
|
259
279
|
// Send pageview on mount
|
|
260
280
|
if (!sentRef.current) {
|
|
@@ -332,22 +352,16 @@ export function AffiliateoProvider({ campaignId, apiUrl, children, }) {
|
|
|
332
352
|
// path) and unobserve after the first fire so the same element can't
|
|
333
353
|
// double-count if the user scrolls back up.
|
|
334
354
|
//
|
|
335
|
-
//
|
|
336
|
-
//
|
|
337
|
-
//
|
|
338
|
-
//
|
|
339
|
-
//
|
|
340
|
-
//
|
|
341
|
-
//
|
|
342
|
-
//
|
|
343
|
-
// the
|
|
344
|
-
//
|
|
345
|
-
//
|
|
346
|
-
// rootMargin: trim the bottom 10% of the viewport from the trigger
|
|
347
|
-
// zone so a section creeping up from the very bottom of the screen
|
|
348
|
-
// doesn't fire instantly. The user has to scroll enough that the
|
|
349
|
-
// section is starting to settle into the main visible area, which
|
|
350
|
-
// matches a human's intuitive sense of "I've reached that section."
|
|
355
|
+
// No options object → IntersectionObserver defaults to
|
|
356
|
+
// { threshold: 0, rootMargin: '0px 0px 0px 0px' }, which fires the
|
|
357
|
+
// instant ANY pixel of the section overlaps the viewport. That's
|
|
358
|
+
// exactly the semantic merchants want for "did the visitor reach
|
|
359
|
+
// this section": if they scrolled enough to see even a sliver of
|
|
360
|
+
// it, count it. Earlier versions used { threshold: 0.5 }, which
|
|
361
|
+
// was unreachable for tall sections (a 1600px pricing section in
|
|
362
|
+
// an 800px viewport tops out at ~50% intersection ratio and never
|
|
363
|
+
// crossed the threshold) — funnel steps tied to those sections
|
|
364
|
+
// silently dropped from every merchant's conversion count.
|
|
351
365
|
const scrollFired = new WeakSet();
|
|
352
366
|
let scrollObserver = null;
|
|
353
367
|
let scrollMo = null;
|
|
@@ -364,7 +378,7 @@ export function AffiliateoProvider({ campaignId, apiUrl, children, }) {
|
|
|
364
378
|
track(goal);
|
|
365
379
|
scrollObserver?.unobserve(entry.target);
|
|
366
380
|
}
|
|
367
|
-
}
|
|
381
|
+
});
|
|
368
382
|
// Observe everything that exists at mount time.
|
|
369
383
|
document.querySelectorAll('[data-affiliateo-scroll]').forEach((el) => {
|
|
370
384
|
scrollObserver?.observe(el);
|