{"id":49453603,"url":"https://github.com/marvelapp/react-ab-test","last_synced_at":"2026-06-02T05:00:39.329Z","repository":{"id":46826008,"uuid":"122215019","full_name":"marvelapp/react-ab-test","owner":"marvelapp","description":"A/B testing React components and debug tools. Isomorphic with a simple, universal interface. Well documented and lightweight. Tested in popular browsers and Node.js. Includes helpers for Mixpanel and Segment.com.","archived":false,"fork":true,"pushed_at":"2021-09-23T12:06:17.000Z","size":2868,"stargazers_count":242,"open_issues_count":8,"forks_count":44,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-10-21T02:43:41.136Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"pushtell/react-ab-test","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/marvelapp.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}},"created_at":"2018-02-20T15:16:05.000Z","updated_at":"2025-07-17T16:49:17.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/marvelapp/react-ab-test","commit_stats":null,"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"purl":"pkg:github/marvelapp/react-ab-test","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marvelapp%2Freact-ab-test","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marvelapp%2Freact-ab-test/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marvelapp%2Freact-ab-test/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marvelapp%2Freact-ab-test/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marvelapp","download_url":"https://codeload.github.com/marvelapp/react-ab-test/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marvelapp%2Freact-ab-test/sbom","scorecard":{"id":622269,"data":{"date":"2025-08-11","repo":{"name":"github.com/marvelapp/react-ab-test","commit":"606a8626a54adbeedeb560d627b0f077c337f665"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.9,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":1,"reason":"Found 5/26 approved changesets -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 10 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"114 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-whgm-jr23-g3j9","Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw","Warn: Project is vulnerable to: GHSA-fwr7-v2mv-hh25","Warn: Project is vulnerable to: GHSA-qwcr-r2fm-qrc7","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-x9w5-v3q2-3rhw","Warn: Project is vulnerable to: GHSA-w8qv-6jwh-64r5","Warn: Project is vulnerable to: GHSA-257v-vj4p-3w2h","Warn: Project is vulnerable to: GHSA-pxg6-pf52-xh8x","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-w573-4hg7-7wgq","Warn: Project is vulnerable to: GHSA-3wcq-x3mq-6r9p","Warn: Project is vulnerable to: GHSA-phwq-j96m-2c2q","Warn: Project is vulnerable to: GHSA-ghr5-ch3p-vcr6","Warn: Project is vulnerable to: GHSA-434g-2637-qmqr","Warn: Project is vulnerable to: GHSA-49q7-c7j4-3p7m","Warn: Project is vulnerable to: GHSA-977x-g7h5-7qgw","Warn: Project is vulnerable to: GHSA-f7q4-pwc6-w24p","Warn: Project is vulnerable to: GHSA-fc9h-whq2-v747","Warn: Project is vulnerable to: GHSA-vjh7-7g9h-fjfh","Warn: Project is vulnerable to: GHSA-4gmj-3p3h-gm8h","Warn: Project is vulnerable to: GHSA-6h5x-7c5m-7cr7","Warn: Project is vulnerable to: GHSA-rv95-896h-c2vc","Warn: Project is vulnerable to: GHSA-qw6h-vgh9-j6wx","Warn: Project is vulnerable to: GHSA-74fj-2j2h-c42q","Warn: Project is vulnerable to: GHSA-pw2r-vq6v-hr8c","Warn: Project is vulnerable to: GHSA-jchw-25xp-jwwc","Warn: Project is vulnerable to: GHSA-cxjh-pqwp-8mfp","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-ww39-953v-wcq6","Warn: Project is vulnerable to: GHSA-43f8-2h32-f4cj","Warn: Project is vulnerable to: GHSA-c7qv-q95q-8v27","Warn: Project is vulnerable to: GHSA-33f9-j839-rf8h","Warn: Project is vulnerable to: GHSA-c36v-fmgq-m8hx","Warn: Project is vulnerable to: GHSA-78xj-cgh5-2h22","Warn: Project is vulnerable to: GHSA-2p57-rm9w-gvfp","Warn: Project is vulnerable to: GHSA-7r28-3m3f-r2pr","Warn: Project is vulnerable to: GHSA-r8j5-h5cx-65gg","Warn: Project is vulnerable to: GHSA-896r-f27r-55mw","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-76p3-8jx3-jpfq","Warn: Project is vulnerable to: GHSA-3rfm-jhwj-7488","Warn: Project is vulnerable to: GHSA-hhq3-ff78-jv3g","Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-qrpm-p2h7-hrv2","Warn: Project is vulnerable to: GHSA-mwcw-c2x4-8c55","Warn: Project is vulnerable to: GHSA-5rrq-pxf6-6jx5","Warn: Project is vulnerable to: GHSA-8fr3-hfg3-gpgp","Warn: Project is vulnerable to: GHSA-gf8q-jrpm-jvxq","Warn: Project is vulnerable to: GHSA-2r2c-g63r-vccr","Warn: Project is vulnerable to: GHSA-cfm4-qjh2-4765","Warn: Project is vulnerable to: GHSA-x4jg-mjrx-434g","Warn: Project is vulnerable to: GHSA-rp65-9cf3-cjxr","Warn: Project is vulnerable to: GHSA-76c9-3jph-rj3q","Warn: Project is vulnerable to: GHSA-hj48-42vr-x3v9","Warn: Project is vulnerable to: GHSA-9wv6-86v2-598j","Warn: Project is vulnerable to: GHSA-rhx6-c78j-4q9w","Warn: Project is vulnerable to: GHSA-h7cp-r72f-jxh6","Warn: Project is vulnerable to: GHSA-v62p-rq8g-8h59","Warn: Project is vulnerable to: GHSA-566m-qj78-rww5","Warn: Project is vulnerable to: GHSA-hwj9-h5mp-3pm3","Warn: Project is vulnerable to: GHSA-7fh5-64p2-3v2j","Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp","Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6","Warn: Project is vulnerable to: GHSA-gcx4-mw62-g8wm","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-m6fv-jmcg-4jfg","Warn: Project is vulnerable to: GHSA-cm22-4g7w-348p","Warn: Project is vulnerable to: GHSA-g4rg-993r-mgx7","Warn: Project is vulnerable to: GHSA-vx3p-948g-6vhq","Warn: Project is vulnerable to: GHSA-3jfq-g458-7qm9","Warn: Project is vulnerable to: GHSA-r628-mhmh-qjhw","Warn: Project is vulnerable to: GHSA-9r2w-394v-53qc","Warn: Project is vulnerable to: GHSA-5955-9wpr-37jh","Warn: Project is vulnerable to: GHSA-qq89-hq3f-393p","Warn: Project is vulnerable to: GHSA-f5x3-32g6-xq36","Warn: Project is vulnerable to: GHSA-4wf5-vphf-c2xc","Warn: Project is vulnerable to: GHSA-jgrx-mgxx-jf9v","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3","Warn: Project is vulnerable to: GHSA-hh27-ffr2-f2jc","Warn: Project is vulnerable to: GHSA-rqff-837h-mm52","Warn: Project is vulnerable to: GHSA-8v38-pw62-9cw2","Warn: Project is vulnerable to: GHSA-hgjh-723h-mx2j","Warn: Project is vulnerable to: GHSA-jf5r-8hm2-f872","Warn: Project is vulnerable to: GHSA-wr3j-pwj9-hqq6","Warn: Project is vulnerable to: GHSA-4v9v-hfq4-rm2v","Warn: Project is vulnerable to: GHSA-9jgg-88mc-972h","Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7","Warn: Project is vulnerable to: GHSA-6fc8-4gx4-v693","Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q","Warn: Project is vulnerable to: GHSA-vxf5-wxwp-m7g9","Warn: Project is vulnerable to: GHSA-9gr3-7897-pp7m","Warn: Project is vulnerable to: GHSA-25mp-g6fv-mqxx","Warn: Project is vulnerable to: GHSA-fmvm-x8mv-47mj","Warn: Project is vulnerable to: GHSA-c59h-r6p8-q9wc","Warn: Project is vulnerable to: GHSA-g77x-44xx-532m","Warn: Project is vulnerable to: GHSA-7gfc-8cq8-jh5f","Warn: Project is vulnerable to: GHSA-qpjv-v59x-3qc4","Warn: Project is vulnerable to: GHSA-r683-j2x4-v87g","Warn: Project is vulnerable to: GHSA-7gc6-qh9x-w6h8","Warn: Project is vulnerable to: GHSA-qrmc-fj45-qfc2","Warn: Project is vulnerable to: GHSA-6c8f-qphg-qjgp","Warn: Project is vulnerable to: GHSA-w5p7-h5w8-2hfq","Warn: Project is vulnerable to: GHSA-662x-fhqg-9p8v","Warn: Project is vulnerable to: GHSA-394c-5j6w-4xmx","Warn: Project is vulnerable to: GHSA-78cj-fxph-m83p","Warn: Project is vulnerable to: GHSA-fhg7-m89q-25r3","Warn: Project is vulnerable to: GHSA-cf4h-3jhx-xvhq"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-21T05:27:54.372Z","repository_id":46826008,"created_at":"2025-08-21T05:27:54.372Z","updated_at":"2025-08-21T05:27:54.372Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33806987,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-02T02:00:07.132Z","response_time":109,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2026-04-30T04:01:03.701Z","updated_at":"2026-06-02T05:00:39.317Z","avatar_url":"https://github.com/marvelapp.png","language":"JavaScript","funding_links":[],"categories":["📦 Legacy \u0026 Inactive Projects"],"sub_categories":[],"readme":"# A/B Testing React Components\n\n[![NPM version](https://badge.fury.io/js/%40marvelapp%2Freact-ab-test.svg)](https://badge.fury.io/js/%40marvelapp%2Freact-ab-test)\n[![Circle CI](https://circleci.com/gh/marvelapp/react-ab-test.svg?style=shield)](https://circleci.com/gh/marvelapp/react-ab-test)\n[![Dependency Status](https://david-dm.org/marvelapp/react-ab-test.svg)](https://david-dm.org/marvelapp/react-ab-test)\n[![NPM Downloads](https://img.shields.io/npm/dm/@marvelapp/react-ab-test.svg?style=flat)](https://www.npmjs.com/package/@marvelapp/react-ab-test)\n\nWrap components in [`\u003cVariant /\u003e`](#variant-) and nest in [`\u003cExperiment /\u003e`](#experiment-). A variant is chosen randomly and saved to local storage.\n\n```js\n\u003cExperiment name=\"My Example\"\u003e\n  \u003cVariant name=\"A\"\u003e\n    \u003cdiv\u003eVersion A\u003c/div\u003e\n  \u003c/Variant\u003e\n  \u003cVariant name=\"B\"\u003e\n    \u003cdiv\u003eVersion B\u003c/div\u003e\n  \u003c/Variant\u003e\n\u003c/Experiment\u003e\n```\n\nReport to your analytics provider using the [`emitter`](#emitter). Helpers are available for [Mixpanel](#mixpanelhelper) and [Segment.com](#segmenthelper).\n\n```js\nemitter.addPlayListener((experimentName, variantName) =\u003e {\n  mixpanel.track('Start Experiment', {\n    name: experimentName,\n    variant: variantName,\n  });\n});\n```\n\nPlease [★ on GitHub](https://github.com/marvelapp/react-ab-test)!\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n\u003ch1\u003eTable of Contents\u003c/h1\u003e\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Standalone Component](#standalone-component)\n  - [Coordinate Multiple Components](#coordinate-multiple-components)\n  - [Weighting Variants](#weighting-variants)\n  - [Force variant calculation before rendering experiment](#force-variant-calculation-before-rendering-experiment)\n  - [Debugging](#debugging)\n  - [Server Rendering](#server-rendering)\n    - [Example](#example)\n  - [With Babel](#with-babel)\n- [Alternative Libraries](#alternative-libraries)\n- [Resources for A/B Testing with React](#resources-for-ab-testing-with-react)\n- [API Reference](#api-reference)\n  - [`\u003cExperiment /\u003e`](#experiment-)\n  - [`\u003cVariant /\u003e`](#variant-)\n  - [`emitter`](#emitter)\n    - [`emitter.emitWin(experimentName)`](#emitteremitwinexperimentname)\n    - [`emitter.addActiveVariantListener([experimentName, ] callback)`](#emitteraddactivevariantlistenerexperimentname--callback)\n    - [`emitter.addPlayListener([experimentName, ] callback)`](#emitteraddplaylistenerexperimentname--callback)\n    - [`emitter.addWinListener([experimentName, ] callback)`](#emitteraddwinlistenerexperimentname--callback)\n    - [`emitter.defineVariants(experimentName, variantNames [, variantWeights])`](#emitterdefinevariantsexperimentname-variantnames--variantweights)\n    - [`emitter.setActiveVariant(experimentName, variantName)`](#emittersetactivevariantexperimentname-variantname)\n    - [`emitter.getActiveVariant(experimentName)`](#emittergetactivevariantexperimentname)\n    - [`emitter.calculateActiveVariant(experimentName [, userIdentifier, defaultVariantName])`](#emittercalculateactivevariantexperimentname--useridentifier-defaultvariantname)\n    - [`emitter.getSortedVariants(experimentName)`](#emittergetsortedvariantsexperimentname)\n    - [`emitter.setCustomDistributionAlgorithm(customAlgorithm)`](#emittersetcustomdistributionalgorithmcustomalgorithm)\n  - [`Subscription`](#subscription)\n    - [`subscription.remove()`](#subscriptionremove)\n  - [`experimentDebugger`](#experimentdebugger)\n    - [`experimentDebugger.setDebuggerAvailable(isAvailable)`](#experimentdebuggersetdebuggeravailableisavailable)\n    - [`experimentDebugger.enable()`](#experimentdebuggerenable)\n    - [`experimentDebugger.disable()`](#experimentdebuggerdisable)\n  - [`mixpanelHelper`](#mixpanelhelper)\n    - [Usage](#usage-1)\n    - [`mixpanelHelper.enable()`](#mixpanelhelperenable)\n    - [`mixpanelHelper.disable()`](#mixpanelhelperdisable)\n  - [`segmentHelper`](#segmenthelper)\n    - [Usage](#usage-2)\n    - [`segmentHelper.enable()`](#segmenthelperenable)\n    - [`segmentHelper.disable()`](#segmenthelperdisable)\n- [How to contribute](#how-to-contribute)\n  - [Requisites](#requisites)\n  - [Running Tests](#running-tests)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n## Installation\n\n`react-ab-test` is compatible with React `\u003e=0.14.x`\n\n```bash\nyarn add @marvelapp/react-ab-test\n```\n\n## Usage\n\n### Standalone Component\n\nTry it [on JSFiddle](https://jsfiddle.net/pushtell/m14qvy7r/)\n\n\nUsing useExperiment Hook\n\n```js\nimport React from 'react';\nimport { useExperiment, emitter } from '@marvelapp/react-ab-test';\n\n// Hook usage pattern requires registration of experiments\nemitter.defineVariants(\"My Example\", [\"A\", \"B\"]);\n\nconst App = () =\u003e {\n  const { selectVariant, emitWin } = useExperiment(\"My Example\");\n  const variant = selectVariant({\n    A: \u003cdiv\u003eSection A\u003c/div\u003e,\n    B: \u003cdiv\u003eSection B\u003c/div\u003e\n  });\n\n  return (\n    \u003cdiv\u003e\n      {variant}\n      \u003cbutton onClick={emitWin}\u003eCTA\u003c/button\u003e\n    \u003c/div\u003e\n  );\n};\n```\n\n\nUsing Experiment Component\n\n```js\nimport React from 'react';\nimport { Experiment, Variant, emitter } from '@marvelapp/react-ab-test';\n\nclass App extends Component {\n  experimentRef = React.createRef();\n\n  onButtonClick(e) {\n    this.experimentRef.current.win();\n  }\n\n  render() {\n    return (\n      \u003cdiv\u003e\n        \u003cExperiment ref={this.experimentRef} name=\"My Example\"\u003e\n          \u003cVariant name=\"A\"\u003e\n            \u003cdiv\u003eSection A\u003c/div\u003e\n          \u003c/Variant\u003e\n          \u003cVariant name=\"B\"\u003e\n            \u003cdiv\u003eSection B\u003c/div\u003e\n          \u003c/Variant\u003e\n        \u003c/Experiment\u003e\n        \u003cbutton onClick={this.onButtonClick}\u003eEmit a win\u003c/button\u003e\n      \u003c/div\u003e\n    );\n  }\n}\n\n// Called when the experiment is displayed to the user.\nemitter.addPlayListener(function(experimentName, variantName) {\n  console.log(`Displaying experiment ${experimentName} variant ${variantName}`);\n});\n\n// Called when a 'win' is emitted, in this case by this.experimentRef.current.win()\nemitter.addWinListener(function(experimentName, variantName) {\n  console.log(\n    `Variant ${variantName} of experiment ${experimentName} was clicked`\n  );\n});\n```\n\n### Coordinate Multiple Components\n\nTry it [on JSFiddle](http://jsfiddle.net/pushtell/pcutps9q/)\n\n```js\nimport React from 'react';\nimport { Experiment, Variant, emitter } from '@marvelapp/react-ab-test';\n\n// Define variants in advance.\nemitter.defineVariants('My Example', ['A', 'B', 'C']);\n\nfunction Component1 = () =\u003e {\n  return (\n    \u003cExperiment name=\"My Example\"\u003e\n      \u003cVariant name=\"A\"\u003e\n        \u003cdiv\u003eSection A\u003c/div\u003e\n      \u003c/Variant\u003e\n      \u003cVariant name=\"B\"\u003e\n        \u003cdiv\u003eSection B\u003c/div\u003e\n      \u003c/Variant\u003e\n    \u003c/Experiment\u003e\n  );\n};\n\nconst Component2 = () =\u003e {\n  return (\n    \u003cExperiment name=\"My Example\"\u003e\n      \u003cVariant name=\"A\"\u003e\n        \u003cdiv\u003eSubsection A\u003c/div\u003e\n      \u003c/Variant\u003e\n      \u003cVariant name=\"B\"\u003e\n        \u003cdiv\u003eSubsection B\u003c/div\u003e\n      \u003c/Variant\u003e\n      \u003cVariant name=\"C\"\u003e\n        \u003cdiv\u003eSubsection C\u003c/div\u003e\n      \u003c/Variant\u003e\n    \u003c/Experiment\u003e\n  );\n};\n\nclass Component3 extends React.Component {\n  onButtonClick(e) {\n    emitter.emitWin('My Example');\n  }\n  render() {\n    return \u003cbutton onClick={this.onButtonClick}\u003eEmit a win\u003c/button\u003e;\n  }\n}\n\nconst App = () =\u003e {\n  return (\n    \u003cdiv\u003e\n      \u003cComponent1 /\u003e\n      \u003cComponent2 /\u003e\n      \u003cComponent3 /\u003e\n    \u003c/div\u003e\n  );\n};\n\n// Called when the experiment is displayed to the user.\nemitter.addPlayListener(function(experimentName, variantName) {\n  console.log(`Displaying experiment ${experimentName} variant ${variantName}`);\n});\n\n// Called when a 'win' is emitted, in this case by emitter.emitWin('My Example')\nemitter.addWinListener(function(experimentName, variantName) {\n  console.log(\n    `Variant ${variantName} of experiment ${experimentName} was clicked`\n  );\n});\n```\n\n### Weighting Variants\n\nTry it [on JSFiddle](http://jsfiddle.net/pushtell/e2q7xe4f/)\n\nUse [emitter.defineVariants()](#emitterdefinevariantsexperimentname-variantnames--variantweights) to optionally define the ratios by which variants are chosen.\n\n```js\nimport React from 'react';\nimport { Experiment, Variant, emitter } from '@marvelapp/react-ab-test';\n\n// Define variants and weights in advance.\nemitter.defineVariants('My Example', ['A', 'B', 'C'], [10, 40, 40]);\n\nconst App = () =\u003e {\n  return (\n    \u003cdiv\u003e\n      \u003cExperiment name=\"My Example\"\u003e\n        \u003cVariant name=\"A\"\u003e\n          \u003cdiv\u003eSection A\u003c/div\u003e\n        \u003c/Variant\u003e\n        \u003cVariant name=\"B\"\u003e\n          \u003cdiv\u003eSection B\u003c/div\u003e\n        \u003c/Variant\u003e\n        \u003cVariant name=\"C\"\u003e\n          \u003cdiv\u003eSection C\u003c/div\u003e\n        \u003c/Variant\u003e\n      \u003c/Experiment\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n### Force variant calculation before rendering experiment\nThere are some scenarios where you may want the active variant of an experiment to be calculated before the experiment is rendered.\nTo do so, use [emitter.calculateActiveVariant()](#emittercalculateactivevariantexperimentname--useridentifier-defaultvariantname). Note that this method must\nbe called after [emitter.defineVariants()](#emitterdefinevariantsexperimentname-variantnames--variantweights)\n\n```js\nimport { emitter } from '@marvelapp/react-ab-test';\n\n// Define variants in advance\nemitter.defineVariants('My Example', ['A', 'B', 'C']);\nemitter.calculateActiveVariant('My Example', 'userId');\n\n// Active variant will be defined even if the experiment is not rendered\nconst activeVariant = emitter.getActiveVariant('My Example');\n\n```\n\n### Debugging\n\nThe [debugger](#experimentdebugger) attaches a fixed-position panel to the bottom of the `\u003cbody\u003e` element that displays mounted experiments and enables the user to change active variants in real-time.\n\nThe debugger is wrapped in a conditional `if(process.env.NODE_ENV === \"production\") {...}` and will not display on production builds using [envify](https://github.com/hughsk/envify).\n\n\u003cimg src=\"https://cdn.rawgit.com/pushtell/react-ab-test/master/documentation-images/debugger-animated-2.gif\" width=\"325\" height=\"325\" /\u003e\n\nTry it [on JSFiddle](http://jsfiddle.net/pushtell/vs9kkxLd/)\n\n```js\nimport React from 'react';\nimport { Experiment, Variant, experimentDebugger } from '@marvelapp/react-ab-test';\n\nexperimentDebugger.enable();\n\nconst App = () =\u003e {\n  return (\n    \u003cdiv\u003e\n      \u003cExperiment name=\"My Example\"\u003e\n        \u003cVariant name=\"A\"\u003e\n          \u003cdiv\u003eSection A\u003c/div\u003e\n        \u003c/Variant\u003e\n        \u003cVariant name=\"B\"\u003e\n          \u003cdiv\u003eSection B\u003c/div\u003e\n        \u003c/Variant\u003e\n      \u003c/Experiment\u003e\n    \u003c/div\u003e\n  );\n}\n````\n\n### Server Rendering\n\nA [`\u003cExperiment /\u003e`](#experiment-) with a `userIdentifier` property will choose a consistent [`\u003cVariant /\u003e`](#variant-) suitable for server side rendering.\n\nSee [`./examples/isomorphic`](https://github.com/pushtell/react-ab-test/tree/develop/examples/isomorphic) for a working example.\n\n#### Example\n\nThe component in [`Component.jsx`](https://github.com/pushtell/react-ab-test/blob/master/examples/isomorphic/Component.jsx):\n\n```js\nvar React = require('react');\nvar Experiment = require('react-ab-test/lib/Experiment');\nvar Variant = require('react-ab-test/lib/Variant');\n\nmodule.exports = React.createClass({\n  propTypes: {\n    userIdentifier: React.PropTypes.string.isRequired,\n  },\n  render: function() {\n    return (\n      \u003cdiv\u003e\n        \u003cExperiment\n          name=\"My Example\"\n          userIdentifier={this.props.userIdentifier}\n        \u003e\n          \u003cVariant name=\"A\"\u003e\n            \u003cdiv\u003eSection A\u003c/div\u003e\n          \u003c/Variant\u003e\n          \u003cVariant name=\"B\"\u003e\n            \u003cdiv\u003eSection B\u003c/div\u003e\n          \u003c/Variant\u003e\n        \u003c/Experiment\u003e\n      \u003c/div\u003e\n    );\n  },\n});\n```\n\nWe use a session ID for the `userIdentifier` property in this example, although a long-lived user ID would be preferable. See [`server.js`](https://github.com/pushtell/react-ab-test/blob/master/examples/isomorphic/server.js):\n\n```js\nrequire('babel/register')({ only: /jsx/ });\n\nvar express = require('express');\nvar session = require('express-session');\nvar React = require('react');\nvar ReactDOMServer = require('react-dom/server');\nvar Component = require('./Component.jsx');\nvar abEmitter = require('@marvelapp/react-ab-test/lib/emitter');\n\nvar app = express();\n\napp.set('view engine', 'ejs');\n\napp.use(\n  session({\n    secret: 'keyboard cat',\n    resave: false,\n    saveUninitialized: true,\n  })\n);\n\napp.get('/', function(req, res) {\n  var reactElement = React.createElement(Component, {\n    userIdentifier: req.sessionID,\n  });\n  var reactString = ReactDOMServer.renderToString(reactElement);\n  abEmitter.rewind();\n  res.render('template', {\n    sessionID: req.sessionID,\n    reactOutput: reactString,\n  });\n});\n\napp.use(express.static('www'));\n\napp.listen(8080);\n```\n\nRemember to call `abEmitter.rewind()` to prevent memory leaks.\n\nAn [EJS](https://github.com/mde/ejs) template in [`template.ejs`](https://github.com/pushtell/react-ab-test/blob/master/examples/isomorphic/views/template.ejs):\n\n```html\n\u003c!doctype html\u003e\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003ctitle\u003eIsomorphic Rendering Example\u003c/title\u003e\n  \u003c/head\u003e\n  \u003cscript type=\"text/javascript\"\u003e\n    var SESSION_ID = \u003c%- JSON.stringify(sessionID) %\u003e;\n  \u003c/script\u003e\n  \u003cbody\u003e\n    \u003cdiv id=\"react-mount\"\u003e\u003c%- reactOutput %\u003e\u003c/div\u003e\n    \u003cscript type=\"text/javascript\" src=\"bundle.js\"\u003e\u003c/script\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\nOn the client in [`app.jsx`](https://github.com/pushtell/react-ab-test/blob/master/examples/isomorphic/www/app.jsx):\n\n```js\nvar React = require('react');\nvar ReactDOM = require('react-dom');\nvar Component = require('../Component.jsx');\n\nvar container = document.getElementById('react-mount');\n\nReactDOM.render(\u003cComponent userIdentifier={SESSION_ID} /\u003e, container);\n```\n\n### With Babel\n\nCode from [`./src`](https://github.com/pushtell/react-ab-test/tree/master/src) is written in [JSX](https://facebook.github.io/jsx/) and transpiled into [`./lib`](https://github.com/pushtell/react-ab-test/tree/master/lib) using [Babel](https://babeljs.io/). If your project uses Babel you may want to include files from [`./src`](https://github.com/pushtell/react-ab-test/tree/master/src) directly.\n\n## Alternative Libraries\n\n* [**react-experiments**](https://github.com/HubSpot/react-experiments) - “A JavaScript library that assists in defining and managing UI experiments in React” by [Hubspot](https://github.com/HubSpot). Uses Facebook's [PlanOut framework](http://facebook.github.io/planout/) via [Hubspot's javascript port](https://github.com/HubSpot/PlanOut.js).\n* [**react-ab**](https://github.com/olahol/react-ab) - “Simple declarative and universal A/B testing component for React” by [Ola Holmström](https://github.com/olahol)\n* [**react-native-ab**](https://github.com/lwansbrough/react-native-ab/) - “A component for rendering A/B tests in React Native” by [Loch Wansbrough](https://github.com/lwansbrough)\n\nPlease [let us know](https://github.com/pushtell/react-ab-test/issues/new) about alternate libraries not included here.\n\n## Resources for A/B Testing with React\n\n* [Product Experimentation with React and PlanOut](http://product.hubspot.com/blog/product-experimentation-with-planout-and-react.js) on the [HubSpot Product Blog](http://product.hubspot.com/)\n* [Roll Your Own A/B Tests With Optimizely and React](http://engineering.tilt.com/roll-your-own-ab-tests-with-optimizely-and-react/) on the [Tilt Engineering Blog](http://engineering.tilt.com/)\n* [Simple Sequential A/B Testing](http://www.evanmiller.org/sequential-ab-testing.html)\n* [A/B Testing Rigorously (without losing your job)](http://elem.com/~btilly/ab-testing-multiple-looks/part1-rigorous.html)\n\nPlease [let us know](https://github.com/pushtell/react-ab-test/issues/new) about React A/B testing resources not included here.\n\n## API Reference\n\n### `\u003cExperiment /\u003e`\n\nExperiment container component. Children must be of type [`Variant`](#variant-).\n\n* **Properties:**\n  * `name` - Name of the experiment.\n    * **Required**\n    * **Type:** `string`\n    * **Example:** `\"My Example\"`\n  * `userIdentifier` - Distinct user identifier. When defined, this value is hashed to choose a variant if `defaultVariantName` or a stored value is not present. Useful for [server side rendering](#server-rendering).\n    * **Optional**\n    * **Type:** `string`\n    * **Example:** `\"7cf61a4521f24507936a8977e1eee2d4\"`\n  * `defaultVariantName` - Name of the default variant. When defined, this value is used to choose a variant if a stored value is not present. This property may be useful for [server side rendering](#server-rendering) but is otherwise not recommended.\n    * **Optional**\n    * **Type:** `string`\n    * **Example:** `\"A\"`\n\n### `\u003cVariant /\u003e`\n\nVariant container component.\n\n* **Properties:**\n  * `name` - Name of the variant.\n    * **Required**\n    * **Type:** `string`\n    * **Example:** `\"A\"`\n\n### `emitter`\n\nEvent emitter responsible for coordinating and reporting usage. Extended from [facebook/emitter](https://github.com/facebook/emitter).\n\n#### `emitter.emitWin(experimentName)`\n\nEmit a win event.\n\n* **Return Type:** No return value\n* **Parameters:**\n  * `experimentName` - Name of an experiment.\n    * **Required**\n    * **Type:** `string`\n    * **Example:** `\"My Example\"`\n\n#### `emitter.addActiveVariantListener([experimentName, ] callback)`\n\nListen for the active variant specified by an experiment.\n\n* **Return Type:** [`Subscription`](#subscription)\n* **Parameters:**\n  * `experimentName` - Name of an experiment. If provided, the callback will only be called for the specified experiment.\n    * **Optional**\n    * **Type:** `string`\n    * **Example:** `\"My Example\"`\n  * `callback` - Function to be called when a variant is chosen.\n    * **Required**\n    * **Type:** `function`\n    * **Callback Arguments:**\n      * `experimentName` - Name of the experiment.\n        * **Type:** `string`\n      * `variantName` - Name of the variant.\n        * **Type:** `string`\n\n#### `emitter.addPlayListener([experimentName, ] callback)`\n\nListen for an experiment being displayed to the user. Trigged by the [React componentWillMount lifecycle method](https://facebook.github.io/react/docs/component-specs.html#mounting-componentwillmount).\n\n* **Return Type:** [`Subscription`](#subscription)\n* **Parameters:**\n  * `experimentName` - Name of an experiment. If provided, the callback will only be called for the specified experiment.\n    * **Optional**\n    * **Type:** `string`\n    * **Example:** `\"My Example\"`\n  * `callback` - Function to be called when an experiment is displayed to the user.\n    * **Required**\n    * **Type:** `function`\n    * **Callback Arguments:**\n      * `experimentName` - Name of the experiment.\n        * **Type:** `string`\n      * `variantName` - Name of the variant.\n        * **Type:** `string`\n\n#### `emitter.addWinListener([experimentName, ] callback)`\n\nListen for a successful outcome from the experiment. Trigged by the [emitter.emitWin(experimentName)](#emitteremitwinexperimentname) method.\n\n* **Return Type:** [`Subscription`](#subscription)\n* **Parameters:**\n  * `experimentName` - Name of an experiment. If provided, the callback will only be called for the specified experiment.\n    * **Optional**\n    * **Type:** `string`\n    * **Example:** `\"My Example\"`\n  * `callback` - Function to be called when a win is emitted.\n    * **Required**\n    * **Type:** `function`\n    * **Callback Arguments:**\n      * `experimentName` - Name of the experiment.\n        * **Type:** `string`\n      * `variantName` - Name of the variant.\n        * **Type:** `string`\n\n#### `emitter.defineVariants(experimentName, variantNames [, variantWeights])`\n\nDefine experiment variant names and weighting. Required when an experiment [spans multiple components](#coordinate-multiple-components) containing different sets of variants.\n\nIf `variantWeights` are not specified variants will be chosen at equal rates.\n\nThe variants will be chosen according to the ratio of the numbers, for example variants `[\"A\", \"B\", \"C\"]` with weights `[20, 40, 40]` will be chosen 20%, 40%, and 40% of the time, respectively.\n\n* **Return Type:** No return value\n* **Parameters:**\n  * `experimentName` - Name of the experiment.\n    * **Required**\n    * **Type:** `string`\n    * **Example:** `\"My Example\"`\n  * `variantNames` - Array of variant names.\n    * **Required**\n    * **Type:** `Array.\u003cstring\u003e`\n    * **Example:** `[\"A\", \"B\", \"C\"]`\n  * `variantWeights` - Array of variant weights.\n    * **Optional**\n    * **Type:** `Array.\u003cnumber\u003e`\n    * **Example:** `[20, 40, 40]`\n\n#### `emitter.setActiveVariant(experimentName, variantName)`\n\nSet the active variant of an experiment.\n\n* **Return Type:** No return value\n* **Parameters:**\n  * `experimentName` - Name of the experiment.\n    * **Required**\n    * **Type:** `string`\n    * **Example:** `\"My Example\"`\n  * `variantName` - Name of the variant.\n    * **Required**\n    * **Type:** `string`\n    * **Example:** `\"A\"`\n\n#### `emitter.getActiveVariant(experimentName)`\n\nReturns the variant name currently displayed by the experiment.\n\n* **Return Type:** `string`\n* **Parameters:**\n  * `experimentName` - Name of the experiment.\n    * **Required**\n    * **Type:** `string`\n    * **Example:** `\"My Example\"`\n\n#### `emitter.calculateActiveVariant(experimentName [, userIdentifier, defaultVariantName])`\n\nForce calculation of active variant, even if the experiment is not displayed yet.\nNote: This method must be called after `emitter.defineVariants`\n\n* **Return Type:** `string`\n* **Parameters:**\n  * `experimentName` - Name of the experiment.\n    * **Required**\n    * **Type:** `string`\n    * **Example:** `\"My Example\"`\n  * `userIdentifier` - Distinct user identifier. When defined, this value is hashed to choose a variant if `defaultVariantName` or a stored value is not present. Useful for [server side rendering](#server-rendering).\n    * **Optional**\n    * **Type:** `string`\n    * **Example:** `\"7cf61a4521f24507936a8977e1eee2d4\"`\n  * `defaultVariantName` - Name of the default variant. When defined, this value is used to choose a variant if a stored value is not present. This property may be useful for [server side rendering](#server-rendering) but is otherwise not recommended.\n    * **Optional**\n    * **Type:** `string`\n    * **Example:** `\"A\"`\n\n#### `emitter.getSortedVariants(experimentName)`\n\nReturns a sorted array of variant names associated with the experiment.\n\n* **Return Type:** `Array.\u003cstring\u003e`\n* **Parameters:**\n  * `experimentName` - Name of the experiment.\n    * **Required**\n    * **Type:** `string`\n    * **Example:** `\"My Example\"`\n\n#### `emitter.setCustomDistributionAlgorithm(customAlgorithm)`\n\nSets a custom function to use for calculating variants overriding the default. This can be usefull\nin cases when variants are expected from 3rd parties or when variants need to be\nin sync with other clients using ab test but different distribution algorithm.\n\n- **Return Type:** No return value\n- **Parameters:**\n  - `customAlgorithm` - Function for calculating variant distribution.\n    - **Required**\n    - **Type:** `function`\n    - **Callback Arguments:**\n      - `experimentName` - Name of the experiment.\n        - **Required**\n        - **Type:** `string`\n      - `userIdentifier` - User's value which is used to calculate the variant\n        - **Required**\n        - **Type:** `string`\n      - `defaultVariantName` - Default variant passed from the experiment\n        - **Type:** `string`\n\n### `Subscription`\n\nReturned by the emitter's add listener methods. More information available in the [facebook/emitter documentation.](https://github.com/facebook/emitter#api-concepts)\n\n#### `subscription.remove()`\n\nRemoves the listener subscription and prevents future callbacks.\n\n* **Parameters:** No parameters\n\n### `experimentDebugger`\n\nDebugging tool. Attaches a fixed-position panel to the bottom of the `\u003cbody\u003e` element that displays mounted experiments and enables the user to change active variants in real-time.\n\nThe debugger is wrapped in a conditional `if(process.env.NODE_ENV === \"production\") {...}` and will not display on production builds using [envify](https://github.com/hughsk/envify). This can be overriden by `setDebuggerAvailable`\n\n\u003cimg src=\"https://cdn.rawgit.com/pushtell/react-ab-test/master/documentation-images/debugger-animated-2.gif\" width=\"325\" height=\"325\" /\u003e\n\n#### `experimentDebugger.setDebuggerAvailable(isAvailable)`\nOverrides `process.env.NODE_ENV` check, so it can be decided if the debugger is available\nor not at runtime. This allow, for instance, to enable the debugger in a testing environment but not in production.\nNote that you require to explicitly call to `.enable` even if you forced this to be truthy.\n\n* **Return Type:** No return value\n* **Parameters:**\n  * `isAvailable` - Tells whether the debugger is available or not\n    * **Required**\n    * **Type:** `boolean`\n\n#### `experimentDebugger.enable()`\n\nAttaches the debugging panel to the `\u003cbody\u003e` element.\n\n* **Return Type:** No return value\n\n#### `experimentDebugger.disable()`\n\nRemoves the debugging panel from the `\u003cbody\u003e` element.\n\n* **Return Type:** No return value\n\n### `mixpanelHelper`\n\nSends events to [Mixpanel](https://mixpanel.com). Requires `window.mixpanel` to be set using [Mixpanel's embed snippet](https://mixpanel.com/help/reference/javascript).\n\n#### Usage\n\nWhen the [`\u003cExperiment /\u003e`](#experiment-) is mounted, the helper sends an `Experiment Play` event using [`mixpanel.track(...)`](https://mixpanel.com/help/reference/javascript-full-api-reference#mixpanel.track) with `Experiment` and `Variant` properties.\n\nWhen a [win is emitted](#emitteremitwinexperimentname) the helper sends an `Experiment Win` event using [`mixpanel.track(...)`](https://mixpanel.com/help/reference/javascript-full-api-reference#mixpanel.track) with `Experiment` and `Variant` properties.\n\nTry it [on JSFiddle](https://jsfiddle.net/pushtell/hwtnzm35/)\n\n```js\nimport React from 'react';\nimport { Experiment, Variant, mixpanelHelper } from '@marvelapp/react-ab-test';\n\n// window.mixpanel has been set by Mixpanel's embed snippet.\nmixpanelHelper.enable();\n\nclass App extends React.Component {\n\n  experimentRef = React.createRef();\n\n  onButtonClick(e) {\n    this.experimentRef.current.win();\n    // mixpanelHelper sends the 'Experiment Win' event, equivalent to:\n    // mixpanel.track('Experiment Win', {Experiment: \"My Example\", Variant: \"A\"})\n  }\n  componentWillMount() {\n    // mixpanelHelper sends the 'Experiment Play' event, equivalent to:\n    // mixpanel.track('Experiment Play', {Experiment: \"My Example\", Variant: \"A\"})\n  }\n  render() {\n    return (\n      \u003cdiv\u003e\n        \u003cExperiment ref={this.experimentRef} name=\"My Example\"\u003e\n          \u003cVariant name=\"A\"\u003e\n            \u003cdiv\u003eSection A\u003c/div\u003e\n          \u003c/Variant\u003e\n          \u003cVariant name=\"B\"\u003e\n            \u003cdiv\u003eSection B\u003c/div\u003e\n          \u003c/Variant\u003e\n        \u003c/Experiment\u003e\n        \u003cbutton onClick={this.onButtonClick}\u003eEmit a win\u003c/button\u003e\n      \u003c/div\u003e\n    );\n  }\n}\n```\n\n#### `mixpanelHelper.enable()`\n\nAdd listeners to `win` and `play` events and report results to Mixpanel.\n\n* **Return Type:** No return value\n\n#### `mixpanelHelper.disable()`\n\nRemove `win` and `play` listeners and stop reporting results to Mixpanel.\n\n* **Return Type:** No return value\n\n### `segmentHelper`\n\nSends events to [Segment](https://segment.com). Requires `window.analytics` to be set using [Segment's embed snippet](https://segment.com/docs/libraries/analytics.js/quickstart/#step-1-copy-the-snippet).\n\n#### Usage\n\nWhen the [`\u003cExperiment /\u003e`](#experiment-) is mounted, the helper sends an `Experiment Viewed` event using [`segment.track(...)`](https://segment.com/docs/libraries/analytics.js/#track) with `experimentName` and `variationName` properties.\n\nWhen a [win is emitted](#emitteremitwinexperimentname) the helper sends an `Experiment Won` event using [`segment.track(...)`](https://segment.com/docs/libraries/analytics.js/#track) with `experimentName` and `variationName` properties.\n\nTry it [on JSFiddle](https://jsfiddle.net/pushtell/ae1jeo2k/)\n\n```js\nimport React from 'react';\nimport { Experiment, Variant, segmentHelper } from '@marvelapp/react-ab-test';\n\n// window.analytics has been set by Segment's embed snippet.\nsegmentHelper.enable();\n\nclass App extends React.Component {\n  experimentRef = React.createRef();\n\n  onButtonClick(e) {\n    this.experimentRef.current.win();\n    // segmentHelper sends the 'Experiment Won' event, equivalent to:\n    // segment.track('Experiment Won', {experimentName: \"My Example\", variationName: \"A\"})\n  }\n  componentWillMount() {\n    // segmentHelper sends the 'Experiment Viewed' event, equivalent to:\n    // segment.track('Experiment Viewed, {experimentName: \"My Example\", variationName: \"A\"})\n  }\n  render() {\n    return (\n      \u003cdiv\u003e\n        \u003cExperiment ref={this.experimentRef} name=\"My Example\"\u003e\n          \u003cVariant name=\"A\"\u003e\n            \u003cdiv\u003eSection A\u003c/div\u003e\n          \u003c/Variant\u003e\n          \u003cVariant name=\"B\"\u003e\n            \u003cdiv\u003eSection B\u003c/div\u003e\n          \u003c/Variant\u003e\n        \u003c/Experiment\u003e\n        \u003cbutton onClick={this.onButtonClick}\u003eEmit a win\u003c/button\u003e\n      \u003c/div\u003e\n    );\n  }\n}\n```\n\n#### `segmentHelper.enable()`\n\nAdd listeners to `win` and `play` events and report results to Segment.\n\n* **Return Type:** No return value\n\n#### `segmentHelper.disable()`\n\nRemove `win` and `play` listeners and stop reporting results to Segment.\n\n* **Return Type:** No return value\n\n## How to contribute\n\n### Requisites\n\nBefore contribuiting you need:\n\n* [doctoc](https://github.com/thlorenz/doctoc) installed\n\nThen you can:\n\n* Apply your changes :sunglasses:\n* Build your changes with `yarn build`\n* Test your changes with `yarn test`\n* Lint your changes with `yarn lint`\n* And finally open the PR! :tada:\n\n### Running Tests\n\n```bash\nyarn test\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarvelapp%2Freact-ab-test","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarvelapp%2Freact-ab-test","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarvelapp%2Freact-ab-test/lists"}