{"id":13879861,"url":"https://github.com/ankane/field_test","last_synced_at":"2025-11-17T14:09:21.766Z","repository":{"id":14381935,"uuid":"76455383","full_name":"ankane/field_test","owner":"ankane","description":"A/B testing for Rails","archived":false,"fork":false,"pushed_at":"2025-10-23T17:13:28.000Z","size":244,"stargazers_count":576,"open_issues_count":0,"forks_count":30,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-11-09T16:03:33.114Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Ruby","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/ankane.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2016-12-14T11:55:05.000Z","updated_at":"2025-11-04T09:50:29.000Z","dependencies_parsed_at":"2024-06-10T04:25:17.958Z","dependency_job_id":"d8abef14-703d-4d2c-bf69-aa3805f95238","html_url":"https://github.com/ankane/field_test","commit_stats":{"total_commits":237,"total_committers":9,"mean_commits":"26.333333333333332","dds":0.5864978902953586,"last_synced_commit":"977437034900a0224e5cd18661945ad91931462e"},"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"purl":"pkg:github/ankane/field_test","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ankane%2Ffield_test","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ankane%2Ffield_test/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ankane%2Ffield_test/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ankane%2Ffield_test/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ankane","download_url":"https://codeload.github.com/ankane/field_test/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ankane%2Ffield_test/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":284893733,"owners_count":27080570,"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","status":"online","status_checked_at":"2025-11-17T02:00:06.431Z","response_time":55,"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":"2024-08-06T08:02:36.399Z","updated_at":"2025-11-17T14:09:21.751Z","avatar_url":"https://github.com/ankane.png","language":"Ruby","funding_links":[],"categories":["Ruby","A/B testing"],"sub_categories":[],"readme":"# Field Test\n\n:maple_leaf: A/B testing for Rails\n\n- Designed for web and email\n- Comes with a [dashboard](https://fieldtest.dokkuapp.com/) to view results and update variants\n- Uses your database for storage\n- Seamlessly handles the transition from anonymous visitor to logged in user\n\nUses [Bayesian statistics](https://www.evanmiller.org/bayesian-ab-testing.html) to evaluate results so you don’t need to choose a sample size ahead of time.\n\n[![Build Status](https://github.com/ankane/field_test/actions/workflows/build.yml/badge.svg)](https://github.com/ankane/field_test/actions)\n\n## Installation\n\nAdd this line to your application’s Gemfile:\n\n```ruby\ngem \"field_test\"\n```\n\nRun:\n\n```sh\nrails generate field_test:install\nrails db:migrate\n```\n\nAnd mount the dashboard in your `config/routes.rb`:\n\n```ruby\nmount FieldTest::Engine, at: \"field_test\"\n```\n\nBe sure to [secure the dashboard](#dashboard-security) in production.\n\n## Getting Started\n\nAdd an experiment to `config/field_test.yml`.\n\n```yml\nexperiments:\n  button_color:\n    variants:\n      - red\n      - green\n      - blue\n```\n\nRefer to it in controllers, views, and mailers.\n\n```ruby\nbutton_color = field_test(:button_color)\n```\n\nTo make testing easier, you can specify a variant with query parameters\n\n```\nhttp://localhost:3000/?field_test[button_color]=green\n```\n\nWhen someone converts, record it with:\n\n```ruby\nfield_test_converted(:button_color)\n```\n\nWhen an experiment is over, specify a winner:\n\n```yml\nexperiments:\n  button_color:\n    winner: green\n```\n\nAll calls to `field_test` will now return the winner, and metrics will stop being recorded.\n\nYou can keep returning the variant for existing participants after a winner is declared:\n\n```yml\nexperiments:\n  button_color:\n    winner: green\n    keep_variant: true\n```\n\nYou can also close an experiment to new participants without declaring a winner while still recording metrics for existing participants:\n\n```yml\nexperiments:\n  button_color:\n    closed: true\n```\n\nCalls to `field_test` for new participants will return the control, and they won’t be added to the experiment.\n\nYou can get the list of experiments and variants for a user with:\n\n```ruby\nfield_test_experiments\n```\n\n## JavaScript and Native Apps\n\nFor JavaScript and native apps, add calls to your normal endpoints.\n\n```ruby\nclass CheckoutController \u003c ActionController::API\n  def start\n    render json: {button_color: field_test(:button_color)}\n  end\n\n  def finish\n    field_test_converted(:button_color)\n    # ...\n  end\nend\n```\n\nFor anonymous visitors in native apps, pass a `Field-Test-Visitor` header with a unique identifier.\n\n## Participants\n\nAny model or string can be a participant in an experiment.\n\nFor web requests, it uses `current_user` (if it exists) and an anonymous visitor id to determine the participant. Set your own with:\n\n```ruby\nclass ApplicationController \u003c ActionController::Base\n  def field_test_participant\n    current_company\n  end\nend\n```\n\nFor mailers, it tries `@user` then `params[:user]` to determine the participant. Set your own with:\n\n```ruby\nclass ApplicationMailer \u003c ActionMailer::Base\n  def field_test_participant\n    @company\n  end\nend\n```\n\nYou can also manually pass a participant with:\n\n```ruby\nfield_test(:button_color, participant: company)\n```\n\n## Jobs\n\nTo get variants in jobs, models, and other contexts, use:\n\n```ruby\nexperiment = FieldTest::Experiment.find(:button_color)\nbutton_color = experiment.variant(user)\n```\n\n## Exclusions\n\nBy default, bots are returned the first variant and excluded from metrics. Change this with:\n\n```yml\nexclude:\n  bots: false\n```\n\nExclude certain IP addresses with:\n\n```yml\nexclude:\n  ips:\n    - 127.0.0.1\n    - 10.0.0.0/8\n```\n\nYou can also use custom logic:\n\n```ruby\nfield_test(:button_color, exclude: request.user_agent == \"Test\")\n```\n\n## Config\n\nKeep track of when experiments started and ended. Use any format `Time.parse` accepts. Variants assigned outside this window are not included in metrics.\n\n```yml\nexperiments:\n  button_color:\n    started_at: Dec 1, 2024 8 am PST\n    ended_at: Dec 8, 2024 2 pm PST\n```\n\nAdd a friendlier name and description with:\n\n```yml\nexperiments:\n  button_color:\n    name: Buttons!\n    description: \u003e\n      Different button colors\n      for the landing page.\n```\n\nBy default, variants are given the same probability of being selected. Change this with:\n\n```yml\nexperiments:\n  button_color:\n    variants:\n      - red\n      - blue\n    weights:\n      - 85\n      - 15\n```\n\nTo help with GDPR compliance, you can switch from cookies to [anonymity sets](https://privacypatterns.org/patterns/Anonymity-set) for anonymous visitors. Visitors with the same IP mask and user agent are grouped together.\n\n```yml\ncookies: false\n```\n\n## Dashboard Config\n\nIf the dashboard gets slow, you can make it faster with:\n\n```yml\ncache: true\n```\n\nThis will use the Rails cache to speed up winning probability calculations.\n\nIf you need more precision, set:\n\n```yml\nprecision: 1\n```\n\n## Multiple Goals\n\nYou can set multiple goals for an experiment to track conversions at different parts of the funnel. First, run:\n\n```sh\nrails generate field_test:events\nrails db:migrate\n```\n\nAnd add to your config:\n\n```yml\nexperiments:\n  button_color:\n    goals:\n      - signed_up\n      - ordered\n```\n\nSpecify a goal during conversion with:\n\n```ruby\nfield_test_converted(:button_color, goal: \"ordered\")\n```\n\nThe results for all goals will appear on the dashboard.\n\n## Analytics Platforms\n\nYou may also want to send experiment data as properties to other analytics platforms like [Segment](https://segment.com), [Amplitude](https://amplitude.com), and [Ahoy](https://github.com/ankane/ahoy). Get the list of experiments and variants with:\n\n```ruby\nfield_test_experiments\n```\n\n### Ahoy\n\nYou can configure Field Test to use Ahoy’s visitor token instead of creating its own:\n\n```ruby\nclass ApplicationController \u003c ActionController::Base\n  def field_test_participant\n    [ahoy.user, ahoy.visitor_token]\n  end\nend\n```\n\n## Dashboard Security\n\n#### Devise\n\n```ruby\nauthenticate :user, -\u003e(user) { user.admin? } do\n  mount FieldTest::Engine, at: \"field_test\"\nend\n```\n\n#### Basic Authentication\n\nSet the following variables in your environment or an initializer.\n\n```ruby\nENV[\"FIELD_TEST_USERNAME\"] = \"moonrise\"\nENV[\"FIELD_TEST_PASSWORD\"] = \"kingdom\"\n```\n\n## Updating Variants\n\nAssign a specific variant to a user with:\n\n```ruby\nexperiment = FieldTest::Experiment.find(:button_color)\nexperiment.variant(participant, variant: \"green\")\n```\n\nYou can also change a user’s variant from the dashboard.\n\n## Associations\n\nTo associate models with field test memberships, use:\n\n```ruby\nclass User \u003c ApplicationRecord\n  has_many :field_test_memberships, class_name: \"FieldTest::Membership\", as: :participant\nend\n```\n\nNow you can do:\n\n```ruby\nuser.field_test_memberships\n```\n\n## Credits\n\nA huge thanks to [Evan Miller](https://www.evanmiller.org/) for deriving the Bayesian formulas.\n\n## History\n\nView the [changelog](https://github.com/ankane/field_test/blob/master/CHANGELOG.md)\n\n## Contributing\n\nEveryone is encouraged to help improve this project. Here are a few ways you can help:\n\n- [Report bugs](https://github.com/ankane/field_test/issues)\n- Fix bugs and [submit pull requests](https://github.com/ankane/field_test/pulls)\n- Write, clarify, or fix documentation\n- Suggest or add new features\n\nTo get started with development:\n\n```sh\ngit clone https://github.com/ankane/field_test.git\ncd field_test\nbundle install\nbundle exec rake compile\nbundle exec rake test\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fankane%2Ffield_test","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fankane%2Ffield_test","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fankane%2Ffield_test/lists"}