Page MenuHomePhabricator

CentralNotice: Make a plan for moving stuff out of cookies
Closed, ResolvedPublic2 Estimated Story Points

Description

Find any currently-in-use and lingering CN cookies via logs, campaign mixin params in the DB, banner scripts, or anywhere else we can think of.

Clarify fundraising and community requirements for any functionality currently provided by cookies, especially for fallback mechanisms when LocalStorage doesn't work.

Check how this work may interact with upcoming core code for working with LocalStorage.

Make a plan for removing as many as CN- or banner-related cookies as possible, in as safe a way as possible.

Event Timeline

Here are some types of CentralNotice cookie that could be candidates for removal or transfer to LocalStorage:

  1. CN (buckets by campaign)
  2. impressionDiet mixin
  3. largeBannerLimit mixin
  4. hide cookies
  5. old-style impression limit cookies set by FR and non-FR banners
  6. cookies set by other miscellaneous non-FR banners

I suggest hide cookies (4) be kept on hold until we create a better mechanism for hiding banners across wikis (T117433).

For a few categories, we may want to be able to fall back to cookies if LocalStorage isn't available; we might check again what percentage of our users have that issue.

For cookies set by mixins (2 and 3) I queried the CentralNotice logs for a list of cookies that these mixins have ever set.

impressionDiet

WMAR DesafiosEdicion octubre2015
[empty string]
C15_WMDE_Test01
wmde-fundraising-2015
banner-diet-test
wam-banner-hide
WAM_2015_11_progress_hide
WAM_2015_11_progress_hide-1
centralnotice_bannercount_fr15
WAM_2015_11_progress_hide-2
sciphotogreece
WMNL-register-WCN-2015
bannercount_fundraiser_Dec2015
wmch-fundraising-2015
Fundraising 2015-wmch
wmde-fundraising-thankyou-2015
WMNL-register-drink-2016
WMIL_Wiktionary_Course20152
NorthBrabant
bannercount_fundraiser_2016
bannercount_WMPL_OPP_2016a
wikimania
WMHU_1percent_2016a
WritingWeeksBrussels2016

largeBannerLimit

centralnotice-frbanner-seen-fullscreen

Also, @BBlack has kindly said he might get data on useless cookies we're seeing from clients on production (see T132374).

A query of the banner history logs on Hadoop provides some insight into the percentage of users who get banners but who have problems with LocalStorage. From a sample of 4000 log entries, about 0.4% don't have LocalStorage available in their browsers, and about 0.25% have other LocalStorage errors (file corruption, no space left on device, quota exceeded...). Details are below.

