Open-source project
qcod/laravel-gamify avatar
qcod/laravel-gamify

laravel-gamify: reputation points and achievement badges for Laravel apps

Gamify your Laravel app with Reputation Points & Achievements Badges support

679 stars70 forksPHPMIT

At a glance

What is it?
The qcod/laravel-gamify package adds a points ledger, badge rules and reputation history to a Laravel application through a trait, a set of point type classes and an artisan generator. It suits teams adding engagement mechanics to an existing app, and it comes with the migration and event plumbing already done.
Who is it for?
laravel-gamify fits a Laravel team that wants points, badges and a reputation ledger in an existing application without building the schema, the undo path and the broadcast event itself. It does not fit a project that needs leaderboards, levels, streaks or any multiplayer rules, because the package covers only points and badges.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 13 days ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the package adds to an existing Laravel app

Laravel Gamify is a Composer package that adds reputation points and achievement badges to an application. The README states the aim in one line: use qcod/laravel-gamify to quickly add reputation point and badges in your Laravel app.

The design assumption is that you already have a Laravel application with users, and that you want to award points for things users do, such as creating a post, and then hand out badges for milestones. The package supplies the parts that would otherwise be hand-built: the database schema for the point ledger, the badge rules, the trait that puts the points total on your user model, the helper functions to award and undo points, and the event that fires when a total changes.

The unit of design is a point type class. A class named PostCreated extends PointType and declares a points value, so the rule for what a post is worth lives in one place in your app code rather than in a configuration table. The generator creates that class for you in the app/Gamify/Points folder, which keeps the package's own code in the vendor directory and your business rules in your application.

The audience is a Laravel developer who wants gamification mechanics as a side feature rather than as a product. It is not a game engine and not a progression system: there is nothing in the README about levels, leaderboards, streaks or teams.

The package is published on Packagist, and the README shows an MIT licence badge alongside a build status badge for the master branch.

Installation, publishing migrations and the doctrine/dbal caveat

Installation is a single Composer command:

bash
$ composer require qcod/laravel-gamify

Service provider registration is handled automatically on Laravel 5.5 and above. The README only asks for manual registration if you are on Laravel 5.4 or lower, in which case you add the provider to the providers array in config/app.php:

php
'providers' => [
    //...
    QCod\Gamify\GamifyServiceProvider::class
]

The next step publishes the migrations for the package tables:

bash
php artisan vendor:publish --provider="QCod\Gamify\GamifyServiceProvider" --tag="migrations"

That generates migrations for the reputations, badges and user_badges tables, plus a migration adding a reputation field to the users table to store the points. The README carries an important operational note: because that last migration drops and adds a column, you need to run composer require doctrine/dbal for it to work. This is a real dependency decision, and on a modern application that already handles column changes without it, the requirement is arguably an artifact of an older approach.

Once published, run the migrations:

bash
php artisan migrate

The config file is published separately, and the README says that if your payee model is App\User then you do not need to change anything in config/gamify.php. That sentence is a small warning about the default assumption baked into the package: the model that receives the points is expected to be the user, and any other model needs configuration.

The Gamify trait and the point type class

The first application-side step is adding the Gamify trait to your user model, or to whichever model acts as the user in your app:

php
use QCod\Gamify\Gamify;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable, Gamify;

From there, points are created as classes. The generator makes one for you:

bash
php artisan gamify:point PostCreated

which creates a PointType class named PostCreated under the app/Gamify/Points folder. The generated class extends PointType, sets a public points property, and defines a payee method that returns the subject's user:

php
class PostCreated extends PointType
{
    public $points = 20;

    public function __construct($subject)
    {
        $this->subject = $subject;
    }

    public function payee()
    {
        return $this->getSubject()->user;
    }
}

The subject is the model the event happened to, in this case the post. The payee is who receives the points, and by default the package looks for a user relation on the subject. You can replace that with a protected payee property set to the relation name, and the README notes in that case you no longer need the payee method at all.

The trait is what puts the API on the model. The README is explicit that it goes on the model that acts as user, so if your application has a different account entity, or if points belong to a team rather than a person, that indirection has to be built around the package rather than by it.

Awarding and undoing points, and the duplicate problem

Awarding happens in a controller. The README shows both calling styles, a helper function and a trait method on the user model:

php
$user = $request->user();
$post = $user->posts()->create($request->only(['title', 'body']));

// you can use helper function
givePoint(new PostCreated($post));

// or via HasReputation trait method
$user->givePoint(new PostCreated($post));

Undoing works the same way in reverse, which is the part that makes the package more than a counter. The README gives the case of a user deleting a post, and shows undoPoint followed by the delete, in both the helper and trait forms.

That undo path is why the package stores an event log rather than only a total. Points are awarded through a ledger, so a wrong award can be reversed instead of being papered over with an adjustment, and the history stays available.

The helper function takes an optional second argument for the payee, since the default is auth()->user(). And the README suggests hooking into Eloquent model events instead, awarding on created and undoing on deleted, which removes the need to remember to call the function in every controller that creates a post.

Duplicates are the sharp edge. By default you can give points multiple times for the same model subject, and a point type class can opt out with a public allowDuplicates property set to false. For a like or a reaction, that flag is the difference between a working feature and a leaderboard full of accidental repeats, so it needs a decision at the point type level rather than at the call site.

