From 9971ac8b30f6d6990b51dcfd0578556c5ac8192b Mon Sep 17 00:00:00 2001 From: Tom Wey Date: Fri, 7 Nov 2025 09:17:02 +0000 Subject: [PATCH 1/3] Extend expiry of user benefits cookies to 30 days Previouly they were short lived (1-2 days) but this resulted in edge cases where if a signed in user didn't visit the site for more than a couple of days, when they returned their first page view wouldn't reflect their benefits (i.e. they would see ads). This is due to a race condition between the user benefits refresh and the ads code. However, we don't want to delay ads until after the user benefits have been refreshed as that would impact performance. So instead, extend the expiry of the cookie. Note: this may result in a user getting benefits they no longer have on the first returning pageview, but this will be correct from the second page view onwards. We think this is OK. This also means we now remove cookies if the user benefits response says they no longer have the benefit, rather than simply letting the cookie expire. --- .../src/client/userFeatures/user-features.ts | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/dotcom-rendering/src/client/userFeatures/user-features.ts b/dotcom-rendering/src/client/userFeatures/user-features.ts index 6648e62e1e1..2e2a57de34b 100644 --- a/dotcom-rendering/src/client/userFeatures/user-features.ts +++ b/dotcom-rendering/src/client/userFeatures/user-features.ts @@ -4,6 +4,7 @@ * https://github.com/guardian/commercial/blob/1a429d6be05657f20df4ca909df7d01a5c3d7402/src/lib/user-features.ts */ +import { removeCookie } from '@guardian/libs'; import { getAuthStatus, isUserLoggedIn } from '../../lib/identity'; import { AD_FREE_USER_COOKIE } from './cookies/adFree'; import { ALLOW_REJECT_ALL_COOKIE } from './cookies/allowRejectAll'; @@ -48,16 +49,36 @@ const requestNewData = async () => { */ const persistResponse = (userBenefitsResponse: UserBenefits) => { createOrRenewCookie(USER_BENEFITS_EXPIRY_COOKIE); + + // All of these user benefits cookies are now valid for 30 days. Previously + // they were short lived (1-2 days) but this resulted in edge cases where if + // a signed in user didn't visit the site for more than a couple of days + // when they returned their first page view wouldn't reflect their benefits + // (i.e. they would see ads). This is due to a race condition between the + // user benefits refresh and the ads code. However, we don't want to delay + // ads until after the user benefits have been refreshed as that would + // impact performance. So instead, extend the expiry of the cookie. Note: + // this may result in a user getting benefits they no longer have on the + // first returning pageview, but this will be correct from the second page + // view onwards. We think this is OK. This also means we now remove cookies + // if the user benefits response says they no longer have the benefit, + // rather than simply letting the cookie expire. if (userBenefitsResponse.hideSupportMessaging) { - createOrRenewCookie(HIDE_SUPPORT_MESSAGING_COOKIE); + createOrRenewCookie(HIDE_SUPPORT_MESSAGING_COOKIE, 30); + } else { + removeCookie({ name: HIDE_SUPPORT_MESSAGING_COOKIE }); } + if (userBenefitsResponse.allowRejectAll) { - createOrRenewCookie(ALLOW_REJECT_ALL_COOKIE); + createOrRenewCookie(ALLOW_REJECT_ALL_COOKIE, 30); + } else { + removeCookie({ name: ALLOW_REJECT_ALL_COOKIE }); } - // Ad free cookie has an expiry of 2 days from now - // See https://github.com/guardian/gateway/blob/52f810a88fa9ce23c6a794916251748718742c3d/src/server/lib/user-features.ts#L111-L115 + if (userBenefitsResponse.adFree) { - createOrRenewCookie(AD_FREE_USER_COOKIE, 2); + createOrRenewCookie(AD_FREE_USER_COOKIE, 30); + } else { + removeCookie({ name: AD_FREE_USER_COOKIE }); } }; From b049399ae8ea3730c4792e2a95b71f5e4771041e Mon Sep 17 00:00:00 2001 From: Tom Wey Date: Fri, 7 Nov 2025 09:31:47 +0000 Subject: [PATCH 2/3] Extract const --- .../src/client/userFeatures/user-features.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/dotcom-rendering/src/client/userFeatures/user-features.ts b/dotcom-rendering/src/client/userFeatures/user-features.ts index 2e2a57de34b..8c8eeb57690 100644 --- a/dotcom-rendering/src/client/userFeatures/user-features.ts +++ b/dotcom-rendering/src/client/userFeatures/user-features.ts @@ -37,6 +37,8 @@ const requestNewData = async () => { return syncDataFromUserBenefitsApi(authStatus).then(persistResponse); }; +const USER_BENEFITS_COOKIE_EXPIRATION_IN_DAYS = 30; + /** * Persist the user benefits response to cookies * @@ -64,19 +66,28 @@ const persistResponse = (userBenefitsResponse: UserBenefits) => { // if the user benefits response says they no longer have the benefit, // rather than simply letting the cookie expire. if (userBenefitsResponse.hideSupportMessaging) { - createOrRenewCookie(HIDE_SUPPORT_MESSAGING_COOKIE, 30); + createOrRenewCookie( + HIDE_SUPPORT_MESSAGING_COOKIE, + USER_BENEFITS_COOKIE_EXPIRATION_IN_DAYS, + ); } else { removeCookie({ name: HIDE_SUPPORT_MESSAGING_COOKIE }); } if (userBenefitsResponse.allowRejectAll) { - createOrRenewCookie(ALLOW_REJECT_ALL_COOKIE, 30); + createOrRenewCookie( + ALLOW_REJECT_ALL_COOKIE, + USER_BENEFITS_COOKIE_EXPIRATION_IN_DAYS, + ); } else { removeCookie({ name: ALLOW_REJECT_ALL_COOKIE }); } if (userBenefitsResponse.adFree) { - createOrRenewCookie(AD_FREE_USER_COOKIE, 30); + createOrRenewCookie( + AD_FREE_USER_COOKIE, + USER_BENEFITS_COOKIE_EXPIRATION_IN_DAYS, + ); } else { removeCookie({ name: AD_FREE_USER_COOKIE }); } From 5179c55d071e134ea66ae85e65a42f7d5f64bc2b Mon Sep 17 00:00:00 2001 From: Tom Wey Date: Mon, 1 Dec 2025 12:22:51 +0000 Subject: [PATCH 3/3] Update comment --- dotcom-rendering/src/client/userFeatures/user-features.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dotcom-rendering/src/client/userFeatures/user-features.ts b/dotcom-rendering/src/client/userFeatures/user-features.ts index 8c8eeb57690..14c07ac2ab4 100644 --- a/dotcom-rendering/src/client/userFeatures/user-features.ts +++ b/dotcom-rendering/src/client/userFeatures/user-features.ts @@ -42,11 +42,11 @@ const USER_BENEFITS_COOKIE_EXPIRATION_IN_DAYS = 30; /** * Persist the user benefits response to cookies * - * If new cookies are added/removed/edited, update the persistUserBenefitsCookie function in Gateway - * https://github.com/guardian/gateway/blob/252b2b2f24be826da42c6e7c1b1e202594184023/src/server/lib/user-features.ts#L88 - * + * If new cookies are added/removed/edited, update the persistUserBenefitsCookies function in Gateway. * In gateway, the cookies are set after authentication. * + * This code also exist in frontend, so any changes here should be mirrored there. + * * @param {UserBenefits} userBenefitsResponse */ const persistResponse = (userBenefitsResponse: UserBenefits) => {