1== Code ==
2
3SAMPLE_SIZE = 2000
4PAST_HOUR_RANGE = 2160 # 90 days * 24 hrs
5
6import json
7from datetime import datetime, timedelta
8
9events = []
10
11for _ in range( SAMPLE_SIZE ):
12 h = random.randint( 0, PAST_HOUR_RANGE - 1 )
13 dh = datetime.today() - timedelta( hours = h )
14 f_name = "/wmf/data/raw/eventlogging/eventlogging_CentralNoticeBannerHistory/hourly/" + \
15 "{}/{:02d}/{:02d}/{:02d}".format( dh.year, dh.month, dh.day, dh.hour )
16 rdd = sc.sequenceFile( f_name )
17 event = json.loads(rdd.first()[1])['event']
18 events.append(event)
19
20errors = [event['e'] for event in events if 'e' in event]
21errors
22
23
24== Results ==
25
261st run: 0.7% (14 errors/2000 logs)
272nd run: 0.55% (11 errors/2000 logs)
28
29
30=== Errors found ===
31
32== Error type breakdown (both runs) ==
33
34"LocalStorage not available" : 0.375% (15/4000)
35"File error: Corrupted" : 0.1% (4/4000)
36"QuotaExceededError" : 0.075% (3/4000)
37"File error: No device space" : 0.05% (2/4000)
38"SQLite encountered an IO error" : 0.025% (1/4000)
39
40
41== 1st run ==
42
43[u'LocalStorage not available.',
44 u'Couldn\'t write value due to LocalStorage exception [Exception... "File error: Corrupted" nsresult: "0x8052000b (NS_ERROR_FILE_CORRUPTED)" location: "JS frame :: https://sv.wikipedia.org/w/load.php?debug=false&lang=sv&modules=Spinner%7Cext.centralNotice.bannerController%2CbannerHistoryLogger%2CchoiceData%2Cdisplay%2CgeoIP%2CimpressionDiet%2CkvStore%2CkvStoreMaintenance%2ClargeBannerLimit%2ClegacySupport%2CstartUp%7Cext.centralauth.centralautologin%7Cext.uls.init%2Cinterface%2Cpreferences%2Cwebfonts%7Cext.visualEditor.desktopArticleTarget.init%7Cext.visualEditor.track%2Cve%7Cjquery.byteLength%2Ccookie%2CembedPlayer%2CloadingSpinner%2CmwEmbedUtil%2CtabIndex%2Cthrottle-debounce%2CtriggerQueueCallback%7Cmediawiki.Title%2CUri%2Capi%2Ccldr%2Ccookie%2CjqueryMsg%2Clanguage%2Ctemplate%2Cuser%7Cmediawiki.api.options%2Cuser%7Cmediawiki.language.data%2Cinit%7Cmediawiki.libs.pluralruleparser%7Cmediawiki.page.startup%7Cmediawiki.template.regexp%7Cmmv.head%7Cmw.EmbedPlayer.loader%7Cmw.MediaWikiPlayer.loader%7Cmw.MwEmbedSupport%2CPopUpMediaTransform%7Cmw.MwEmbedSupport.style%7Cmw.PopUpMediaTransform.styles%7Cmw.TimedText.loader%7Cskins.vector.js%7Cuser.defaults&skin=vector&version=596a59638cfd :: mw.centralNotice.kvStore.setItem :: line 38" data: no]',
45 u'LocalStorage not available.',
46 u'Couldn\'t write value due to LocalStorage exception [Exception... "File error: Corrupted" nsresult: "0x8052000b (NS_ERROR_FILE_CORRUPTED)" location: "JS frame :: https://sv.wikipedia.org/w/load.php?debug=false&lang=sv&modules=Spinner%7Cext.centralNotice.bannerController%2CbannerHistoryLogger%2CchoiceData%2Cdisplay%2CgeoIP%2CimpressionDiet%2CkvStore%2CkvStoreMaintenance%2ClargeBannerLimit%2ClegacySupport%2CstartUp%7Cext.centralauth.centralautologin%7Cext.uls.init%2Cinterface%2Cpreferences%2Cwebfonts%7Cext.visualEditor.desktopArticleTarget.init%7Cext.visualEditor.track%2Cve%7Cjquery.byteLength%2Ccookie%2CembedPlayer%2CloadingSpinner%2CmwEmbedUtil%2CtabIndex%2Cthrottle-debounce%2CtriggerQueueCallback%7Cmediawiki.Title%2CUri%2Capi%2Ccldr%2Ccookie%2CjqueryMsg%2Clanguage%2Ctemplate%2Cuser%7Cmediawiki.api.options%2Cuser%7Cmediawiki.language.data%2Cinit%7Cmediawiki.libs.pluralruleparser%7Cmediawiki.page.startup%7Cmediawiki.template.regexp%7Cmmv.head%7Cmw.EmbedPlayer.loader%7Cmw.MediaWikiPlayer.loader%7Cmw.MwEmbedSupport%2CPopUpMediaTransform%7Cmw.MwEmbedSupport.style%7Cmw.PopUpMediaTransform.styles%7Cmw.TimedText.loader%7Cskins.vector.js%7Cuser.defaults&skin=vector&version=596a59638cfd :: mw.centralNotice.kvStore.setItem :: line 38" data: no]',
47 u'Couldn\'t write value due to LocalStorage exception [Exception... "File error: Corrupted" nsresult: "0x8052000b (NS_ERROR_FILE_CORRUPTED)" location: "JS frame :: https://sv.wikipedia.org/w/load.php?debug=false&lang=sv&modules=Spinner%7Cext.centralNotice.bannerController%2CbannerHistoryLogger%2CchoiceData%2Cdisplay%2CgeoIP%2CimpressionDiet%2CkvStore%2CkvStoreMaintenance%2ClargeBannerLimit%2ClegacySupport%2CstartUp%7Cext.centralauth.centralautologin%7Cext.uls.init%2Cinterface%2Cpreferences%2Cwebfonts%7Cext.visualEditor.desktopArticleTarget.init%7Cext.visualEditor.track%2Cve%7Cjquery.byteLength%2Ccookie%2CembedPlayer%2CloadingSpinner%2CmwEmbedUtil%2CtabIndex%2Cthrottle-debounce%2CtriggerQueueCallback%7Cmediawiki.Title%2CUri%2Capi%2Ccldr%2Ccookie%2CjqueryMsg%2Clanguage%2Ctemplate%2Cuser%7Cmediawiki.api.options%2Cuser%7Cmediawiki.language.data%2Cinit%7Cmediawiki.libs.pluralruleparser%7Cmediawiki.page.startup%7Cmediawiki.template.regexp%7Cmmv.head%7Cmw.EmbedPlayer.loader%7Cmw.MediaWikiPlayer.loader%7Cmw.MwEmbedSupport%2CPopUpMediaTransform%7Cmw.MwEmbedSupport.style%7Cmw.PopUpMediaTransform.styles%7Cmw.TimedText.loader%7Cskins.vector.js%7Cuser.defaults&skin=vector&version=596a59638cfd :: mw.centralNotice.kvStore.setItem :: line 38" data: no]',
48 u'Couldn\'t write value due to LocalStorage exception [Exception... "SQLite encountered an IO error" nsresult: "0x80630002 (NS_ERROR_STORAGE_IOERR)" location: "JS frame :: https://en.wikipedia.org/w/load.php?debug=false&lang=en&modules=Spinner%7Cext.centralNotice.bannerController%2CbannerHistoryLogger%2CchoiceData%2Cdisplay%2CgeoIP%2CimpressionDiet%2CkvStore%2CkvStoreMaintenance%2ClargeBannerLimit%2ClegacySupport%2CstartUp%7Cext.centralauth.centralautologin%7Cext.eventLogging%7Cext.eventLogging.subscriber%7Cext.quicksurveys.init%2Clib%7Cext.uls.init%2Cinterface%2Cpreferences%2Cwebfonts%7Cext.visualEditor.desktopArticleTarget.init%7Cext.visualEditor.supportCheck%2Ctrack%2Cve%7Cjquery.byteLength%2Ccookie%2CembedPlayer%2CloadingSpinner%2CmwEmbedUtil%2CtabIndex%2Cthrottle-debounce%2CtriggerQueueCallback%7Cmediawiki.Title%2CUri%2Capi%2Ccldr%2Ccookie%2Cexperiments%2CjqueryMsg%2Clanguage%2Cstorage%2Ctemplate%2Cuser%7Cmediawiki.api.options%2Cuser%7Cmediawiki.language.data%2Cinit%7Cmediawiki.libs.pluralruleparser%7Cmediawiki.page.startup%7Cmediawiki.template.regexp%7Cmmv.head%7Cmw.EmbedPlayer.loader%7Cmw.MediaWikiPlayer.loader%7Cmw.MwEmbedSupport%2CPopUpMediaTransform%7Cmw.MwEmbedSupport.style%7Cmw.PopUpMediaTransform.styles%7Cmw.TimedText.loader%7Cschema.QuickSurveyInitiation%7Cskins.vector.js%7Cuser.defaults&skin=vector&version=ae794d7bd151 :: mw.centralNotice.kvStore.setItem :: line 46" data: no]',
49 u'LocalStorage not available.',
50 u'Couldn\'t write value due to LocalStorage exception [Exception... "File error: Corrupted" nsresult: "0x8052000b (NS_ERROR_FILE_CORRUPTED)" location: "JS frame :: https://sv.wikipedia.org/w/load.php?debug=false&lang=sv&modules=Spinner%7Cext.centralNotice.bannerController%2CbannerHistoryLogger%2CchoiceData%2Cdisplay%2CgeoIP%2CimpressionDiet%2CkvStore%2CkvStoreMaintenance%2ClargeBannerLimit%2ClegacySupport%2CstartUp%7Cext.centralauth.centralautologin%7Cext.uls.init%2Cinterface%2Cpreferences%2Cwebfonts%7Cext.visualEditor.desktopArticleTarget.init%7Cext.visualEditor.track%2Cve%7Cjquery.byteLength%2Ccookie%2CembedPlayer%2CloadingSpinner%2CmwEmbedUtil%2CtabIndex%2Cthrottle-debounce%2CtriggerQueueCallback%7Cmediawiki.Title%2CUri%2Capi%2Ccldr%2Ccookie%2CjqueryMsg%2Clanguage%2Ctemplate%2Cuser%7Cmediawiki.api.options%2Cuser%7Cmediawiki.language.data%2Cinit%7Cmediawiki.libs.pluralruleparser%7Cmediawiki.page.startup%7Cmediawiki.template.regexp%7Cmmv.head%7Cmw.EmbedPlayer.loader%7Cmw.MediaWikiPlayer.loader%7Cmw.MwEmbedSupport%2CPopUpMediaTransform%7Cmw.MwEmbedSupport.style%7Cmw.PopUpMediaTransform.styles%7Cmw.TimedText.loader%7Cskins.vector.js%7Cuser.defaults&skin=vector&version=596a59638cfd :: mw.centralNotice.kvStore.setItem :: line 38" data: no]',
51 u'LocalStorage not available.',
52 u'LocalStorage not available.',
53 u'LocalStorage not available.',
54 u'LocalStorage not available.',
55 u'LocalStorage not available.',
56 u'LocalStorage not available.']
57
58
59== 2nd run ==
60
61[u'LocalStorage not available.',
62 u'LocalStorage not available.',
63 u"Couldn't write value due to LocalStorage exception QuotaExceededError",
64 u'LocalStorage not available.',
65 u'Couldn\'t write value due to LocalStorage exception [Exception... "File error: No device space" nsresult: "0x80520010 (NS_ERROR_FILE_NO_DEVICE_SPACE)" location: "JS frame :: https://en.wikipedia.org/w/load.php?debug=false&lang=en&modules=Spinner%7Cext.centralNotice.bannerController%2CbannerHistoryLogger%2CchoiceData%2Cdisplay%2CgeoIP%2CimpressionDiet%2CkvStore%2CkvStoreMaintenance%2ClargeBannerLimit%2ClegacySupport%2CstartUp%7Cext.centralauth.centralautologin%7Cext.eventLogging%7Cext.eventLogging.subscriber%7Cext.quicksurveys.init%2Clib%7Cext.uls.init%2Cinterface%2Cpreferences%2Cwebfonts%7Cext.visualEditor.desktopArticleTarget.init%7Cext.visualEditor.supportCheck%2Ctrack%2Cve%7Cjquery.byteLength%2Ccookie%2CembedPlayer%2CloadingSpinner%2CmwEmbedUtil%2CtabIndex%2Cthrottle-debounce%2CtriggerQueueCallback%7Cmediawiki.Title%2CUri%2Capi%2Ccldr%2Ccookie%2Cexperiments%2CjqueryMsg%2Clanguage%2Cstorage%2Ctemplate%2Cuser%7Cmediawiki.api.options%2Cuser%7Cmediawiki.language.data%2Cinit%7Cmediawiki.libs.pluralruleparser%7Cmediawiki.page.startup%7Cmediawiki.template.regexp%7Cmmv.head%7Cmw.EmbedPlayer.loader%7Cmw.MediaWikiPlayer.loader%7Cmw.MwEmbedSupport%2CPopUpMediaTransform%7Cmw.MwEmbedSupport.style%7Cmw.PopUpMediaTransform.styles%7Cmw.TimedText.loader%7Cschema.QuickSurveyInitiation%7Cskins.vector.js%7Cuser.defaults&skin=vector&version=d9de2fc9ce0c :: mw.centralNotice.kvStore.setItem :: line 45" data: no]',
66 u'Couldn\'t write value due to LocalStorage exception [Exception... "File error: No device space" nsresult: "0x80520010 (NS_ERROR_FILE_NO_DEVICE_SPACE)" location: "JS frame :: https://en.wikipedia.org/w/load.php?debug=false&lang=en&modules=Spinner%7Cext.centralNotice.bannerController%2CbannerHistoryLogger%2CchoiceData%2Cdisplay%2CgeoIP%2CimpressionDiet%2CkvStore%2CkvStoreMaintenance%2ClargeBannerLimit%2ClegacySupport%2CstartUp%7Cext.centralauth.centralautologin%7Cext.eventLogging%7Cext.eventLogging.subscriber%7Cext.quicksurveys.init%2Clib%7Cext.uls.init%2Cinterface%2Cpreferences%2Cwebfonts%7Cext.visualEditor.desktopArticleTarget.init%7Cext.visualEditor.supportCheck%2Ctrack%2Cve%7Cjquery.byteLength%2Ccookie%2CembedPlayer%2CloadingSpinner%2CmwEmbedUtil%2CtabIndex%2Cthrottle-debounce%2CtriggerQueueCallback%7Cmediawiki.Title%2CUri%2Capi%2Ccldr%2Ccookie%2Cexperiments%2CjqueryMsg%2Clanguage%2Cstorage%2Ctemplate%2Cuser%7Cmediawiki.api.options%2Cuser%7Cmediawiki.language.data%2Cinit%7Cmediawiki.libs.pluralruleparser%7Cmediawiki.page.startup%7Cmediawiki.template.regexp%7Cmmv.head%7Cmw.EmbedPlayer.loader%7Cmw.MediaWikiPlayer.loader%7Cmw.MwEmbedSupport%2CPopUpMediaTransform%7Cmw.MwEmbedSupport.style%7Cmw.PopUpMediaTransform.styles%7Cmw.TimedText.loader%7Cschema.QuickSurveyInitiation%7Cskins.vector.js%7Cuser.defaults&skin=vector&version=d9de2fc9ce0c :: mw.centralNotice.kvStore.setItem :: line 45" data: no]',
67 u"Couldn't write value due to LocalStorage exception QuotaExceededError",
68 u'LocalStorage not available.',
69 u'LocalStorage not available.',
70 u"Couldn't write value due to LocalStorage exception Error: QuotaExceededError: DOM Exception 22",
71 u'LocalStorage not available.']

Main questions that I hope we can answer (in view of the above data):

  • Do we need to fall back to cookies for users for whom LocalStorage doesn't work?
  • If we do need to fall back to cookies, for which features do we need to do so?
  • For any features that don't fall back to cookies, what should the banner/campaign functionality be for users without LocalStorage?

Generally, the data shows that only a small percentage of users who ever see banners have problems with LocalStorage. It's probably less than 1%.

(Specifically, it says: Of all users who were targeted by Fundraising campaigns over the last 90 days, who may see banners due to their browsers being compatible with our Javascript, and who don't have Do Not Track enabled in their browsers, probably less than 1% had issues with LocalStorage.)

Here are the features that currently rely on cookies, and that we can consider switching to LocalStorage:

  • Bucketing (all campaigns) The "CN" cookie stores which bucket a user is in for each campaign.
  • Impression limiting (FR only) For FR only, the impressionDiet mixin uses cookies to count how many banners a user has seen. Non-FR campaigns already use LocalStorage.
  • Large banner limiting (FR only) For FR only, the largeBannerLimit mixin uses a cookie to record if a user has seen a large banner. AFIK, non-FR campaigns don't use this feature.

(Two other CentralNotice features also use cookies: GeoIP, and temporarily hiding banners after a user clicks the "close" button. I don't think we should consider switching these features to LocalStorage yet. Regarding the first, GeoIP is used far beyond CentralNotice; changes there should be part of a wider discussion about removing it from CentralNotice. Regarding hiding banners, we can't easily move to LocalStorage because our current way of hiding banners over multiple sites won't work. Instead, I think, we need to look at redoing the whole hide cookie system.)

tl;dr: For bucketing, impression limiting, and large banner limiting, I think we should decide whether a fallback to cookies is needed, and, for any of those features that don't get a cookie fallback, what the functionality should be for users without LocalStorage. That's probably less than 1% of users who currently see banners.

Thanks!!! :)

Some specific proposals, regarding the points just described:

Proposal A

  • For bucketing, use LocalStorage, or fall back to a cookie if necessary, on all campaigns.
  • For impression limiting and large banner limiting, use LocalStorage, or fall back to cookies if necesssary, only on FR campaigns.
  • On non-FR campaigns, follow existing default behaviour for impression limiting and hiding large banners for users without LocalStorage (i.e., in the case of the former, don't show any banners to those users if impressions are being limited, or never show large banner to those users).

Proposal B

  • Don't use any cookie fallback. Only serve banners to users with LocalStorage. Don't worry about the less than 1% of users who don't have it.

Proposal C

  • Don't use any cookie fallback. For users without LocalStorage: always just use bucket A (but record that this was the case via /beacon/impression, so those users don't mess up A/B test data), show banners randomly some % of the time if banners are being limited, and never show large banners).

Proposal D

  • Some combination of the above.

Proposal B is really tempting for consistency. For 'emergency' notifications, are we doing anything to display messages to the javascript-less?

If a 0.65% banner decline is disturbing to fr-all, I'd say go with proposal C. Since we're not touching the hide cookies, we'll at least still quit nagging when people donate.

One other important use of cookies that I don't think was mentioned: long term hiding (250 days) after a user donates.

I think fundraising would be okay just not showing banners for those without working LocalStorage if it's < 1% (Proposal B). However what's the situation with "Do Not Track"? Do we have any idea how many people that is, and what we do for them at the moment?

One other important use of cookies that I don't think was mentioned: long term hiding (250 days) after a user donates.

Ah yes, right! That works almost the same as the hiding when you click on close. In a nutshell, we should leave all "hide" cookies alone for now. (These are the cookies that start with "centralnotice_hide_" and are processed by ext.centralNotice.display.hide.js.)

I think fundraising would be okay just not showing banners for those without working LocalStorage if it's < 1% (Proposal B). However what's the situation with "Do Not Track"? Do we have any idea how many people that is, and what we do for them at the moment?

Currently, the only functionality that changes with "Do Not Track" is banner history (it gets disabled and doesn't send us anything). Since the estimate about LocalStorage availability comes from banner history logs, it can't tell us about those users. However, I don't know any reason users with Do Not Track enabled would have a different rate of LocalStorage availability.

If we go with Proposal B, maybe we could add a data point to /beacon/impression to report when a doesn't have LocalStorage. That way we could monitor the percentage of users left out.

I should also say that Proposal A, while a little more complex, is not at all onerous, and would help site performance just as much as Proposal B for about 99% of users.

Finally: the estimate on LocalStorage availability does have limitations. I haven't broken it down by device type, and it only covers countries where we've fundraised recently. It's possible that for some constituencies (say, maybe, mobile devices in some countries?) the percentage is a bit higher.

Patches for review for T132639 follow Proposal A.

To do this, added limited, optional cookie-based fallback to kvStore...

The main disadvantage that I see so far is that the ext.centralNotice.kvStore RL module is now a dependency of ext.centralNotice.display, which means that it will be loaded for any user for whom there are possible campaigns in choiceData. I can think of a possible way to avoid that, however... (that is... don't store buckets for campaigns with only one bucket, and only load kvStore for users with possible campaigns with more than one bucket in choiceData...) See also T133741.

Closing, since the patches that implement this plan have merged. (See T132639 and T132640.)