Reading totals, the reputation log, and the live update event

The current total is on the user model through getPoints, with an optional formatted form:

php
// get integer point
$user->getPoints(); // 20

// formatted result
$user->getPoints(true); // if point is more than 1000 1K+

The formatted variant returns 1K+ style values, which is a display convenience for a leaderboard or a profile page.

The history comes from a relation on the user model, and the README walks through the fields available on each entry: the name of the point type, the payee user, how many points, and the model on which the point was given.

To ask the question in the other direction, how much reputation a specific post has generated, you define a morphMany relation on the post model:

php
    public function reputations()
    {
        return $this->morphMany('QCod\Gamify\Reputation', 'subject');
    }

That morph relationship is what makes the ledger queryable per subject rather than only per user.

For a live interface, the package fires a ReputationChanged event whenever a user's points change, carrying the user model, the point amount and a boolean saying whether it was an increment. The README notes the event also broadcasts on a configured channel name, so a frontend can listen over a socket and update a points display without polling. The event implements ShouldBroadcast in the example, which means this is Laravel's broadcasting path rather than a custom one.

For real-time use, one caveat: broadcast delivery is only as good as your broadcasting configuration, and the README does not document the channel setup it expects.

Point types can be dynamic, qualified, or computed

Beyond a flat points value, the PointType class supports three variations that the README describes in the configuration section.

The first is a dynamic point amount. If a point should be calculated rather than fixed, you add a getPoints method that does the calculation and returns an integer. The example multiplies one value by ten.

The second is a point qualifier, an optional method returning a boolean. If it returns true the point is given, otherwise it is ignored, which is how you express a rule such as only awarding points the first time a user does something.

The third is the payee resolution, where a protected payee property names the relation on the subject that identifies who gets the points, replacing the payee method.

And there is the duplicate flag, allowDuplicates set to false, which turns off repeated awards for the same subject.

These four knobs are the entire extension surface for point rules, as far as the README documents. Badges work in a similar way to point types, and the README describes them as given to users based on a rule, though the section on badges is cut off in the text available here.

The repository layout backs this up. The src directory holds the package code, database holds the migrations, config holds the package configuration, and tests holds the test suite alongside a phpunit.xml and a pint.json for code style, with the .phpunit.cache directory present as well. The presence of a Pint configuration and a CHANGELOG.md indicates the project keeps a modern Laravel development setup, and the tests directory suggests the behaviour is covered rather than just demonstrated in the README.

Maintenance, licensing and where the package stops

The release history shows a package that keeps up with the framework. Version 1.0.8 was published on 2024-08-24, 1.0.9 on 2025-05-15, and 1.0.10 on 2026-08-17 with a note that it adds Laravel 13 support. The last push to the repository was on 2026-10-10, and the repository is not archived.

The cadence is roughly one or two releases a year, which is about right for a package that mostly has to follow the framework's own release cycle. Because the major version has stayed at 1.0 across those changes, the version number tells you little about compatibility, and the Laravel 13 note in the release title is the informative part.

The licence is MIT, with the licence file named LICENSE.md at the repository root and a Packagist badge confirming it. MIT permits commercial use and modification in an application without conditions, which is what a gamification feature in a commercial product needs.

The boundary of the package is the real consideration. There is no leaderboard, no level system, no streak logic, no team or multiplayer scoring, and no way to express a rule that spans several subjects at once, such as awarding a badge for ten posts by five different authors. The point type class is a single event with a single subject and a single payee. Anything beyond that is application code.

There is also a documentation gap worth noting before you commit. The README is thorough on points and stops mid-sentence in the badges section, so the badge API is not fully described in the README text available to a reader, and the repository has no separate docs directory. Reading the src directory is the way to see how badges are configured.

Editorial conclusion

laravel-gamify fits a Laravel team that wants points, badges and a reputation ledger in an existing application without building the schema, the undo path and the broadcast event itself. It does not fit a project that needs leaderboards, levels, streaks or any multiplayer rules, because the package covers only points and badges. Before adopting it, publish the migrations and check that your user model matches the App\User assumption in config/gamify.php, decide early whether you will use the allowDuplicates flag on point types, and confirm that your Laravel version still supports the service provider auto-discovery path described in the README.

Frequently asked questions

How do I install laravel-gamify in a Laravel app?

Run composer require qcod/laravel-gamify, publish the migrations with the vendor:publish command for the QCod\Gamify\GamifyServiceProvider provider and the migrations tag, then run php artisan migrate.

Why do I need doctrine/dbal to install laravel-gamify?

The README states it is needed to support dropping and adding columns, which the published migration does when it adds the reputation field to the users table.

How do I create a reputation point type in laravel-gamify?

Run php artisan gamify:point PostCreated, which creates a PointType class named PostCreated under the app/Gamify/Points folder where you set the points value and the payee.

Can laravel-gamify award points only once for the same model?

Yes, by default points can be given multiple times for the same subject, and a point type can set a public allowDuplicates property to false to prevent that.

Does laravel-gamify include leaderboards or levels?

The README covers reputation points and achievement badges, with no mention of leaderboards, levels or streak rules, so those would be application code.

Official sources

  1. Issues
  2. License: MIT
  3. qcod/laravel-gamify on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/qcod-laravel-gamify.svg)](https://hysenlabs.com/projects/qcod-laravel-gamify)

Was this useful?