-
Notifications
You must be signed in to change notification settings - Fork 149
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
Chore/track analytics consent screen view and selection rates #2784 #2793
Chore/track analytics consent screen view and selection rates #2784 #2793
Conversation
5b99d43
to
fa75907
Compare
fa75907
to
44def92
Compare
44def92
to
8f9bada
Compare
8f9bada
to
7740433
Compare
7740433
to
bc6de31
Compare
be17456
to
5c5e373
Compare
5c5e373
to
03af30e
Compare
03af30e
to
de1da50
Compare
b2f120b
to
ccc82fa
Compare
fffb8fc
to
03de36e
Compare
03de36e
to
0547cf0
Compare
0547cf0
to
a0418c8
Compare
@markmhx issues with page views not being reported correctly are now fixed, feel free to try it out. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice approach Edu. Appreciate the time spent trying different solutions 👍🏼
The data is now showing up for me during testing in the Segment debugger 🙏 I did try loading another route ( Could we make this airtight in that this buy page view wouldn't get reported in this scenario in addition to the subsequent request-diagnostics one? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work @edu-stx! 👍
a0418c8
to
f14dcf5
Compare
@kyranjamie @markmhx the page views are being tracked by this line whenever the path changes, Even if a user goes to function AppRoutesAfterAnalyticsConsentAnswered() {
// All routes as they were, unchanged
}
function AppRoutes() {
if (!hasResponded) return <AllowDiagnosticsPage />
return <AppRoutesAfterAnalyticsConsentAnswered />
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great that you've changed the page tracking events, this is an improvement. Have a search for .page(
though, as in some places we still call this manually.
src/app/routes/app-routes.tsx
Outdated
export function AppRoutes() { | ||
const hasStateRehydrated = useHasStateRehydrated(); | ||
const hasResponded = useHasUserRespondedToAnalyticsConsent(); | ||
|
||
if (!hasStateRehydrated) return <LoadingSpinner />; | ||
|
||
if (!hasResponded) { | ||
return ( | ||
<Routes> | ||
<Route path={RouteUrls.RequestDiagnostics} element={<AllowDiagnosticsPage />} /> | ||
<Route path="*" element={<Navigate replace to={RouteUrls.RequestDiagnostics} />} /> | ||
</Routes> | ||
); | ||
} | ||
return <AppRoutesAfterAnalyticsConsentAnswered />; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happened to using the route guard?
If we do do it this way: Wouldn't it make more sense to flip it: creating a separate component for the RequestDiagnosticsPage, and leave the existing routes here?
if (!hasResponded) return <AppRoutesBeforeAnalyticsConsentAnswered />;
return <AllTheRoutesAsTheyWereBefore>...
The exception is the Request Diagnostics routes, so I'd make a component for that, not the rest of the entire app's routing.
More generally, if this pattern has advantages for this case, I'm okay with it. But for example, why don't we do the same for creating an account?
if (!hasCreatedAccount) {
return <Routes><OnlyRoutesForMakingAnAccount /><Routes/>
}
It's more common in my exp. to define all the routes statically, and implement route guards to prevent navigation to restricted pages, than it is conditionally creating a route config.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great that you've changed the page tracking events, this is an improvement. Have a search for .page( though, as in some places we still call this manually.
Thank you :) Do you mean in general in the codebase or as part of this PR? Code unrelated to this feature seems out of scope. This PR has a .page()
call for the analytics consent page, given the “catch all” routes’ .page()
seen below is not yet loaded when the consent screen loads.
What happened to using the route guard?
Using the route guard caused page views to still be picked up by the above before users answered the analytics consent. We would have ended up collecting any routes the users manually navigated to before they responded to the analytics consent, meaning we would not be making the data collection “airtight”, i.e. strictly contained to the analytics page & response prior to user acceptance.
If we do do it this way: Wouldn't it make more sense to flip it: creating a separate component for the RequestDiagnosticsPage, and leave the existing routes here?
This is the approach taken in an earlier commit, albeit rendering the elements directly. It seemed from an earlier discussion that we should not follow this pattern, and in any case it doesn’t work with the above catch all .page()
hook.
More generally, if this pattern has advantages for this case [...]
It not so much it having advantages, as it is fulfilling the objectives at hand,
- From the feature: strictly ensure only views and responses to consent are collected prior to acceptance
- From earlier feedback: keep as close to the existing patterns as possible
I’m sure there are better ways of doing this, although I can’t see how we’d go about it without, for example, refactoring how we collect page views to collect only what is expected. Incidentally, the current implementation will collect not just page views, but any random string the user types in the URL.
But for example, why don't we [...]
Seems that it’s a matter of convention: what conventions do we have and follow, and to what extent do the conventions we adopt allow us to implement the features we want? In this PR, I tried my best to follow existing conventions while implementing the feature 😇
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry if this wasn't clear.
useEffect(() => void analytics.page('view', `${pathname}`), [analytics, pathname]);
This effect improves the page tracking, but in some places page tracking is handled manually, which means this addition will double log page views. As this PR introduces this behaviour, I think it should be fixed before merging. Edit: Edu pointed out this is already in dev
Example 1. Example 2. All that's required is removing these page tracking events.
The other point was just a small one on component organisation, rather than anything relating to a previous conversation.
As a developer, when I come to <AppRoutes />
I expect to see the app's routes. But now, the main responsibility of the component is handling the edge case regarding the request diagnostics page. It makes more sense to create an abstraction around the edge case, and move that to its own component, rather than the entire app's routes. Here's a clearer example:
function AppRoutesBeforeUserHasConsented() {
return (
<Routes>
<Route path={RouteUrls.RequestDiagnostics} element={<AllowDiagnosticsPage />} />
<Route path="*" element={<Navigate replace to={RouteUrls.RequestDiagnostics} />} />
</Routes>
);
}
export function AppRoutes() {
const hasStateRehydrated = useHasStateRehydrated();
const hasResponded = useHasUserRespondedToAnalyticsConsent();
if (!hasStateRehydrated) return <LoadingSpinner />;
if (!hasResponded) {
return <AppRoutesBeforeUserHasConsented />
}
return <AllTheAppsRoutesAsComponentNameSuggests />;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I'll re-arrange app routes
f14dcf5
to
f7142ed
Compare
Segment is always on. Segment can only be turned on, it can’t be turned off once it’s turned on. Therefore, in order to be able to capture the analytics acceptance rate (and then nothing else should the user opt out of analytics), Segment needs to be turned on as soon as the app loads. The user’s consent response is respected by modifying the behavior of the methods we use to interact with Segment: if the user accepts, they work as expected and capture analytics, otherwise, they’re converted into no-ops and calling those functions won’t capture any analytics.
Segment only captures consent page load and consent response by default. These are the only two analytics that Segment will capture by default. Should the user opt out of analytics, Segment will not capture anything further.
Users can’t manually navigate to pages other than the consent screen without having provided their consent response. Users may try to navigate to any part of the app by typing the address in the URL bar. However, given Segment is on by default, until they provide a response to the analytics consent, they will always be redirected to the consent page and aren’t allowed to view other pages or interact with the app in any way (and therefore avoid data collection).
Sentry code has been commented removed given it was disabled to avoid interfering with this PR, will be taken care of as part of #2822.
FYI @fbwoolf, using settings slice as recommended in comment.
Closes #2784