PHPackages                             jamesblackwell/laravel-ab-testing - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. jamesblackwell/laravel-ab-testing

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

jamesblackwell/laravel-ab-testing
=================================

A/B Testing package for Laravel using Pennant

52.2k↓50%[3 issues](https://github.com/jamesblackwell/laravel-ab-testing/issues)PHP

Since May 21Pushed 12mo ago2 watchersCompare

[ Source](https://github.com/jamesblackwell/laravel-ab-testing)[ Packagist](https://packagist.org/packages/jamesblackwell/laravel-ab-testing)[ RSS](/packages/jamesblackwell-laravel-ab-testing/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependenciesVersions (1)Used By (0)

[![A/B Testing Dashboard Screenshot](https://camo.githubusercontent.com/f3ca90e355ed6620164522427ca3079d3be62aa05a1653d88cec53c292aff773/68747470733a2f2f696d61676564656c69766572792e6e65742f317770576d6f4f46304b2d595f4e784c4a4f336532772f62353165343261612d326432342d343037302d343466312d3964323163653234313230302f7075626c6963)](https://camo.githubusercontent.com/f3ca90e355ed6620164522427ca3079d3be62aa05a1653d88cec53c292aff773/68747470733a2f2f696d61676564656c69766572792e6e65742f317770576d6f4f46304b2d595f4e784c4a4f336532772f62353165343261612d326432342d343037302d343466312d3964323163653234313230302f7075626c6963)

Laravel A/B Testing
===================

[](#laravel-ab-testing)

A simple, robust A/B testing framework for Laravel using [Laravel Pennant](https://laravel.com/docs/10.x/pennant).

- **Code driven** - define experiments using Laravel Pennant. Track views and conversions in your code.
- **Zero flicker** - determine variants before rendering, no calls to external services.
- **Privacy friendly** - keep all data on server.
- **Admin dashboard** for real-time results and statistical significance
- **Supports primary and secondary goals** - track multiple goals per experiment.

Quickstart
----------

[](#quickstart)

1. Install `composer require quizgecko/laravel-ab-testing` and run the migrations.
2. [Define a Pennant Feature](https://laravel.com/docs/12.x/pennant#defining-features) with a 'test' and 'control' variant.
3. Use `feature_flag('example-experiment', $userOrUniqueId)` to get the variant and display the variation to the user e.g. a different view code block in your views.
4. Use `experiment_view('example-experiment', $userOrUniqueId)` to track views.
5. Use `experiment_conversion('example-experiment', $userOrUniqueId)` to track conversions. Optionally track secondary conversions with `experiment_secondary_conversion('example-experiment', $userOrUniqueId)`.
6. View results in admin dashboard at `yoursite.com/admin/ab`.

Motivation
----------

[](#motivation)

Laravel Pennant is a great package to handle feature flags, however it still requires you to setup a lot of tracking to run actual A/B tests. This package works on top of Pennant and adds various easy to use helpers to track views and conversions, then displays the results in a dashboard.

---

Installation
------------

[](#installation)

```
composer require quizgecko/laravel-ab-testing
```

Publish and run the migration:

```
php artisan vendor:publish --tag=ab-testing-migrations
php artisan migrate
```

Publish the configuration file (optional):

```
php artisan vendor:publish --tag=ab-testing-config
```

---

Setup
-----

[](#setup)

1. **Define Experiments**

Define your experiments in a service provider (e.g., `AppServiceProvider`). Use the `Feature` facade from Laravel Pennant. Always use a descriptive, kebab-case name including month/year.

Important: currently only two variants are supported and the Feature should return `'test'` or `'control'`. You can also return `'not-in-experiment'` to exclude a user from the experiment. Only variants with `'test'` or `'control'` are considered in the admin dashboard.

```
use Illuminate\Support\Facades\Feature;
use Illuminate\Support\Arr;
use App\Models\User;

Feature::define('homepage-signup-copy-april-2025', function ($scope) {
    // Exclude paid users
    if ($scope instanceof User && $scope->is_paid) {
        return 'not-in-experiment';
    }
    // 50/50 split for guests and free users
    return Arr::random(['test', 'control']);
});
```

- **Scope**: Use `$scope` as either a `User` or a guest ID (like `abid()`).
- **Return values**: `'test'`, `'control'`, or `'not-in-experiment'`.

2. **Check Variant in Code**

Use the `feature_flag()` helper to get the assigned variant:

```
$variant = feature_flag('homepage-signup-copy-april-2025', $userOrUniqueId);
if ($variant === 'test') {
    // Show test variation
} elseif ($variant === 'control') {
    // Show control
} else {
    // Not in experiment
}
```

3. **Track Views and Conversions**

Call these helpers at the appropriate places:

```
experiment_view('homepage-signup-copy-april-2025', $userOrUniqueId); // When user sees the experiment
experiment_conversion('homepage-signup-copy-april-2025', $userOrUniqueId); // When user completes the primary goal
experiment_secondary_conversion('homepage-signup-copy-april-2025', $userOrUniqueId); // For secondary goals
```

- Always pass the same scope (`User` or `abid`) as used in the feature definition.
- Views are only tracked once per user/guest per experiment.
- Conversions are only tracked if a view was previously tracked.

---

Admin Dashboard
---------------

[](#admin-dashboard)

Visit `/admin/ab` (requires `auth` and `can:viewAdmin`) to see:

- All running experiments
- Views, conversions, conversion rates for each variant
- Statistical significance (p-value, confidence)
- Primary and secondary goal tracking

---

Helper Functions
----------------

[](#helper-functions)

- `feature_flag($experimentName, $scope = null)`
- `experiment_view($experimentName, $scope = null, $variant = null)`
- `experiment_conversion($experimentName, $scope = null)`
- `experiment_secondary_conversion($experimentName, $scope = null)`
- `abid()`

abid
----

[](#abid)

The `abid()` function returns a unique identifier for the current user or guest. It is used to track views and conversions for anonymous users.

```
$abid = abid();
```

For example, if you wanted to test a signup flow, use the abid as the scope:

```
$variant = feature_flag('homepage-signup-copy-april-2025', abid());
```

---

Database
--------

[](#database)

The package creates an `experiments` table:

- `experiment_name` (string)
- `variant` (string)
- `total_views` (int)
- `conversions` (int)
- `secondary_conversions` (int)

---

Best Practices
--------------

[](#best-practices)

- Use descriptive, kebab-case experiment names with month/year.
- Always pass the correct scope (User or abid) to helpers.
- Remove old experiments and helpers when finished.
- Place `experiment_view()` where the user meaningfully sees the experiment.
- Place `experiment_conversion()` where the primary goal is completed.
- Remove unused features from Pennant when done to prevent table bloat.
- Delete older experiments from the database to keep it clean.

---

License
-------

[](#license)

MIT

###  Health Score

19

—

LowBetter than 10% of packages

Maintenance25

Infrequent updates — may be unmaintained

Popularity25

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity14

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/470aac6ba5fdc2719cfe75875ba91477e6341b08e197e629fb40affadd58f77a?d=identicon)[jamesblackwell](/maintainers/jamesblackwell)

---

Top Contributors

[![jamesblackwell](https://avatars.githubusercontent.com/u/1156154?v=4)](https://github.com/jamesblackwell "jamesblackwell (24 commits)")

---

Tags

ab-testinglaravelpennant

### Embed Badge

![Health badge](/badges/jamesblackwell-laravel-ab-testing/health.svg)

```
[![Health](https://phpackages.com/badges/jamesblackwell-laravel-ab-testing/health.svg)](https://phpackages.com/packages/jamesblackwell-laravel-ab-testing)
```

###  Alternatives

[plugowski/iptables

Class to manage entries in iptables.

131.6k](/packages/plugowski-iptables)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
