Skip to content

RT-1064: Implement tracking metrics for personalizations#24

Merged
alaviss merged 3 commits into
mainfrom
hieu/nvpyprkzwtwn
Jun 25, 2026
Merged

RT-1064: Implement tracking metrics for personalizations#24
alaviss merged 3 commits into
mainfrom
hieu/nvpyprkzwtwn

Conversation

@alaviss

@alaviss alaviss commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

Summary

After applying personalizations on to a page, we will send events to record their application as impressions and record all clicks within the replaced elements.

Details

All events are recorded into td_c360_personalization.events. We are hardcoding the database to simplify querying in the console in the future.

On application, we are now:

  • Dispatch a record for impression.
  • Adding data-td-personalization-{campaign,creative} to the host element.
  • Install an event handler to capture clicks and dispatch a record.

All records to the events table contains:

  • Basic tracking values (page, id, user, etc.): Sensitive identifiers are automatically pruned by the SDK if it is configured to anonymize the data.
  • The event: impression or click.
  • Campaign and creative ID.

Comment thread src/treasure.ts
options?: AddRecordOptions
) => {
return this._sdk.addRecord(table, record, success, error)
return this._sdk.addRecord(table, record, success, error, options)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, this means that customers can choose a different db for emitting events. Let's see what Integrations says.

expect(spy).not.toHaveBeenCalled()
})

it('does not report an unattributable spot even when it injects', () => {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this unattributable because it's missing campaign and creative ids? IMO, we should still emit these because:

  1. they reflect a bug in campaign launch logic.
  2. neither us nor customers will have visibility into unattributable offers
  3. if a user sees a personalization, it is an impression irrespective of whether it's attributable to a campaign or creative.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we don't have the IDs... we can't link the data to any campaign or creatives.

This is mostly to protect against the fact we don't encode this for existing campaigns yet.

Comment on lines +606 to +630
it('leaves impression null when the offer has no campaign', () => {
const payload: PersonalizationPayload = {
offers: {
w: {
attributes: {
'td_personalization.audience_rank': '1',
'td_personalization.content': p13n([
{
id: 'cr-1',
css_selector: '#ok',
html_value: '<p>x</p>',
css_value: '',
},
]),
},
},
},
}
expect(decodeOffers(payload, 1000)[0]?.impression).toBeNull()
})

it('leaves impression null when the entry has no id', () => {
const payload: PersonalizationPayload = {
offers: {
w: {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand the reasoning behind nulling offers without creative or campaign id. But I wonder what would lead to this. If there is a bug in our logic that results in empty creative or campaign id, would we want to lose the metrics emitted while we fix and deploy the bug?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Backwards compatibility, for the most part.

alaviss added 2 commits June 24, 2026 10:31
This is done by installing a handler on the shadow roots we installed,
and tagging them with data attributes to record their campaign and
creative IDs.

Assisted-by: Claude Opus 4.8
@alaviss alaviss force-pushed the hieu/nvpyprkzwtwn branch from 243508d to 136b49b Compare June 24, 2026 17:31
@alaviss alaviss changed the base branch from p13n to main June 24, 2026 17:32
Comment thread src/plugins/record.ts

export interface AddRecordOptions {
/** Defaults to the SDK's configured database when omitted. */
database?: string

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it a requirement to have another database configured besides the one that is in the default config? Can we just use the one in the default config?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is. We are looking to store all metrics in a known database to simplify report generation by Personalization Studio and AI Studio in the future.

@imnutz imnutz self-requested a review June 25, 2026 03:54

@imnutz imnutz left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM


const PERSONALIZATION_DATABASE = 'td_c360_personalization'
const PERSONALIZATION_TABLE = 'events'
const CLICKABLE_SELECTOR = 'a, button, [role="button"], [role="link"]'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: ideally the clickable selector should be something like td-personalization-clickable but it's fine for now since you're scope the trackClicks event listener to the spot.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do that once the editor can generate those 😆

@alaviss alaviss merged commit 43f8367 into main Jun 25, 2026
8 checks passed
@alaviss alaviss deleted the hieu/nvpyprkzwtwn branch June 25, 2026 20:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants