Updated 8 July 2026
In Bagisto, a seller dashboard shows sales, orders and payouts. A Seller Account Health Score answers the harder question: am I about to be suspended?
Our multi-vendor marketplace needed a quality signal, not another revenue chart — one screen a seller reads in a second.
The good news is that no new tables are needed. The numbers already exist; they have simply never been added together.
A marketplace already records every cancelled order, every review, and every flag a customer raises against a store.
Those three facts live on three different screens, so nobody ever reads them together.
The quick fix is to warn on each metric on its own:
|
1 2 3 4 5 6 7 |
if ($cancellationRate > 5) { $warnings[] = 'Too many cancellations'; } if ($averageRating < 3) { $warnings[] = 'Rating too low'; } |
This passes a seller with a 4% cancellation rate and a 2.1 rating, because no single rule is broken.
It also never ranks the problems, so the seller cannot tell which one is costing them the most orders.
Cancellations sit on order items, feedback on seller reviews, and flags on the seller flag table.
Each metric that has data takes an equal share of 100 points — a third each, a half each, or all of it.

Every metric is first reduced to a goodness between 0 and 1, where 1 means nothing is wrong.
|
1 2 3 4 5 6 7 8 |
// The Seller Account Health Score shares 100 points between the metrics that count. $weight = 100 / (1 + ($hasReviews ? 1 : 0) + ($flagsEnabled ? 1 : 0)); $goodness = [ 'cancellation' => 1 - min(1, $cancellationRate / 100), 'feedback' => $averageRating / 5, 'flags' => 1 - min(1, $flagCount / $redFlagLimit), ]; |
A metric earns its full share only when it is perfect. Every point it falls short is then deducted a second time.
|
1 2 |
// Full weight at goodness 1, nothing at 0.5, and negative below that. $contribution = $weight * (2 * $goodness - 1); |
Because the shares always total 100, the Seller Account Health Score reduces to one identity: score = R − (100 − R).
|
1 2 3 4 5 6 7 |
$score = (int) round(min(100, max(0, array_sum($contributions)))); $band = match (true) { $score <= 33 => 'unhealthy', $score <= 66 => 'at-risk', default => 'healthy', }; |
The maths is plain arithmetic; a single round() keeps the result an integer between 0 and 100.
A controller asks the helper once per request and hands the finished scorecard straight to the view.
Weighting is a product decision, not a technical one, so every threshold lives in a constant that can be tuned.
Flags only count when the admin enables flagging, so a seller is never punished by a feature they cannot see.
A metric with no data is skipped, not scored zero — otherwise every new seller would open the page already unhealthy.
Reads go through repositories and Eloquent relations, exactly as in our note on reading extended protected properties.
A Seller Account Health Score adds no data. It gives meaning to the data a marketplace has collected all along.
Show one number, explain the arithmetic behind it, and let the seller fix the metric that actually costs them orders.
If you have more details or questions, you can reply to the received confirmation email.
Back to Home
Be the first to comment.