Weave 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 that summarizes database changes over time. Define a stats class, call increase() or decrease() as events happen, then query totals grouped by day, week, or month, returning increments, decrements, and net differences for each period.

View on GitHub
Deep Wiki
Context7

Product Decisions This Supports

  • Build vs. buy for product analytics. This package makes the case for not standing up a third-party analytics vendor (Mixpanel, Amplitude, Segment) or a BI stack when the questions you actually need answered are narrow: "is this number going up, and how fast?" For a subscription count, active seats, open orders, tickets resolved, or credits consumed, increase/decrease/set plus a grouped query gets you a defensible trend line for the cost of one Composer dependency and one migration.
  • Instrumentation as a roadmap commitment. Adding a SubscriptionStats class is a deliberate product statement: this metric is a first-class KPI, owned by the app, versioned with the codebase, and queryable by any future feature (dashboards, admin panels, customer-facing reporting, internal alerting). It makes "we should track X" a one-hour ticket instead of a vendor-integration project.
  • Net-growth framing, not vanity totals. The returned DataPoint carries value, increments, decrements, and difference per period. That distinction drives real decisions: a flat subscription count with high increments and high decrements is churn-masked-by-acquisition, and the data model surfaces it without extra work.
  • Multi-tenant and segmented reporting. StatsWriter::for($tenant->orderStats(), ['payment_type' => 'recurring']) and the matching StatsQuery::for(...) let you scope a metric per customer, per plan, or per channel. This is the difference between "revenue is up" and "revenue is up only in the self-serve segment, and declining in enterprise" — an actual roadmap input.
  • Day-one dashboards via backfill. increase(1, $subscription->created_at) writes an event as if it happened in the past. You can seed history from existing tables on launch day and ship a chart with twelve months of trend instead of an empty graph and a three-month waiting period.
  • External source-of-truth reconciliation. set($count) handles metrics your app doesn't own (Stripe subscription counts, warehouse job totals, third-party API quotas) — useful when deciding whether to trust a vendor's billing dashboard or your own numbers, and for detecting drift between them.
  • Cheap experimentation readouts. Per-plan, per-flow, or per-feature-flag counters scoped by custom columns let you answer "did the onboarding change move activation?" without a data team or an experiment platform, provided you're willing to define the metric before shipping.
  • Data residency and privacy by default. Metrics live in your database. For teams where sending per-user behavioural data to a US SaaS is a legal or procurement problem, an aggregate counter is often an acceptable substitute for an event stream.

When to Consider This Package

Adopt when:

  • You are on Laravel (this release line supports Laravel 9 through 13, PHP 8.2+) and your team already reads Spatie packages as low-risk, idiomatic code.
  • The metric is a single scalar over time — a count, a balance, a gauge. Subscriptions, seats, open tickets, inventory units, credits, active workspaces.
  • You control the write path (you can call increase/decrease in the same transaction or job as the domain event), or you can poll an external number into set().
  • You need the trend inside the product — admin dashboards, customer-facing usage charts, internal ops views — rather than in a BI tool.
  • You want per-entity segmentation (tenant, plan, region) but not arbitrary ad-hoc slicing.
  • Write volume is modest: one row per change event. Tens of thousands to low millions per year is comfortable; hundreds of millions is not.
  • You value exit optionality. The schema is a type/value/timestamps table; migrating off means writing one export query.

Look elsewhere when:

  • You need funnels, retention cohorts, sessionisation, or per-user event streams. This is aggregate arithmetic, not an analytics platform. Reach for a warehouse (dbt + BigQuery/Snowflake) or a product analytics vendor.
  • You need arbitrary slicing and ad-hoc exploration. Custom columns cover a handful of dimensions; anything resembling "group by any of nine attributes" belongs in a columnar store.
  • Volume is very high or bursty. Every increment is an insert. High-traffic counters will bloat the table and stress the group-by queries; consider pre-aggregated rollups, Redis counters flushed periodically, or a time-series store.
  • You need a UI. There is none. You are building the chart layer yourself (or pairing with a charting library). The package ships data, not dashboards.
  • You need sub-second real-time. Period grouping is SQL over historical rows; "live now" counts are better served by a cache or a streaming metric system.
  • Correctness is regulated. Counters that must reconcile to the cent (financial ledgers, billing) need immutable double-entry records, not increment/decrement deltas that can drift if a write is missed or double-fired. Use set() from the authoritative source, or don't use this at all for that number.
  • Your write path is unreliable. decrease called without a matching increase (missed webhook, retried job, refund) silently corrupts the running value. You need idempotency keys or reconciliation jobs around it — budget for that.
  • Adoption signal matters to you. 451 stars and zero listed dependents is a thin ecosystem. The Spatie pedigree, MIT licence, changelog discipline, and steady Laravel-version support are real mitigations, but this is a small, narrowly-scoped library — treat it as a component you could fork or replace in a day, not a platform bet.

Operational caveats to plan for: define a retention/pruning policy before the table grows unbounded; index type and the timestamp column; decide whether stats writes belong in the same transaction as the domain change (consistency) or in an async job (latency); and document, per metric, exactly which domain events are allowed to call increase and decrease, because that invariant is the entire correctness model.

How to Pitch It (Stakeholders)

For executives: We need trend data on a handful of core numbers — subscriptions, active seats, order volume — and today we either don't have it or pay a vendor for it. This is a free, MIT-licensed Laravel component that stores those counters in our own database and returns them grouped by day, week, or month. It replaces, for our narrow use case, a five- or six-figure annual analytics contract, keeps the data in-house (no new data-processing agreement, no PII leaving our systems), and takes roughly a day to integrate per metric. Crucially, it is a building block, not a lock-in: the underlying table is plain and exportable, and the whole thing can be removed or replaced without touching product features. The trade-off is scope — it gives us counts over time, not user-level behavioural analytics or funnels. If we later need those, we still buy the bigger tool; this doesn't foreclose that decision, it just stops us from buying it prematurely.

For engineering: Small, well-maintained Spatie package, MIT, actively released and tracking current Laravel and PHP versions, with MySQL, PostgreSQL, and SQLite support. Integration is a published migration, a BaseStats subclass, and increase/decrease/set calls at the domain events — plus a fluent query builder for period grouping with increments, decrements, and net difference. It supports scoping to Eloquent models and HasMany relationships, which covers per-tenant reporting, and accepts explicit timestamps so we can backfill history from existing tables. No UI, no queues, no external services, no new infrastructure. Main engineering obligations: define the write-path invariants per metric so counters can't drift, add indexes and a retention policy, and treat high-volume counters as a separate problem. Low blast radius — one table, one trait, and the code is small enough to fork if we ever need to.

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.
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel