Skip to content
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

[NASAA-205] - Send top stories experiment analytics events #12075

Open
wants to merge 42 commits into
base: latest
Choose a base branch
from

Conversation

hotinglok
Copy link
Collaborator

@hotinglok hotinglok commented Oct 21, 2024

Resolves NASAA-205

Overall changes

Adds an <amp-analytics/> component that is added to the page in <AmpExperiment/> if an analyticsConfig is passed in specifically to handle tracking of experiment events. This is in the same format as the config used for tracking page views in ampAnalyticsJson.ts and is used to track view and click events of the experiment Top Stories section that are viewable in Piano. This PR also includes minor refactors to the experimentTopStories helpers file, as well as the existing <ATIAnalytics/> component that allows the amp experiment variant to come through on the page view event too.

Code changes

  • Adds an optional <amp-analytics/> component to <AmpExperiment/> if an analyticsConfig is passed to the component.
  • Created analytics config for the top stories experiment.
    • This uses buildATIEventTrackUrl() to format events ready to send to Piano via <amp-analytics/>.
      • Exposes the variant prop that exists in getEventInfo() to use the existing 'Onsite Ads - Variant' metric in Piano (renamed as experimentVariant to avoid it being confused with service variants. These events are registered as publisher.click and publisher.display events which is used to represent component view/click events.
  • Adds data-experiment attribute to both <TopStoriesSection/> components rendered in the article body and the secondary column. This makes it easier to make selectors in the amp-analytics to trigger tracking events for <TopStoriesSection/>.
    • This was also done to account for certain cases where events weren't sending because the selector in the config only targets the first element it finds. So the view event for the <TopStoriesSection/> in the secondary column won't send if the selector was only something like section[aria-labelledby='top-stories-heading'].
    • As experimentTopStories blocks are always added to the data on valid assets/services, view events for the control variant which only ever shows the <TopStoriesSection/.> in it's original position in the secondary column didn't send view events at all, hence the need for separate tracking of each one.
  • Added ampExperimentName to atiData that is added conditionally (only when shouldEnableTopStoriesExperiment is true).
    • The active variant name is retrieved by AMP via their Variable Substitution using the experiment name. This is added to the page view event to track when people are still not interacting with or seeing the top stories, even if they are being shown higher up.
    • Updated relevant buildATIURL functions/types/tests to include ampExperimentName when it exists.
    • Other MVT properties are also added to the page view event (MVT Test, MVT Experiment ID, and MVT Variant).
  • Refactored block insertion logic.
    • Updates the halfway point of inserting the experimentTopStories block to account for blocks in the data that are never rendered (mpu and wsoj). It doesn't need to be exactly 50% of the way through, this approximation will suffice for this experiment since it will only ever be off by one position at worst.
  • Refactored shouldEnableTopStoriesExperiment conditions.
    • Added a minimum blocks length requirement to account for shorter articles that lead to the Top Stories section showing above most of the content.
  • Added more assets to test with.

Testing

Links

Piano dashboard with filter showing relevant columns

Control (no changes to existing behaviour):

Variant name in code: control

Variant 1 (show Top Stories section halfway into the article content instead of after it):

Variant name in code: show_at_halfway

Events

Ensure the following events for both variants on a valid articles are being sent through in the ATI tag inspector and are visible in the Piano dashboards.

On page view (type 'page' event in Tag Inspector, 'page.display' in Piano dashboard)

  • All existing properties in the 'Custom Variables' section should remain the same (see example below):
image
  • There should be an 'Other' section with the following properties:
Key Value
mv_test* Google Discover
mv_experiment_id (Experiment name) topStoriesExperiment
mv_creation (Variant) control

*mv_test is convenient to make relevant results show in the 'Content - MV Testing' section in Piano, so this just has the value 'Google Discover' to make it easier to find.

  • There should not be a detailed placement id (tag inspector)/ detailedPosition (piano dashboard) property for the page view event.

When viewing the Top Stories section (type 'onSiteAds' event in Tag Inspector, 'publisher.display' in Piano dashboard):

  • An event with an 'onSiteAds' section should appear with the following properties alongside the mv_ events in the 'Other' section above:
image

When clicking on any promo in the Top Stories section (promo position irrelevant, type 'onSiteAds' event in Tag Inspector, 'publisher.click' in Piano dashboard):

  • An event with an 'onSiteAds' section should appear with the following properties alongside the mv_ events in the 'Other' section above:
image

Helpful Links

Add Links to useful resources related to this PR if applicable.

Coding Standards

Repository use guidelines

Comment on lines +7 to +10
jest.mock('../../../lib/analyticsUtils', () => ({
...jest.requireActual('../../../lib/analyticsUtils'),
getAtUserId: jest.fn().mockReturnValue('123-456-789'),
}));
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This block is needed because getAtUserId() always generates a random ID.

@hotinglok hotinglok marked this pull request as ready for review October 28, 2024 12:16
Comment on lines 22 to 23
requests: Record<string, unknown>;
triggers: Record<string, unknown>;
Copy link
Contributor

Choose a reason for hiding this comment

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

Question (non-blocking) Can this be typed any more strictly? I can see that we set base, clicks, trackClicks which we could encode here too.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I've updated this a bit with just the things that we've used for the experiment. There's a lot of other optional properties that I've not included, but those can be added whenever they're needed.

@@ -252,6 +263,7 @@ export const buildATIEventTrackUrl = ({
advertiserID,
url,
detailedPlacement,
variant,
Copy link
Contributor

Choose a reason for hiding this comment

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

Confusingly, we use the term variant for services with dual scripts e.g. serbian with cyrillic script has a variant = cyr

If this is not the intention of the term variant here, can we please rename it to something else, to avoid confusion - perhaps experimentVariant or something similar?

Copy link
Contributor

Choose a reason for hiding this comment

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

I saw this as well, but had a look at the utility and apparently it was set for A/B testing 3 years ago

variant = '', // not a service variant - used for A/B testing

Copy link
Collaborator Author

@hotinglok hotinglok Oct 29, 2024

Choose a reason for hiding this comment

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

We've added this here to use as the experiment variant in our use-case because getEventInfo() uses this as a variant for A/B testing, it just wasn't previously passed in here.
As the value just needs to be in the right place in the string, I'll rename it in there too and remove the comment to make it clearer

@@ -49,6 +50,7 @@ export const buildPageATIParams = ({
statsDestination,
timePublished,
timeUpdated,
...(ampExperimentName && { ampExperimentName }),
Copy link
Contributor

Choose a reason for hiding this comment

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

nitpick: Is spreading needed here? If ampExperimentName is undefined, it won't be returned?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

If I left it as is in the object, the key ampExperimentName would still be there even if the value was falsey. As it is currently written, it won't work without the spread operator because it wouldn't have a valid key/pair if it evaluated as false.

@@ -109,6 +110,7 @@ export interface ATIEventTrackingProps {
advertiserID?: string;
url?: string;
detailedPlacement?: string;
variant?: string;
Copy link
Contributor

Choose a reason for hiding this comment

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

As per comment above - is this an experiment variant or a dual script variant?

Copy link
Member

@michellebbc michellebbc left a comment

Choose a reason for hiding this comment

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

I am not seeing the additional variant data you've added to the page.display event appearing in the analytics portal. I suspect they can only go on publisher.* type events?

variants: {
control: 50,
show_at_halfway: 50,
},
},
};

const ARTICLE_LENGTH_THRESHOLD = 10;
const enableExperimentTopStories = ({
Copy link
Member

Choose a reason for hiding this comment

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

Non-blocking suggestion, expecially as it isn't new to this PR: From reading this function name I was expecting it to do some kind of enablement rather than returning a boolean decision.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good point. I think I was just struggling for a name since shouldEnableExperimentTopStories is returned in the object from 'getExperimentTopStories()`. Happy to accept any other suggestions.

const shouldEnableExperimentTopStories = enableExperimentTopStories({

Copy link
Member

@michellebbc michellebbc left a comment

Choose a reason for hiding this comment

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

Good spot with the MVT properties. I've had a quick check in Piano and can see the data 😄

Copy link
Contributor

@karinathomasbbc karinathomasbbc left a comment

Choose a reason for hiding this comment

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

Thanks for sorting the variant vs experimentVariant issue - it's a lot clearer now.

@@ -215,6 +216,31 @@ export const buildATIPageTrackPath = ({
value: getATIMarketingString(href, campaignType),
wrap: false,
},
...(ampExperimentName
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

After fixing conflicts, there was an initial concern that this might be overridden by the elections banner experiment that is currently being done, but as that is only run on mundo/portuguese, this should be ok because experimentVariant won't be defined.

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.

6 participants