https://github.com/transferwise/mitosis
A/B split filter
https://github.com/transferwise/mitosis
ab-testing filter
Last synced: about 1 year ago
JSON representation
A/B split filter
- Host: GitHub
- URL: https://github.com/transferwise/mitosis
- Owner: transferwise
- License: apache-2.0
- Archived: true
- Created: 2016-11-03T18:44:39.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2024-04-04T23:41:39.000Z (about 2 years ago)
- Last Synced: 2025-03-03T04:44:56.001Z (over 1 year ago)
- Topics: ab-testing, filter
- Language: Groovy
- Size: 93.8 KB
- Stars: 2
- Watchers: 115
- Forks: 4
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# Mitosis [](https://circleci.com/gh/transferwise/mitosis/tree/master)
A/B traffic split servlet filter.
## Installation
Just add the following configuration to your `build.gradle` file
```gradle
allprojects {
repositories {
maven { url 'https://jitpack.io' }
}
}
dependencies {
compile 'com.github.transferwise:mitosis:1.1.0'
}
```
## Configuration
If we wanted to [uniformly distribute](https://en.wikipedia.org/wiki/Uniform_distribution_(continuous)) `a` and `b` variants for an experiment `test` across the requests of our application, the configuration would be
```java
@Bean
public Filter experimentFilter() {
return ExperimentFilter.builder().build()
.prepare(new UserExperiment("test", asList(["a", "b"])));
}
```
If we wanted to uniformly distribute `a` and `b` variants for an experiment `test` across the request *paths* of our application, the configuration would be
```java
public Filter experimentFilter() {
return ExperimentFilter.builder().build()
.prepare(new SeoExperiment("test", asList(["a", "b"])));
}
```
For a SeoExperiment a given path will always return the same variant (unless overridden by request parameters).
## Usage
In Spring controllers.
```java
@RequestMapping("/do-something")
public String doSomething(@RequestAttribute("experiments") Map experiments) {
if (experiments.get("test").equals("a")) {
return goForVariantA();
}
if (experiments.get("test").equals("b")) {
return goForVariantB();
}
}
```
In Thymeleaf templates.
```html
This is the A version
This is the B version
var experiments = [[${experiments}]];
if (experiments['test'] === 'a') {
goForVariantA();
}
if (experiments['test'] === 'b') {
goForVariantB();
}
```
## Forcing an experiment variant
Variants are uniformly distributed automatically. A way of forcing a specific experiment variant, so you can share and preview the experiment, is to pass the preferred variant as a request parameter.
In an experiment configuration like the following
```java
@Bean
public Filter experimentFilter() {
return ExperimentFilter.builder().build()
.prepare(new UserExperiment("test1", asList("a", "b")))
.prepare(new UserExperiment("test2", asList("c", "d")));
}
```
You can force the test `test1` to variant `b` by setting the `activate` query parameter in the following way
https://yoursite.com/?activate=test1:b
Worth mentioning that if you have multiple experiments running and you want to force multiple variants you can do
https://yoursite.com/?activate=test1:b,test2:c
## Advanced use
You can use lambda functions to create more complex filters, so you will split your traffic only under controlled circumstances.
Let's imagine you want to run your test only for people visiting some urls starting with "/path":
```java
@Bean
public Filter experimentFilter() {
return ExperimentFilter.builder().build()
.prepare("test", asList("a", "b"), r -> r.getRequestURI().contains("/path"));
}
```
When using lambda functions, the experiment variant will be assigned only if the function returns `true`. **Otherwise, no variant will be assigned**, so you need to handle within your logic.
Mitosis provides a handful request filters that can be combined at will. If we wanted to assign variants only to english-speaking users, excluding Googlebot crawler so our experiment won't affect SEO, we can configure the experiment in the following way
```java
filter.prepare("test", asList("a", "b"), languageEquals("en").and(userAgentContains("googlebot").negate()));
```
## Cookie Consent
When building the experiment filter you may optionally configure a cookie consent check.
If a cookie with the cookie consent cookie name does not exist then mitosis will not set any cookies.
If a cookie with the cookie consent cookie name does exist but the value of that cookie does not match the regex provided, mitosis will not set any cookies.
Note that user experiments rely on cookies so may only be run on users who have accepted the cookie consent. SEO experiments do not rely on cookies.
If a cookie with the cookie consent cookie name does exist and the value of that cookie matches the regex provided, mitosis will operate as normal.
```java
@Bean
public Filter experimentFilter() {
return ExperimentFilter.builder()
.cookieConsent("consentCookie", "^1$")
.build()
.prepare("test", asList("a", "b"));
}
```