Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Stats Laravel Package

spatie/laravel-stats

Lightweight Laravel package to track stat changes in your app over time. Create a stats class, call increase/decrease on events (e.g., subscriptions), then query totals, increments, decrements, and differences grouped by day/week/month for any date range.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require spatie/laravel-stats
    

    Publish the migration (if using database storage):

    php artisan vendor:publish --provider="Spatie\Stats\StatsServiceProvider" --tag="migrations"
    php artisan migrate
    
  2. Define a Stats Class: Create a class extending BaseStats in app/Models/Stats (or your preferred namespace):

    namespace App\Models\Stats;
    
    use Spatie\Stats\BaseStats;
    
    class UserStats extends BaseStats {}
    
  3. First Usage: Track an event (e.g., user signups):

    UserStats::increase(); // Increment count on signup
    

    Query historical data:

    $stats = UserStats::query()
        ->start(now()->subDays(7))
        ->end(now())
        ->get();
    

Key First Use Case

Track daily active users (DAU):

// Increment on user activity
UserActivityStats::increase();

// Query DAU for last 30 days
$dau = UserActivityStats::query()
    ->start(now()->subDays(30))
    ->end(now())
    ->groupByDay()
    ->get();

Implementation Patterns

Core Workflows

  1. Event-Driven Tracking: Use increase()/decrease() in:

    • Controllers (e.g., UserController@store).
    • Observers (e.g., UserObserver@created).
    • Jobs (e.g., ProcessSubscriptionJob). Example:
    // In UserObserver
    public function created(User $user) {
        UserStats::increase();
    }
    
  2. Querying Patterns:

    • Time Ranges:
      // Last 7 days
      Stats::query()->start(now()->subDays(7))->end(now())->get();
      
    • Grouping:
      // Monthly trends
      Stats::query()->groupByMonth()->get();
      
    • Aggregations:
      // Total sum over time
      Stats::query()->sum();
      
  3. Custom Storage: Extend BaseStats to use Redis or custom logic:

    class RedisUserStats extends BaseStats {
        protected $storage = 'redis';
    }
    

Integration Tips

  • Laravel Events: Bind stats updates to events:
    event(new UserRegistered($user));
    // In listener:
    UserStats::increase();
    
  • API Endpoints: Create a resource route for stats:
    Route::get('/stats/dau', function () {
        return UserStats::query()->groupByDay()->get();
    });
    
  • Scheduling: Use Laravel Scheduler to reset daily stats:
    // In App\Console\Commands\ResetDailyStats
    UserStats::resetDaily();
    

Gotchas and Tips

Pitfalls

  1. Database Locking:

    • Concurrent increase()/decrease() calls may cause race conditions.
    • Fix: Use database transactions or Redis for high-traffic apps.
    DB::transaction(function () {
        UserStats::increase();
    });
    
  2. Time Zone Handling:

    • Queries use the server’s timezone by default.
    • Fix: Set timezone explicitly:
    Stats::query()->start(now('America/New_York')->subDays(7))->get();
    
  3. Grouping Edge Cases:

    • groupByWeek()/groupByMonth() may include empty days if no data exists.
    • Fix: Use groupByWeek()->whereNotNull('value') or handle gaps in frontend.
  4. Migration Conflicts:

    • If using custom storage, ensure the stats table exists or skip migrations:
    // In StatsServiceProvider
    public function boot() {
        if (!config('stats.use_database')) {
            Schema::hasTable('stats') || $this->createStatsTable();
        }
    }
    

Debugging

  • Missing Data: Verify increase()/decrease() is called in the correct context (e.g., middleware vs. controller).
    php artisan tinker
    UserStats::query()->get(); // Check raw data
    
  • Query Performance: Add indexes to stats table:
    Schema::table('stats', function (Blueprint $table) {
        $table->index(['stat_key', 'date']);
    });
    

Extension Points

  1. Custom Metrics: Extend BaseStats to support multi-dimensional stats:
    class UserRegionStats extends BaseStats {
        public function increase(string $region) {
            $this->increment($region);
        }
    }
    
  2. Storage Adapters: Implement Spatie\Stats\StatsRepository interface for custom storage (e.g., DynamoDB).
  3. Webhooks: Trigger external notifications on stat changes:
    // In BaseStats
    protected static function afterIncrement() {
        Http::post('https://api.example.com/webhook', ['stats' => self::get()]);
    }
    

Pro Tips

  • Normalize Stat Keys: Use consistent keys (e.g., user_signups, user_cancellations) for clarity.
  • Cache Queries: Cache frequent queries (e.g., dashboard stats):
    $stats = Cache::remember('dau_last_7_days', now()->addDays(1), function () {
        return UserStats::query()->groupByDay()->get();
    });
    
  • Visualization: Pair with Laravel Charts or Highcharts for dashboards:
    // Example with Laravel Charts
    Charts::dataset('line', [0, 10, 5, 20])
         ->title('User Growth')
         ->colors(['#4CAF50']);
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport