Skip to content

Conversation

@dskamiotis
Copy link
Contributor

@dskamiotis dskamiotis commented Nov 20, 2025

What does this change?

Adds URL parameter support to the beta AB testing framework, allowing developers to force themselves into AB tests using ?ab-TestName=variant

Implementation:

New Middleware (add-queryparams-to-abtests.ts)
Middleware runs after getContentFromURLMiddleware (which fetches article JSON)

Middleware runs before handleArticle (which renders the HTML)

  • Extracts AB test assignments from query parameters (e.g., ?ab-myTest=variant)
  • Filters for params starting with ab- prefix
  • Strips the ab- prefix to match hash/cookie naming convention
  • Adds them to config.serverSideABTests before rendering
  • Integration (server.dev.ts)

Why?

The beta AB framework had no way to force test participation during development, making it difficult to test features gated behind AB tests locally.

Essentially the getParticipations function checks the participations object of the beta ab framework to see if the user is in the test. We are circumventing this by forcing the test name in to the window.guardian.config.serverSideABTests locally

We currently do this in the Legacy ab-core and would like to include this useful development feature in the beta ab testing on localhost:3030/

✅ Force participation on localhost:3030/article#ab-MyTest=variant
✅ Override production assignments for debugging
✅ Multiple tests: ?ab-Test1=variant, ?ab-Test2=control
✅ Priority: URL > Server > Cookie
✅ No breaking changes to existing code

Screenshots

To Test I added console logs to see the participations:

const betaAB = useBetaAB();
console.log('🧪🧪 AB Test Participations:', betaAB?.getParticipations());
console.log('🧪🧪 In MyTest variant?', betaAB?.isUserInTestGroup('MyTest', 'variant'));
console.log('🧪🧪 In MyTest control?', betaAB?.isUserInTestGroup('MyTest', 'control'));

using Localhost with #ab-MyTest=control: http://localhost:3030/Article/https://www.theguardian.com/sport/2023/nov/22/ronnie-osullivan-warns-he-will-quit-snooker-if-he-cannot-play-in-china#ab-MyTest=control

Control #ab-MyTest=control Variant #ab-MyTest=variant
Cookie participations URL override
Screenshot 2025-11-20 at 11 01 02 Screenshot 2025-11-20 at 11 00 12

document.cookie = "gu_client_ab_tests=TestA:control,TestB:variant; path=/";

Without URL Fragment With URL Fragment
Cookie participations URL override (#ab-TestA=variant)
Screenshot 2025-11-20 at 11 25 37 Screenshot 2025-11-20 at 11 26 53
Multiple tests from cookie URL overrides multiple specific test: #ab-TestA=variant,ab-TestB=variant
Screenshot 2025-11-20 at 11 31 12 Screenshot 2025-11-20 at 11 44 04

@github-actions
Copy link

Hello 👋! When you're ready to run Chromatic, please apply the run_chromatic label to this PR.

You will need to reapply the label each time you want to run Chromatic.

Click here to see the Chromatic project.

@github-actions
Copy link

github-actions bot commented Nov 20, 2025

@dskamiotis dskamiotis added the run_chromatic Runs chromatic when label is applied label Nov 20, 2025
@github-actions github-actions bot removed the run_chromatic Runs chromatic when label is applied label Nov 20, 2025
@dskamiotis dskamiotis requested a review from a team November 20, 2025 10:52
@dskamiotis dskamiotis force-pushed the ds/force-ab-test-participation-in-development branch from f2a97cf to 48f1822 Compare November 20, 2025 11:53
@github-actions
Copy link

github-actions bot commented Nov 20, 2025

@dskamiotis dskamiotis force-pushed the ds/force-ab-test-participation-in-development branch from 48f1822 to 73df669 Compare November 20, 2025 12:58
@Jakeii
Copy link
Member

Jakeii commented Nov 20, 2025

This will work for client side code but not server side code - may lead to confusion? hash fragments aren't visible to the server so would need a different way to opt in

@dskamiotis dskamiotis requested a review from a team as a code owner November 24, 2025 09:58
@dskamiotis dskamiotis force-pushed the ds/force-ab-test-participation-in-development branch 2 times, most recently from 934fc7c to 3051ace Compare November 24, 2025 11:44
@dskamiotis dskamiotis force-pushed the ds/force-ab-test-participation-in-development branch 4 times, most recently from a8f9528 to c1854cf Compare November 25, 2025 10:22
@dskamiotis dskamiotis force-pushed the ds/force-ab-test-participation-in-development branch from 216d6e9 to 22dfe45 Compare November 26, 2025 20:26
@dskamiotis dskamiotis added the run_chromatic Runs chromatic when label is applied label Nov 27, 2025
@github-actions github-actions bot removed the run_chromatic Runs chromatic when label is applied label Nov 27, 2025
@dskamiotis dskamiotis force-pushed the ds/force-ab-test-participation-in-development branch from 22dfe45 to 2e573bc Compare November 27, 2025 10:14
@dskamiotis dskamiotis added the run_chromatic Runs chromatic when label is applied label Nov 27, 2025
@github-actions github-actions bot removed the run_chromatic Runs chromatic when label is applied label Nov 27, 2025
@dskamiotis dskamiotis force-pushed the ds/force-ab-test-participation-in-development branch from 2e573bc to 87633f9 Compare December 1, 2025 11:32
@dskamiotis dskamiotis added the run_chromatic Runs chromatic when label is applied label Dec 1, 2025
@github-actions github-actions bot removed the run_chromatic Runs chromatic when label is applied label Dec 1, 2025
@Jakeii
Copy link
Member

Jakeii commented Dec 1, 2025

Could we add to the readme's with how to opt in locally?

};
req.body = frontendData;
} catch (error) {
return next();
Copy link
Member

Choose a reason for hiding this comment

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

We should log the error here, to help resolve issues if people don't format their params quite right!


export const getABTestsFromQueryParams: Handler = async (req, res, next) => {
try {
const frontendData = validateAsFEArticle(req.body);
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this will work for other page types, Fronts etc.

Copy link
Contributor

@on-ye on-ye left a comment

Choose a reason for hiding this comment

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

This needs a re-review as this has changed since I first reviewed. See Jake's comments

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants