{"id":16758415,"url":"https://github.com/kessler/pickpick","last_synced_at":"2025-06-19T00:08:04.227Z","repository":{"id":57323917,"uuid":"140909169","full_name":"kessler/pickpick","owner":"kessler","description":"An A/B testing engine","archived":false,"fork":false,"pushed_at":"2024-02-19T15:10:44.000Z","size":167,"stargazers_count":37,"open_issues_count":3,"forks_count":6,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-06-15T16:08:01.400Z","etag":null,"topics":["ab-testing","javascript","node-module","nodejs","nodejs-modules","npm-module","npm-package"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kessler.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-07-14T02:20:33.000Z","updated_at":"2024-04-21T12:13:01.000Z","dependencies_parsed_at":"2024-06-07T06:03:53.207Z","dependency_job_id":null,"html_url":"https://github.com/kessler/pickpick","commit_stats":null,"previous_names":["ironsource/pickpick"],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/kessler/pickpick","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kessler%2Fpickpick","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kessler%2Fpickpick/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kessler%2Fpickpick/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kessler%2Fpickpick/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kessler","download_url":"https://codeload.github.com/kessler/pickpick/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kessler%2Fpickpick/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260654685,"owners_count":23042679,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ab-testing","javascript","node-module","nodejs","nodejs-modules","npm-module","npm-package"],"created_at":"2024-10-13T04:05:14.291Z","updated_at":"2025-06-19T00:07:59.215Z","avatar_url":"https://github.com/kessler.png","language":"JavaScript","readme":"# ANNOUCEMENT: repository changing ownership\nOn the 16th of March 2024 this repository will change ownership and move to the personal account of one of it's maintainers, [Yaniv Kessler](https://github.com/kessler)\n\nOwnership change will also occur on the npm registry to [Yaniv Kessler](https://www.npmjs.com/~kessler)\n\n# pickpick\n\nAn A/B testing engine\n\n[![CircleCI](https://img.shields.io/circleci/project/github/ironSource/pickpick.svg)](https://circleci.com/gh/ironSource/pickpick)\n[![Coverage Status](https://coveralls.io/repos/github/ironSource/pickpick/badge.svg?branch=master)](https://coveralls.io/github/ironSource/pickpick?branch=master)\n[![npm latest version](https://img.shields.io/npm/v/pickpick.svg)](https://www.npmjs.com/package/pickpick)\n\nTo use this engine, create one or more experiments and stick them in a container. Each experiment is composed of a bunch of variations which are randomly picked/served to you. Once you obtain a variation, use it to render some content or make some sort of a decision.\n\nThe container's job is to select the correct experiments for each `visitor` based on each experiment's targeting expression. Thusly, to get a variation one would call `pick()` twice, once on the container and once on the experiment.\n\nFurther information about the targeting experssion syntax can be found here: [pickpick-targeting-compiler](https://github.com/ironSource/pickpick-targeting-compiler)\n\nAlso, please take a look at our [examples](./examples)\n\n## example\n\n`npm i -S pickpick`\n\nLet's say we have a website with two pages `buy` and `index` and we want to run 3 experiments:\n\n-   on the `buy` page test `color button`\n-   on the `buy` page test `price`\n-   on the `index` page test `text`\n\n```js\nconst { Experiment, ExperimentContainer } = require('pickpick')\n\n// first create the experiments:\n\nlet e1 = Experiment.create({\n\tname: 'buy page button color experiment',\n\tid: '953d6fe0',\n\tvariations: [\n\t\t{ object: '#ff0000', weight: 4 },\n\t\t{ object: '#ff0000', weight: 1 },\n\t\t{ object: '#00ff00', weight: 1 }\n\t],\n\ttargeting: '_.path in [\"buy\", \"index\"]'\n})\n\nlet e2 = Experiment.create({\n\tname: 'buy page price experiment',\n\tid: 'a40f09ac',\n\tvariations: [\n\t\t{ object: 25 },\n\t\t{ object: 35 },\n\t\t{ object: 45 }\n\t],\n\ttargeting: '_.path !== \"home\" \u0026\u0026 page !== \"foo\"'\n})\n\nlet e3 = Experiment.create({\n\tname: 'index text experiment',\n\tid: 'ac49ef42',\n\tvariations: [\n\t\t{ object: 'hi' },\n\t\t{ object: 'hello' },\n\t\t{ object: 'welcome' }\n\t],\n\ttargeting: '_.path === \"index\"'\n})\n\n// now create a container:\nlet experiments = [e1, e2, e3]\nlet container = ExperimentContainer.create({ experiments })\n\n// simulate a visitor that needs a determination about which variation of which experiment he gets:\nlet visitor = { page: 'index' }\nfor (let i = 0; i \u003c 10; i++) {\n\tlet experiment = container.pick(visitor)\n\n\tif (!experiment) {\n\t\t// no experiment that targets this user\n\t\t// handle this with defaults\n\t\tconsole.log('default goes here')\n\t} else {\n\n\t\tconsole.log(`selected experiment '${experiment.name}' for '${JSON.stringify(visitor)}'`)\n\t\tlet variation = experiment.pick()\n\t\tconsole.log(`selected variation is ${variation}`)\n\t}\n}\n```\n\n## API\n\n\u003c!-- Generated by documentation.js. Update this documentation by updating the source code. --\u003e\n\n#### Table of Contents\n\n-   [Experiment](#experiment)\n    -   [Parameters](#parameters)\n    -   [pick](#pick)\n    -   [match](#match)\n        -   [Parameters](#parameters-1)\n    -   [add](#add)\n        -   [Parameters](#parameters-2)\n    -   [iterator](#iterator)\n-   [Targeting](#targeting)\n    -   [Parameters](#parameters-3)\n    -   [match](#match-1)\n        -   [Parameters](#parameters-4)\n    -   [expression](#expression)\n    -   [iterator](#iterator-1)\n    -   [has](#has)\n        -   [Parameters](#parameters-5)\n-   [Variation](#variation)\n    -   [Parameters](#parameters-6)\n-   [ExperimentContainer](#experimentcontainer)\n    -   [Parameters](#parameters-7)\n    -   [add](#add-1)\n        -   [Parameters](#parameters-8)\n    -   [pick](#pick-1)\n        -   [Parameters](#parameters-9)\n    -   [targetingFeatures](#targetingfeatures)\n    -   [iterator](#iterator-2)\n    -   [has](#has-1)\n        -   [Parameters](#parameters-10)\n    -   [hasId](#hasid)\n        -   [Parameters](#parameters-11)\n    -   [toJSON](#tojson)\n\n### Experiment\n\n[lib/Experiment.js:34-171](https://git@github.com/:ReasonSoftware/pickpick/blob/a6938cd996f3f68216a96b210bf576e6e3ff6ece/lib/Experiment.js#L34-L171 \"Source code on GitHub\")\n\nAn A/B test experiment contains one or more [variations](@Variation) and a definition of [targeting](@Targeting).\n\n   Experiments are serializable and can be created using classes from this engine or object literals. For example:\n\n```js\nconst { Experiment } = require('pickpick')\n\nconst e1 = Experiment.create({\n\tname: 'my experiment',\n\tid: 'foo',\n\tvariations: [\n\t\t{ object: 1, weight: 1 },\n\t\t{ object: 2, weight: 1 },\n\t\t{ object: 3, weight: 1 }\n\t],\n\ttargeting: '_.geo === \"US\"'\n})\n```\n\n#### Parameters\n\n-   `$0` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** \n    -   `$0.name`  \n    -   `$0.id`  \n    -   `$0.variations`   (optional, default `[]`)\n    -   `$0.targeting`   (optional, default `Targeting.default()`)\n    -   `$0.userData`  \n\n#### pick\n\n[lib/Experiment.js:66-68](https://git@github.com/:ReasonSoftware/pickpick/blob/a6938cd996f3f68216a96b210bf576e6e3ff6ece/lib/Experiment.js#L66-L68 \"Source code on GitHub\")\n\nrandomly select one variation from the Variations set\n\nReturns **Variant** the value contained within the selected variation\n\n#### match\n\n[lib/Experiment.js:76-78](https://git@github.com/:ReasonSoftware/pickpick/blob/a6938cd996f3f68216a96b210bf576e6e3ff6ece/lib/Experiment.js#L76-L78 \"Source code on GitHub\")\n\ncheck if this experiment matches the input targeting\n\n##### Parameters\n\n-   `targeting` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** \n\nReturns **[Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** \n\n#### add\n\n[lib/Experiment.js:84-95](https://git@github.com/:ReasonSoftware/pickpick/blob/a6938cd996f3f68216a96b210bf576e6e3ff6ece/lib/Experiment.js#L84-L95 \"Source code on GitHub\")\n\nadd another variation to this experiment\n\n##### Parameters\n\n-   `variation` **([Variation](#variation) \\| [Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object))** \n\n#### iterator\n\n[lib/Experiment.js:116-118](https://git@github.com/:ReasonSoftware/pickpick/blob/a6938cd996f3f68216a96b210bf576e6e3ff6ece/lib/Experiment.js#L116-L118 \"Source code on GitHub\")\n\niterate over the variations contained in this experiment\n\n### Targeting\n\n[lib/Targeting.js:11-80](https://git@github.com/:ReasonSoftware/pickpick/blob/a6938cd996f3f68216a96b210bf576e6e3ff6ece/lib/Targeting.js#L11-L80 \"Source code on GitHub\")\n\nTargeting\n\n#### Parameters\n\n-   `expression` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** see [pickpick-targeting-compiler](https://github.com/ironSource/pickpick-targeting-compiler) for more details\n-   `userEnvironment` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)**  (optional, default `{}`)\n\n#### match\n\n[lib/Targeting.js:31-39](https://git@github.com/:ReasonSoftware/pickpick/blob/a6938cd996f3f68216a96b210bf576e6e3ff6ece/lib/Targeting.js#L31-L39 \"Source code on GitHub\")\n\ncheck if the input data is matched by this targeting instance\n\n##### Parameters\n\n-   `inputTargeting` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** is normally a simple js object\n\nReturns **[Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** \n\n#### expression\n\n[lib/Targeting.js:45-47](https://git@github.com/:ReasonSoftware/pickpick/blob/a6938cd996f3f68216a96b210bf576e6e3ff6ece/lib/Targeting.js#L45-L47 \"Source code on GitHub\")\n\naccess this Targeting's expression\n\nReturns **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** \n\n#### iterator\n\n[lib/Targeting.js:52-54](https://git@github.com/:ReasonSoftware/pickpick/blob/a6938cd996f3f68216a96b210bf576e6e3ff6ece/lib/Targeting.js#L52-L54 \"Source code on GitHub\")\n\niterate over the features that participate in the targeting\n\n#### has\n\n[lib/Targeting.js:61-63](https://git@github.com/:ReasonSoftware/pickpick/blob/a6938cd996f3f68216a96b210bf576e6e3ff6ece/lib/Targeting.js#L61-L63 \"Source code on GitHub\")\n\ncheck if a feature is part of this targeting instance\n\n##### Parameters\n\n-   `feature` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** a name of a feature, e.g `geo`\n\nReturns **[Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** \n\n### Variation\n\n[lib/Variation.js:9-99](https://git@github.com/:ReasonSoftware/pickpick/blob/a6938cd996f3f68216a96b210bf576e6e3ff6ece/lib/Variation.js#L9-L99 \"Source code on GitHub\")\n\nA variation attaches weight to a piece of data. Variations are used in Experiments and ExperimentContainers\n\n#### Parameters\n\n-   `$0` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** \n    -   `$0.object`  \n    -   `$0.weight`   (optional, default `1`)\n\n### ExperimentContainer\n\n[lib/ExperimentContainer.js:38-239](https://git@github.com/:ReasonSoftware/pickpick/blob/a6938cd996f3f68216a96b210bf576e6e3ff6ece/lib/ExperimentContainer.js#L38-L239 \"Source code on GitHub\")\n\nContains one or more experiments and routes traffic evenly to each of them based on their\n   targeting. The following is an example of using a container to host several experiments, pick\n   on thats appropriate for a single visitor's targeting and then access a variation from the\n   selected experiment:\n\n```js\nconst { ExperimentContainer, Experiment } = require('pickpick')\n\nconst experiments = [\n\t\tExperiment.create(...),\n\t\tExperiment.create(...),\n\t\tExperiment.create(...)\n]\n\nconst container = ExperimentContainer.create({ experiments })\n\nlet experiment = container.pick({ geo: 'US', page: 'index.html '})\nif (experiment) {\n\tlet variation = experiment.pick()\n\t// do something with the variation data\n} else {\n\tconsole.log('no experiments that match this targeting were found')\n}\n```\n\n#### Parameters\n\n-   `__seed` **[number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)** just for testing / predictable engine results\n\n#### add\n\n[lib/ExperimentContainer.js:77-102](https://git@github.com/:ReasonSoftware/pickpick/blob/a6938cd996f3f68216a96b210bf576e6e3ff6ece/lib/ExperimentContainer.js#L77-L102 \"Source code on GitHub\")\n\nAdd an experiment to this container. Inside a container experiments must\nhave unique ids. This method can accept different kinds of experiment expressions:\n\n-   an instance of Experiment:\n\n```js\ncontainer.add(Experiment.create(...))\n```\n\n-   An instance of Variation where it's object is an Experiment:\n        \t```js\n        \tcontainer.add(Variation.create(Experiment.create(...)))\n        ````\n-   An instance of Variation where it's object is an Expriment defined as an object literal:\n\n```js\ncontainer.add(Variation.create({... experiment data ...}))\n```\n\n-   A variation object literal wrapping an experiment object literal, this is useful in deserialization scenarios:\n\n```js\ncontainer.add({ object: {... experiment data }, weight: 5 })\n```\n\n##### Parameters\n\n-   `experiments` **...any** \n\n#### pick\n\n[lib/ExperimentContainer.js:131-151](https://git@github.com/:ReasonSoftware/pickpick/blob/a6938cd996f3f68216a96b210bf576e6e3ff6ece/lib/ExperimentContainer.js#L131-L151 \"Source code on GitHub\")\n\nThe pick method accepts a targeting object and randomly selects an experiment\n   from a set of experiments that match the targeting specification.\n\n   By default, selection is random and even, however, bias can be applied by specifying a weight\n   when adding an experiment to the container (see ExperimentContainer.add())\n\n   Weights are considered at the moment of selection from the current set of\n   matching experiments, therefor, careful planning of targeting is required to achieve\n   accurate traffic distribution betwee experiments.\n\n   For example, consider two experiments, `E1`, that targets `{ geo: 'US', page: '*' }` and `E2` that targets\n   `{ geo: 'US', page: 'index.html' }`. If both had the weight `1`, given the following stream\n   of visitors:\n\n    { geo: 'US', page: 'sale.html' }\n    { geo: 'US', page: 'index.html' }\n    { geo: 'US', page: 'sale.html' }\n    { geo: 'US', page: 'index.html' }\n\n   Then it is more likely that `E1` will receive more traffic than `E2` since `E1` competes with `E2` evenly on `index.html`\n   page but not on `sale.html`\n\n##### Parameters\n\n-   `targeting` **[Targeting](#targeting)** \n\nReturns **[Experiment](#experiment)** an experiment that matches this targeting or null if none is found.\n\n#### targetingFeatures\n\n[lib/ExperimentContainer.js:159-161](https://git@github.com/:ReasonSoftware/pickpick/blob/a6938cd996f3f68216a96b210bf576e6e3ff6ece/lib/ExperimentContainer.js#L159-L161 \"Source code on GitHub\")\n\nAn iterator over all the targeting features from all the experiments\n   added to this container\n\nReturns **Iterator** \n\n#### iterator\n\n[lib/ExperimentContainer.js:175-177](https://git@github.com/:ReasonSoftware/pickpick/blob/a6938cd996f3f68216a96b210bf576e6e3ff6ece/lib/ExperimentContainer.js#L175-L177 \"Source code on GitHub\")\n\niterate over all the experiments in this container:\n\n    let container = ExperimentContainer.create(...)\n\n    for (let experiment of container) {\n    \tconsole.log(experiment.id)\n    \t}\n\nReturns **ObjectIterator** \n\n#### has\n\n[lib/ExperimentContainer.js:184-188](https://git@github.com/:ReasonSoftware/pickpick/blob/a6938cd996f3f68216a96b210bf576e6e3ff6ece/lib/ExperimentContainer.js#L184-L188 \"Source code on GitHub\")\n\ncheck if this container contains the specified experiment\n\n##### Parameters\n\n-   `experiment` **Expriment** \n\nReturns **[Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** \n\n#### hasId\n\n[lib/ExperimentContainer.js:195-201](https://git@github.com/:ReasonSoftware/pickpick/blob/a6938cd996f3f68216a96b210bf576e6e3ff6ece/lib/ExperimentContainer.js#L195-L201 \"Source code on GitHub\")\n\ncheck if this container contains an experiment using an id\n\n##### Parameters\n\n-   `experimentId` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** \n\nReturns **[Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** \n\n#### toJSON\n\n[lib/ExperimentContainer.js:208-215](https://git@github.com/:ReasonSoftware/pickpick/blob/a6938cd996f3f68216a96b210bf576e6e3ff6ece/lib/ExperimentContainer.js#L208-L215 \"Source code on GitHub\")\n\nserialize this container with all it's experiments\n\nReturns **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** \n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkessler%2Fpickpick","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkessler%2Fpickpick","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkessler%2Fpickpick/lists"}