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
Set a first-party cookie when user opts out of tracking #15184
Conversation
js/piwik.js
Outdated
@@ -7706,6 +7712,32 @@ if (typeof window.Piwik !== 'object') { | |||
// initialize the Piwik singleton | |||
addEventListener(windowAlias, 'beforeunload', beforeUnloadHandler, false); | |||
|
|||
window.addEventListener('message', function(e) { | |||
try { | |||
var data = JSON.parse(e.data); |
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.
haven't tested it yet... do we need to check if the message is for us just to avoid any issues with potentially other messages? like include some 'matomo_optout' in the string and then check if e.data && typeof e.data === 'string' && e.data.indexOf('matomo_optout') >= -1
? (not tested that particular code... and would need to make sure we post this string in the opt 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.
Have added some namespacing of the message attributes to make it less likely that we'll accidentally pick up messages intended for other scripts. The best practice would be to also check the message origin against the domain we expect to receive it from, but I can't find a way to do this since the tracker and the tracked site could be on any domain.
I don't think I need to explicitly check that e.data
is defined, is a string etc as I am catching the exceptions from JSON.parse()
in situations like this.
js/piwik.js
Outdated
return; | ||
} | ||
|
||
if (typeof data.opted_in == 'undefined') { |
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.
btw we have some method for this isDefined(data.opt_in)
or so is the name
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.
Sweet, using this throughout now
js/piwik.js
Outdated
return; | ||
} | ||
|
||
if (typeof data.loaded != 'undefined') { |
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.
same here be good to use our isDefined method for this maybe
js/piwik.js
Outdated
* first-party opt-out cookie. | ||
*/ | ||
updateOptOutForm: function() { | ||
if (typeof window.postMessage === 'undefined') { |
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.
here as well be good to use isDefined method
js/piwik.js
Outdated
if (numAttempts > 1200) { | ||
clearInterval(optOutTimer); | ||
} | ||
}, 100); |
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.
As DOM interactions are quite expensive in terms of performance, be good to check this maybe only about every second or so? Even every 2 seconds might be fine
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.
The problem is that the optout iframe might be displaying incorrectly to the user (e.g. saying they haven't opted out when they have) until it receives this message. The first time through the loop is usually unsuccessful because the iframe hasn't finished loading yet, and increasing the delay even to 200ms means there is a noticeable pause before the optout iframe updates itself. Maybe we need a new approach - calling postMessage
on the iframe before it finishes loading is also causing an error message to be printed to the console which isn't ideal.
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.
Could use setTimeout
instead... and each time use something like interval = numAttempts * 100 or * 200
or
@@ -1,22 +1,73 @@ | |||
function submitForm(e, form) { | |||
if (e.preventDefault) { // IE8 and below do not support preventDefault |
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 haven't tested the feature yet but would have expected the preventDefault code and also below the setInterval is still needed?
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.
This code was to prevent the checkbox state from toggling until after the API call had been made, and then refresh the iframe to show the new checkbox state. It seems a bit unnecessary when we are working with the first-party cookies, but if we do want to retain that workflow (i.e. sync the iframe form checkbox with the real world optout value after every change, to make sure that it reflects what will actually happen) I could put back the preventDefault
and then fire a message back to the iframe after the first-party cookie has been set in the tracker JS.
…kie; change namespacing of message from mtm_ to maq_; rework optout form initialisation logic to be driven by the optout.js instead of the piwik.js
@Findus23 @MichaelHeerklotz any chance you could give this PR a test as well? |
js/piwik.js
Outdated
var tracker = Piwik.getTracker(); | ||
|
||
var originHost = getHostName(e.origin); | ||
var matomoHost = getHostName(tracker.getPiwikUrl()); |
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.
Would maybe need to adjust getHostName
to check if url
is set... otherwise if the tracking code is embedded on the page, but no async tracker is created (which some users do), then it might not return a string? Not sure though... looking at the code it seems getPiwikUrl
always returns a string so it is likely fine
I was just testing the opt out. I was embedding the opt out into an html page and opted out. The third party
Even though it should say
The problem is that it seems to only check for the first party cookie but not for the third party cookie status here: This will be pretty much the behaviour for all Matomo sites as none of the visitors that previously unsubscribed would have the first party ignore cookie yet. So it is important to only show "You are not opted out" if neither the first nor the third party ignore cookie is set. If either of them is set, we assume the user is opted out. I then opted out, and it was saying "opted out" after I clicked on it. However, when I reloaded the page, it was saying again "not opted out".
Stopped testing afterwards. |
that'd be great.
If it's possible then be great to explain in the error message why it doesn't work eg
not sure of the code details, but the idea would be that consent mechanism should be completely independant of cookies and work the same whether or not cookies are enabled in tracker. |
Note: we still need to ignore disableCookies setting when opting out or in... will create a separate PR for this #15309 |
FYI made a few tweaks...
@diosmosis @Findus23 could you maybe have a look as well? |
matches = e.exec(url); | ||
|
||
return matches ? matches[1] : url; | ||
} |
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.
Would using:
document.createElement('a');
a.href = url;
return a.hostname;
be a bit safer here?
@tsteur looks ok to me though I didn't test locally and it is a fairly complicated PR. I like the interesting use of postMessage here, that seems like it could potentially have other use cases in the tracker (not just opt out and overlay). It would be nice to be able to unit test the opt out JS if possible (maybe by loading it in karma and testing w/ angular unit tests?). Might be a bit of work to make that possible though; if it's a good idea we could create an issue for now. |
Part of #14395 (allowing opt-out to work in Chrome on HTTP sites), also related to #6505