-
Notifications
You must be signed in to change notification settings - Fork 2
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
Send events using POST #36
Conversation
680e022
to
cac9020
Compare
cac9020
to
2e99415
Compare
2e99415
to
1f6df61
Compare
1f6df61
to
dccaac1
Compare
32f81cb
to
d549746
Compare
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.
had just a couple comments. a couple other call-outs:
- can we see if this seems to not get blocked by Adblock on folk's local machines? I coincidentally was just helping Michael with a WT thing and it was being blocked by his Adblock, so we could test it on his machine (or likely anyone else's)
- can we ensure that we have the best view of pageloads -> pageviews possible ahead of launching this? i was working with Clayton on some of this, but I think we should be a bit more confident on those charts before shipping so we are confident we have a good way to track how well this change goes.
@@ -144,7 +151,13 @@ export class WT { | |||
delete this.loaderImage.onload; | |||
reject(); | |||
}; | |||
this.loaderImage.src = `${this.getUrl()}?${query}`; | |||
const params = new this.context.URLSearchParams(query); | |||
const sendBeaconResult = this.context.navigator.sendBeacon(`${this.getBeaconUrl()}`, params); |
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.
afaict, the only time this would return false is if the data limit is surpassed, see the note under Return Value here. given that, I'm a bit skeptical that we'd ever get false returned but I think we don't know for sure. that being said, can we just hit the new POST endpoint instead (via a standard AJAX call) so we don't have to maintain the track.gif
endpoint? then, we also wouldn't need beaconUrl
and trackerUrl
, we can just have the latter.
additionally, not all browsers will have navigator.sendBeacon
, so I think it would be wise to add a polyfill to avoid crashing in this case, or checking for the existence of the function and falling back to an AJAX call if it doesn't exist.
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.
@bcharna i believe there's an example of hitting the data limit (via an overly long query string) in the PR description.
that said, i think the only reason that's likely to happen is due to the how we batch events together. i'm not sure if there's any reason to do that with the beacon API, but if we can remove that it would be a win in terms of complexity.
re: polyfilling, i think we can safely offload that to consumers of the library rather than make that decision for everybody.
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.
yeah, except the data limits may be different for query string size limit vs beacon's limit.
also agree batching may not be necessary, but likely something we can punt on for now to keep change size smaller.
fair point on polyfilling – are you proposing we go with my latter suggestion (check for existence of function and hit AJAX if not present)?
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.
proposing we leave as is + add a note in the readme that sendBeacon
support is required and users may polyfill if neccesary.
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.
ah, I see. sorry, I sort of combined two pieces of feedback in the original comment. so I think to summarize we're saying:
- end users of wt (for us, landing, platform and today) will polyfill themselves.
- we'll make a POST request instead of an image request in the case that
this.context.navigator.sendBeacon
returnsfalse
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.
Do we want to completely get rid of the image request (i.e. try sendBeacon then try POST)? or try all three (i.e. try sendBeacon then try POST then try image)?
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.
I don't see a reason to keep the image request around – all browsers should support POST via standard AJAX. but to clarify, @nopelluhh was proposing only to fallback to the standard AJAX if sendBeacon
returns false, thus we assume that the function is present (this means we'll want to add a polyfill in our apps that use wt).
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 are your thoughts on a sendbeacon-polyfill? I see from the source code that it already handles sending as AJAX.
If we take all the suggestions into consideration, seems like we can clean up a lot of code (remove image fallback, remove batching, use polyfill to handle fallback)
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.
it looks like that's a fork of https://github.com/miguelmota/Navigator.sendBeacon, can we see what the difference is between those? it looks like the original repo has more stars/has been updated more recently but have never worked w/ either.
and yep, a lot of cleanup is possible here!
@@ -52,7 +53,9 @@ export class WT { | |||
this.emitter = new EventEmitter(); | |||
this.wtConfig = { cookies: { expires: EXPIRES_IN_DAYS } }; | |||
this.context = context; | |||
this.paramDefaults = {}; | |||
this.paramDefaults = { | |||
wt_version: WT_VERSION, |
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.
I like this! will it go into event.metadata
?
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.
i'm not sure that i like this (as is); recording this for every event seems excessive, especially if it's going into an already unstructured metadata column. what's the motivation for tracking this/do we need it on a data level/do we need it for every event?
if we do keep this i'd suggest renaming to wt_client_version
for accuracy.
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.
I don't think we have to worry about storage size, but I hear you. I actually think having app version info would be more useful (so not super opinionated on whether we leave wt version info in or not), but that's outside of the scope here.
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.
yeah, this will be saved in event.metadata
. this was to help me QA that the new events were saving properly on macallan so I don't feel too strongly about keeping it. i feel ok with removing it because it doesn't add much value outside of the QA use case.
also, going to pass along to @nopelluhh to do a pass as well, since this is such critical code. |
@@ -52,7 +53,9 @@ export class WT { | |||
this.emitter = new EventEmitter(); | |||
this.wtConfig = { cookies: { expires: EXPIRES_IN_DAYS } }; | |||
this.context = context; | |||
this.paramDefaults = {}; | |||
this.paramDefaults = { | |||
wt_version: WT_VERSION, |
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.
i'm not sure that i like this (as is); recording this for every event seems excessive, especially if it's going into an already unstructured metadata column. what's the motivation for tracking this/do we need it on a data level/do we need it for every event?
if we do keep this i'd suggest renaming to wt_client_version
for accuracy.
@@ -144,7 +151,13 @@ export class WT { | |||
delete this.loaderImage.onload; | |||
reject(); | |||
}; | |||
this.loaderImage.src = `${this.getUrl()}?${query}`; | |||
const params = new this.context.URLSearchParams(query); | |||
const sendBeaconResult = this.context.navigator.sendBeacon(`${this.getBeaconUrl()}`, params); |
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.
@bcharna i believe there's an example of hitting the data limit (via an overly long query string) in the PR description.
that said, i think the only reason that's likely to happen is due to the how we batch events together. i'm not sure if there's any reason to do that with the beacon API, but if we can remove that it would be a win in terms of complexity.
re: polyfilling, i think we can safely offload that to consumers of the library rather than make that decision for everybody.
@@ -144,7 +151,13 @@ export class WT { | |||
delete this.loaderImage.onload; | |||
reject(); | |||
}; | |||
this.loaderImage.src = `${this.getUrl()}?${query}`; | |||
const params = new this.context.URLSearchParams(query); |
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.
along the lines of brad's browser support callout, this is a newer API. we already use the qs
library so i'd suggest using that (or fully migrating to URLSearchParams
if you have time for a bigger change).
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's our cutoff for browser support for both sendBeacon
and URLSearchParams
? Their browser compatibility is pretty similar with full support on latest versions except no support on IE. For sendBeacon
's data parameter, I'm taking advantage of the URLSearchParams
object so they kind of go hand-in-hand so I don't think I could use qs
with sendBeacon
. I also tried the Blob object with sendBeacon
to send the data as JSON but that led to CORS issues.
i selfishly like the idea that noah suggested to leave as is, add note in the readme that sendBeacon
and URLSearchParams
are required and let users polyfill if necessary.
this also leads back to the fallback question: if we're requiring sendBeacon support, should we just get rid of all fallbacks (POST and image)? i left the image code in there to keep the change small
if (sendBeaconResult) { | ||
resolve(); | ||
} else { | ||
this.loaderImage.src = `${this.getUrl()}?${query}`; |
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.
in line with the above comment on when we'd fall back to this, i'm concerned we don't have visibility into when/how often this fallback is happening. it's liable to happen frequently in areas where we track text input (putting aside how silly some of our tracking is on that front).
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.
yeah, great call-out, was thinking something similar. we could add an extra param in the body (that doesn't need to go into the wt event), something like fallback: true
, and then see frequency by querying request logs.
Motivations: 1) Change the tracking endpoint so that it doesn't contain "track" in its path, i.e. move away from "/track.gif" 2) Use the POST HTTP method for more reliability and avoiding errors from URI length limits Other Notes: - Uses whatwg-fetch to polyfill window.fetch() in older browsers. - Sends requests to /wt/t at the configured trackerDomain, otherwise the same host as the current page. - Cross-origin tracking may require CORS changes on the server
d549746
to
db26301
Compare
I made the following changes, repushed to Macallan, and re-tested on Chrome, Safari, and Firefox. Changes:
Going to fast-follow these changes so we can unblock marketing:
I got a few people on the team to QA but didn't explicitly call out using AdBlock. I did verify that the fix was not blocked by uBlock on my own machine. I'll get a few more people to test with ad blockers today.
Yup, Clayton sent over this dashboard. Hoping that we see a noticeable jump up after the release. |
Update: Got Deergha to confirm that events are coming through, even with Adblock |
great on the QA front, also yeah that's the dashboard we were looking at. I don't think it's perfect, but should provide us at least directional insights.
I still think we should do this as Beacon provides more of a guarantee that requests will go through (if browser window is closed). let's also consider removing batching in the next go. |
fetch(`${this.getRoot()}/wt/t`, { | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/x-www-form-urlencoded', |
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.
can we switch this to json? suppose can wait until the follow-up release
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.
Yeah good question. I initially thought json wouldn't work because I was getting a CORS error, but the change in platform seems to have addressed it now. I can switch to json in the follow-up.
Edit: Actually, if we go with sendBeacon
this may not be relevant
also @mattagra, can you update the PR description now that stuff has changed? |
Done. Also added fast-follows to the PR description. |
Interesting, we're seeing a few events fall back to the pixel image with Not seeing non-2xx on the /wt/t endpoint though so it might be a problem receiving the response from the server. Also makes me wonder if this would double record events. Seems like |
Pivotal ticket(s)
https://www.pivotaltracker.com/story/show/177824064
Context
WT Event Fixes Spec
Changes
/wt/t
withPOST
method using window.fetch()window.fetch()
fails (plan is to remove in the future)Test Cases
Tested on macallan
@clutter/wt@1.2.0-rc.1
See events on macallan:
Chrome:
Firefox:
Safari:
Callouts
wt changes: https://github.com/clutter/wt/pull/62
Future