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

Data consent updates and privacy improvements (Fixes #14213) #14559

Merged
merged 8 commits into from
Jun 3, 2024

Conversation

alexgibson
Copy link
Member

@alexgibson alexgibson commented May 9, 2024

One-line summary

Note

I apologize for this PR being large, with many things to test. Whoever reviews I owe you a beverage of your choice at all-hands 🍺 🍸 🍹

This PR implements the following changes:

  • Adds explicit opt-in for data collection in EU/EAA countries only on specific URLs.
  • Omits non-essential cookies and analytics on URLs in EU/EAA countries where opt-in is not requested.
  • Adds global data preferences page and link in main footer.
  • Implements Global Privacy Control (GPC) as an additional opt-out signal to Do Not Track (DNT).

Significant changes and points to review

  • I tried to break down testing instructions per page type / analytics function in order to make things easier. Sorry for the list being long, but it hopefully covers everything.
  • I also tried to separate out consent logic from analytics/attribution logic, to try and make both tests and code easier to follow.

Issue / Bugzilla link

#14213

Testing

Successful test run: https://github.com/mozilla/bedrock/actions/runs/9113965630

Important

Make sure to clear cookies before / after each test.


Cookie settings page (EU):

URL: https://www-demo1.allizom.org/en-US/privacy/websites/cookie-settings/?geo=de

  • When moz-consent-pref consent cookie is NOT set, default form values should equal "I Do Not Agree".
  • When clicking "Save Changes", moz-consent-pref consent cookie IS set.
    • Updating form values and clicking "Save Changes" should update the existing cookie.
    • Refreshing the page should show the values stored in the cookie reflected in the form.

Cookie settings page (rest-of-world):

URL: https://www-demo1.allizom.org/en-US/privacy/websites/cookie-settings/

  • When moz-consent-pref consent cookie is NOT set, default form values should equal "I Agree".

Firefox Campaign Pages (EU)

URL: https://www-demo1.allizom.org/de/firefox/challenge-the-default/?geo=de

With GPC/DNT enabled:

  • Consent banner is NOT shown.
  • GTM script is NOT loaded.
    • Verify window.dataLayer contains core-datalayer-loaded and page-id-loaded events.
  • moz-stub-attribution-code and moz-stub-attribution-sig cookies are NOT set.

With GCP/DNT disabled:

  • Consent banner IS shown.
  • Clicking "Accept" closes banner.
    • GTM script IS loaded.
      • Verify window.dataLayer contains core-datalayer-loaded and page-id-loaded events.
    • moz-stub-attribution-code and moz-stub-attribution-sig cookies ARE set.
    • Refreshing page persists consent choice and analytics behavior.
    • Open: https://www-demo1.allizom.org/de/firefox/download/thanks/?geo=de
      • GTM script IS loaded.
      • attribution_code and attribution_sig parameters ARE added to the Firefox auto-download URL.
  • Clicking "Reject" closes banner.
    • GTM script NOT loaded.
    • moz-stub-attribution-code and moz-stub-attribution-sig cookies are NOT set.
    • Refreshing page persists consent choice and behavior.

GTM test:

  • Test page load / download events fire as expected in GTM when accepting cookies.

Firefox Campaign Pages (rest-of-world)

URL: https://www-demo1.allizom.org/de/firefox/challenge-the-default/

With GPC/DNT enabled:

  • GTM script is NOT loaded.
  • moz-stub-attribution-code and moz-stub-attribution-sig cookies are NOT set.

With GPC/DNT disabled:

  • GTM script IS loaded.
    • Verify window.dataLayer contains core-datalayer-loaded and page-id-loaded events.
  • moz-stub-attribution-code and moz-stub-attribution-sig cookies ARE set.

With a consent cookie set that rejects analytics:

  • GTM script is NOT loaded after page refresh.
  • moz-stub-attribution-code and moz-stub-attribution-sig cookies are NOT set (you may need to clear these if they were already set previously before opt-out).

With a consent cookie set that accepts analytics:

  • GTM script IS loaded after page refresh.
    • Verify window.dataLayer contains core-datalayer-loaded and page-id-loaded events.
  • moz-stub-attribution-code and moz-stub-attribution-sig cookies ARE set.

GTM test:

  • Test page load / download events fire as expected in GTM.

Firefox product pages (EU):

URL: https://www-demo1.allizom.org/en-US/firefox/new/?geo=de

  • Consent banner is NOT shown.
  • GTM (Google Tag Manager) script is NOT loaded.
  • moz-stub-attribution-code and moz-stub-attribution-sig cookies are NOT set.

Firefox product pages pages (rest-of-world)

URL: https://www-demo1.allizom.org/en-US/firefox/new/

With GPC/DNT enabled:

  • GTM script is NOT loaded.
  • moz-stub-attribution-code and moz-stub-attribution-sig cookies are NOT set.

With GCP/DNT disabled:

  • GTM script IS loaded.
    • Verify window.dataLayer contains core-datalayer-loaded and page-id-loaded events.
  • moz-stub-attribution-code and moz-stub-attribution-sig cookies ARE set.
  • Click download
    • attribution_code and attribution_sig parameters ARE added to the Firefox auto-download URL.

With a consent cookie set that rejects analytics:

  • GTM script is NOT loaded.
  • moz-stub-attribution-code and moz-stub-attribution-sig cookies are NOT set (you may need to clear these if they were already set previously before opt-out).

With a consent cookie set that accepts analytics:

  • GTM script IS loaded.
    • Verify window.dataLayer contains core-datalayer-loaded and page-id-loaded events.
  • moz-stub-attribution-code and moz-stub-attribution-sig cookies ARE set.
  • Click download
    • attribution_code and attribution_sig parameters ARE added to the Firefox auto-download URL.

Firefox RTAMO flow (same logic applies for EU and rest-of-world)

URL: https://www-demo1.allizom.org/en-US/firefox/download/thanks/?s=direct&utm_source=test&utm_campaign=test

With GPC/DNT enabled:

  • moz-stub-attribution-code and moz-stub-attribution-sig cookies are NOT set.
  • Firefox auto-download triggers WITHOUT attribution_code and attribution_sig parameters.

With GPC/DNT disabled:

  • moz-stub-attribution-code and moz-stub-attribution-sig cookies ARE set.
  • Firefox auto-download triggers WITH attribution_code and attribution_sig parameters.

FxA form (EU)

URL: https://www-demo1.allizom.org/en-US/firefox/?geo=de&utm_source=test&utm_campaign=test

Note: since these are form fields, you might need to do a hard refresh between each test to reset the form.

  • Consent banner is NOT shown (since the URL is not in the allow-list).
  • utm_source=test and utm_campaign=test are NOT passed through to the form fxa-email-form-utm-source and fxa-email-form-utm-campaign hidden fields.
  • FxA flow params (flow_id, device_id) are NOT added to hidden fields.
  • When filling out the form, email *IS still passed through to FxA as expected.

When using Firefox on desktop:

  • <input type="hidden" name="context" value="fx_desktop_v3"> IS added to the form.

FxA form (rest-of-world)

URL: https://www-demo1.allizom.org/en-US/firefox/?utm_source=test&utm_campaign=test

Note: since these are form fields, you might need to do a hard refresh between each test to reset the form.

By default: (does not require DNT/GPC)

  • utm_source=test and utm_campaign=test ARE passed through to the form fxa-email-form-utm-source and fxa-email-form-utm-campaign hidden fields.
  • FxA flow params (flow_id, device_id) ARE added to hidden fields.
  • When filling out the form, email *IS still passed through to FxA as expected.

With a consent cookie set that rejects analytics:

  • utm_source=test and utm_campaign=test are NOT passed through to the form fxa-email-form-utm-source and fxa-email-form-utm-campaign hidden fields.
  • FxA flow params (flow_id, device_id) are NOT added to hidden fields.
  • When filling out the form, email IS still passed through to FxA as expected.

With a consent cookie set that accepts analytics:

  • utm_source=test and utm_campaign=test ARE passed through to the form fxa-email-form-utm-source and fxa-email-form-utm-campaign hidden fields.
  • FxA flow params (flow_id, device_id) ARE added to hidden fields.
  • When filling out the form, email *IS still passed through to FxA as expected.

When using Firefox on desktop:

  • <input type="hidden" name="context" value="fx_desktop_v3"> IS added to the form.

VPN attribution (EU)

URL: https://www-demo1.allizom.org/en-US/products/vpn/?geo=pl&utm_source=test&utm_campaign=test

With GPC/DNT enabled:

  • Consent banner is NOT shown.
  • utm_source=test&utm_campaign=test are NOT propagated through to subscription links.
  • FxA flow parameters (flow_id, device_id etc) are NOT added to subscription links.

With GCP/DNT disabled:

  • Consent banner IS shown.
  • Clicking "Accept" closes banner.
    • utm_source=test&utm_campaign=test ARE propagated through to subscription links.
    • FxA flow parameters (flow_id, device_id etc) ARE added to subscription links.
    • Refreshing page persists consent choice and analytics behavior.
  • Clicking "Reject" closes banner.
    • utm_source=test&utm_campaign=test are NOT propagated through to subscription links.
    • FxA flow parameters (flow_id, device_id etc) are NOT added to subscription links.
    • Refreshing page persists consent choice and analytics behavior.

VPN attribution (rest-of-world)

URL: https://www-demo1.allizom.org/en-US/products/vpn/?utm_source=test&utm_campaign=test

By default: (does not require DNT/GPC)

  • utm_source=test&utm_campaign=test ARE propagated through to subscription links.
  • FxA flow parameters (flow_id, device_id etc) ARE added to subscription links.

With a consent cookie set that rejects analytics:

  • utm_source=test&utm_campaign=test are NOT propagated through to subscription links.
  • FxA flow parameters (flow_id, device_id etc) are NOT added to subscription links.

With a consent cookie set that accepts analytics:

  • utm_source=test&utm_campaign=test ARE propagated through to subscription links.
  • FxA flow parameters (flow_id, device_id etc) ARE added to subscription links.

VPN affiliate marketing flow (EU)

URL: https://www-demo1.allizom.org/en-US/products/vpn/?geo=de&cjevent=123456789

With GPC/DNT enabled:

  • Consent banner is NOT shown.
  • Fetch request is NOT made to stage.cjms.nonprod.cloudops.mozgcp.net/aic.
  • moz-cj-affiliate cookie is NOT set.

With GCP/DNT disabled:

  • Consent banner IS shown.
  • Clicking "Accept" closes banner
    • Fetch request IS made to stage.cjms.nonprod.cloudops.mozgcp.net/aic.
    • moz-cj-affiliate cookie IS set.
    • Refreshing page persists consent choice and analytics behavior.
  • Clicking "Reject" closes banner
    • moz-cj-affiliate cookie is NOT set.
    • Fetch request is NOT made to stage.cjms.nonprod.cloudops.mozgcp.net/aic.
    • Refreshing page persists consent choice and analytics behavior.

VPN affiliate marketing flow (rest-of-world)

URL: https://www-demo1.allizom.org/en-US/products/vpn/?cjevent=123456789

With GPC/DNT enabled:

  • Fetch request is NOT made to stage.cjms.nonprod.cloudops.mozgcp.net/aic.
  • moz-cj-affiliate cookie is NOT set.

With GCP/DNT disabled:

  • Fetch request IS made to stage.cjms.nonprod.cloudops.mozgcp.net/aic.
  • moz-cj-affiliate cookie IS set.

With a consent cookie set that rejects analytics:

  • Fetch request is NOT made to stage.cjms.nonprod.cloudops.mozgcp.net/aic.
  • moz-cj-affiliate cookie is NOT set.

With a consent cookie set that accepts analytics:

  • Fetch request *IS made to stage.cjms.nonprod.cloudops.mozgcp.net/aic.
  • moz-cj-affiliate cookie IS set.

VPN / Stripe Radar (EU)

URL: https://www-demo1.allizom.org/en-US/products/vpn/?geo=de

With GPC/DNT enabled:

  • Consent banner is NOT shown.
  • Cookies from js.stripe.com are NOT set.

With GCP/DNT disabled:

  • Consent banner IS shown.
  • Clicking "Accept" closes banner.
    • Cookies from js.stripe.com ARE set.
    • Refreshing page persists consent choice and analytics behavior.
  • Clicking "Reject" closes banner.
    • Cookies from js.stripe.com are NOT set.
    • Refreshing page persists consent choice and analytics behavior.

VPN / Stripe Radar (rest-of-world)

URL: https://www-demo1.allizom.org/en-US/products/vpn/

By default:

  • Cookies from js.stripe.com ARE set.

With a consent cookie set that rejects analytics:

  • Cookies from js.stripe.com are NOT set.

With a consent cookie set that accepts analytics:

  • Cookies from js.stripe.com ARE set.

Glean (EU)

URL: https://www-demo1.allizom.org/en-US/products/vpn/?geo=de

With GPC/DNT enabled:

  • Consent banner is NOT shown.
  • Glean page load ping is NOT sent.

With GPC/DNT disabled:

  • Consent banner IS shown.
  • Clicking "Accept" closes banner
    • Glean page load ping IS sent.
    • Refreshing page persists consent choice and analytics behavior.
  • Clicking "Reject" closes banner
    • Glean deletion request ping IS sent.
    • Refreshing page should show no ping.

Glean (rest-of-world)

URL: https://www-demo1.allizom.org/en-US/products/vpn/

By default (does not require DNT/GPC):

  • Glean page load ping IS sent.

With a consent cookie set that rejects analytics:

  • Glean deletion request ping IS sent.

With a consent cookie set that accepts analytics:

  • Glean page load ping IS sent.

Page banners (same logic applies for EU and rest-of-world)

This is not so easy to test as right now there is not a banner shown on desktop. The easiest way is to change this code locally so the firefox app store banner gets shown on desktop.

URL: http://localhost:8000/en-US/

  • firefox-app-store-banner cookie IS set when clicking close (X) button on app banner.
  • Monitor banner is NOT displayed again on page reload.

With a consent cookie set that rejects preference cookies:

  • firefox-app-store-banner cookie is NOT set when clicking close (X) button on app banner.
  • App banner IS displayed again on page reload.

With a consent cookie set that accepts preference cookies:

  • firefox-app-store-banner cookie IS set when clicking close (X) button on app banner.
  • App banner is NOT displayed again on page reload.

Traffic Cop (same logic applies for EU and rest-of-world)

URL: https://www-demo1.allizom.org/en-US/products/vpn/

With GPC/DNT enabled:

  • Experiment redirect is not triggered.

With GPC/DNT disabled:


GPC (Global Privacy Control)

URL: https://www-demo1.allizom.org/.well-known/gpc.json

  • Returns valid application/json content type

Copy link

codecov bot commented May 9, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 76.90%. Comparing base (090c466) to head (8b47cb6).

Current head 8b47cb6 differs from pull request most recent head bbb3988

Please upload reports for the commit bbb3988 to get more accurate results.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #14559      +/-   ##
==========================================
+ Coverage   76.85%   76.90%   +0.04%     
==========================================
  Files         156      156              
  Lines        8149     8166      +17     
==========================================
+ Hits         6263     6280      +17     
  Misses       1886     1886              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@alexgibson alexgibson force-pushed the cookie-banner-hook branch 19 times, most recently from e1fe4ab to 1acc725 Compare May 15, 2024 09:05
@alexgibson alexgibson force-pushed the cookie-banner-hook branch 5 times, most recently from 8cd7d63 to 0be5e58 Compare May 15, 2024 10:07
stephaniehobson

This comment was marked as resolved.

Copy link
Contributor

@stephaniehobson stephaniehobson left a comment

Choose a reason for hiding this comment

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

Issue: Banner remains visible after consent cookie is set.

Steps to reproduce:

  1. Land on a page which opens the banner
  2. Click Cookie settings
  3. Configure cookies and save
  4. Use the back button or click previous page

Expected behaviour:

  • Consent has been configured, the banner does not display

Actual behaviour:

  • Consent banner is still visible.
    (reloading the page acts as expected and does make it respect the new settings)

I'm open to this being non-blocking if it can be addressed in a follow-up PR, however, this is how I commonly interact with these banners so there's at least one user out there would would be confused by it.

Edit: Now that I know what's involved in fixing this I no-longer consider it launch blocking.

Copy link
Contributor

@stephaniehobson stephaniehobson left a comment

Choose a reason for hiding this comment

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

With a consent cookie set that rejects analytics:

[ ] Glean deletion request ping IS sent.

I'm not sure what I'm looking for to confirm this.

@alexgibson
Copy link
Member Author

Question: Is it a concern that for FxA form (rest-of-world) if DNT/GPC are enabled the form behaves as if the user has consented to analytics?

Not at this time, but this could change in the future. The mandate thus far has been to fix issues for EU/EAA, with minimal changes for rest-of-world. From legal's perspective this is OK for now, but how we handle consent longer term for rest-of-world will likely be a followup item to address.

Re Glean: I'm not sure what I'm looking for to confirm this.

See: https://bedrock.readthedocs.io/en/latest/attribution/0001-analytics.html#debugging-pings. You should be able to see when a deletion request ping is sent.

Issue: Banner remains visible after consent cookie is set.

What you're seeing here is bfcache, which is default browser behavior. Basically when clicking the back button, the previous page is cached by the browser rather than requiring it to be loaded over the network again. There are ways to disable this, but the obvious drawback is we lose the performance gains of bfcache. I'll take a look to see if there's anything we can do here, but my gut is to not really start messing with this stuff.

@alexgibson
Copy link
Member Author

alexgibson commented May 28, 2024

@stephaniehobson I pushed a commit containing a potential fix for the bfcache issue you spotted. It makes me a little nervous to write code that will automatically refresh a web page, so let's only use this if we feel like the fix is safe. I did add some guardrails around it so that the code will only run if a consent banner was visible on the previous page. Let me know what you think? I pushed it to the demo instance for testing - it seems to work OK?

/**
 * If user clicks back button from /cookie-settings/ and
 * the page is in bfcache, reload the page if they have
 * set a consent cookie to avoid showing the banner again
 * inadvertently.
 * @param {Object} e - The page navigation event.
 */
function handleBfCacheNavigation(e) {
    if (e.persisted && hasConsentCookie()) {
        window.location.reload();
    }
}

window.addEventListener('pageshow', handleBfCacheNavigation, false);

@stephaniehobson
Copy link
Contributor

Glean (EU) > With GPC/DNT disabled > Clicking "Reject" closes banner > Glean deletion request ping IS sent.

When I rejected cookies I saw this (Glean.core.Pings.Maker) Storage for deletion-request empty. Ping will still be sent.

@stephaniehobson
Copy link
Contributor

Chore: The following strings can be removed from vpn/shared.ftl:

vpn-shared-affiliate-notification-message
vpn-shared-affiliate-notification-reject
vpn-shared-affiliate-notification-ok

Copy link
Contributor

@stephaniehobson stephaniehobson left a comment

Choose a reason for hiding this comment

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

I have tested/reviewed all the functionality and files I wanted to. I think the only merge-blocking thing is that I have not been able to verify the Glean deletion request ping. That could still be tester error though.

Removing the banner when the user goes back to the banner page after viewing cookie settings is not a launch blocker IMHO (now that I know what it would take to fix it...) but we should make sure we're both comfortable with the current state before it merges. Maybe we can clear that up on Slack tomorrow or Monday morning.

@alexgibson
Copy link
Member Author

alexgibson commented May 31, 2024

When I rejected cookies I saw this (Glean.core.Pings.Maker) Storage for deletion-request empty. Ping will still be sent.

This is the expected result. The log message is worded a little oddly for sure. I asked the Glean folks about it, and they say it basically means the ping has no custom metrics attached to it other than the standard client_info section that contains client_id etc. This is all that's needed for a deletion-request since it basically tells our telemetry systems to "delete all data containing this client_id".

@alexgibson
Copy link
Member Author

alexgibson commented May 31, 2024

Thanks for the detailed review @stephaniehobson!

I've addressed all comments so far. I think we're both comfortable enough with handleBfCacheNavigation()? It seems to work well enough in testing, and should only fire under the specific condition when a banner is shown.

@stephaniehobson
Copy link
Contributor

R+ as soon as the lastupdated date is updated.

Very through and thoughtful work on a massive change for the better. ✨

@alexgibson
Copy link
Member Author

alexgibson commented May 31, 2024

Thanks @stephaniehobson - can you please give me an r+wc and then I can update the date and merge on Monday? (this will give me extra time in my day to test things before deploying to prod). Thanks again

Copy link
Contributor

@stephaniehobson stephaniehobson left a comment

Choose a reason for hiding this comment

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

R+wc

Just needs the date updated.

@alexgibson alexgibson merged commit 5507bb2 into mozilla:main Jun 3, 2024
4 checks passed
@alexgibson alexgibson deleted the cookie-banner-hook branch June 3, 2024 08:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Do Not Merge ⚠️ Needs Review Awaiting code review P1 First level priority - Must have Review: L Code review time: 2 hours or more
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants