feat: capture page views and surface as page_events in selectPlacements - #109
feat: capture page views and surface as page_events in selectPlacements#109alexs-mparticle wants to merge 14 commits into
Conversation
…eventAttributes per page view
…ents Derive a flat page_events array from stored page views at selectPlacements time. Each view's eventAttributes are exploded into attr_-namespaced keys; the title attribute is surfaced as page_name and EventName as event_name. The raw nested mpPageViews store is stripped so only the flattened copy is sent. Relax returnLocalSessionAttributes to no longer require a placement mapping. Restore the isKitReady guard in process() and remove debug logging.
Compute a timeOnPage field for each page_events entry at read time in buildPageEvents as the diff of consecutive activeTimeOnSite values — the active time a page was viewed before the next page view was logged. Emitted only when it is a genuine, non-negative number; omitted for the still-open last entry, negative diffs (clock skew, reset, out-of-order), and non-numeric activeTimeOnSite. Nothing new is persisted; StoredPageView is unchanged.
…iews # Conflicts: # dist/Rokt-Kit.common.js # dist/Rokt-Kit.common.js.map # dist/Rokt-Kit.esm.js.map # dist/Rokt-Kit.iife.js # dist/Rokt-Kit.iife.js.map
Add an explicit PageEvent return type for buildPageEvents (with timeOnPage optional) instead of Record<string, unknown>[]. Revert the legacy #processEvent attribute-mapping tests back to MessageType.PageView and strip the captured mpPageViews list from their exact-shape assertions via a helper, since processing a PageView now legitimately captures a page-view record.
| // raw nested mpPageViews so Rokt receives only the flattened copy. | ||
| const rawPageViews = localSessionAttributes[PAGE_VIEWS_KEY]; | ||
| const pageEvents = Array.isArray(rawPageViews) ? this.buildPageEvents(rawPageViews as StoredPageView[]) : []; | ||
| delete localSessionAttributes[PAGE_VIEWS_KEY]; |
There was a problem hiding this comment.
We should not be mutating this.
| } | ||
|
|
||
| private buildPageEvents(pageViews: StoredPageView[]): PageEvent[] { | ||
| return pageViews.map((pv, i) => { |
There was a problem hiding this comment.
Nit: Use pageview and index, rather than abbreviations.
…st test asserts - Split mpPageViews off the session attributes via destructuring instead of delete, so the store returned by getLocalSessionAttributes is not mutated. - Rename buildPageEvents map params pv/i to pageView/index. - Drop the mappedSessionAttributes masking helper; the attribute-mapping tests now assert only their own mapped keys directly and leave mpPageViews to the page-view capture tests.
|
|
||
| mp().Rokt.setLocalSessionAttribute?.(PAGE_VIEWS_KEY, pageViews); | ||
| } catch (err) { | ||
| console.error('Rokt Kit: Failed to capture page view', err); |
There was a problem hiding this comment.
Instead of console.erroring, we should increase observability by sending to data dog
There was a problem hiding this comment.
or, in addition to i should say
| const filteredUserIdentities = this.returnUserIdentities(filteredUser); | ||
|
|
||
| const localSessionAttributes = this.returnLocalSessionAttributes(); | ||
| const { [PAGE_VIEWS_KEY]: rawPageViews, ...sessionAttributes } = this.returnLocalSessionAttributes(); |
There was a problem hiding this comment.
I was conflating PAGE_VIEWS_KEY and PAGE_EVENTS_KEY. Maybe LS_Page_VIEWS_KEY is more clear to stated it's the key for the persistence?
| const flat: PageEvent = { | ||
| event_name: pageView.event_name, | ||
| pageUrl: pageView.pageUrl, | ||
| sourceMessageId: pageView.sourceMessageId, | ||
| timestamp: pageView.timestamp, | ||
| activeTimeOnSite: pageView.activeTimeOnSite, |
There was a problem hiding this comment.
nit: Any reason we are doing 2 transforms? Saving to LS as a PageView, where we do some mapping, then turning a PageView into a PageEvent. Could we just save it as a PageEvent to reduce the number of schemas to keep track of?
| pageViews.shift(); | ||
| } | ||
|
|
||
| mp().Rokt.setLocalSessionAttribute?.(PAGE_VIEWS_KEY, pageViews); |
There was a problem hiding this comment.
setLocalSessionAttribute only accepts primitive AttributeValues (string | number | boolean | null | undefined) — same as every existing LSA usage (boolean flags). Passing an array of objects here works at runtime only because the setter doesn't validate, but it violates the core SDK contract.
Prefer JSON.stringify on write and JSON.parse on read so the stored value stays a string.
| flat[`${PAGE_EVENT_ATTR_PREFIX}${key}`] = value; | ||
| } | ||
| } | ||
| flat.page_name = pageView.eventAttributes?.[PAGE_TITLE_ATTRIBUTE]; |
There was a problem hiding this comment.
you can remove the ? in eventAttributes? here by moving this up one line to be embedded in the if clause directly above
Summary
Records page-view events as they are logged, persists them durably to the Rokt local-session-attribute store, and surfaces them as a flat
page_eventsarray on the nextselectPlacementscall as targeting context.What's included
process): page views (EventDataType === 3) are appended to a persistedmpPageViewslist (max 25, oldest evicted), guarded so a malformed event can never throw out of the forwarder. CapturesEventName, fullpageUrl(window.location.href),SourceMessageId,timestamp,ActiveTimeOnSite, andEventAttributes.buildPageEvents): each stored view is flattened into apage_eventsentry —event_name,page_name(from thetitleattribute), andeventAttributesexploded intoattr_-namespaced keys so they can't clobber base fields. The raw nestedmpPageViewsstore is stripped so only the flat copy is sent.timeOnPage— the active time a page was viewed before the next page view was logged (diff of consecutiveactiveTimeOnSite). Emitted only when it's a genuine non-negative number; omitted for the still-open last entry, negative diffs, and non-numeric values. Derived at read time — nothing extra persisted.returnLocalSessionAttributes()so the store flows through whenever it's available and populated.Testing
mParticle.getInstance()._Store.getLocalSessionAttributes()in the dev console.Expected result:
Verify the expected payload when making a select placements call: