Account Age Loyalty Bonus
6 min read
- View as Markdown Open this page as plain Markdown (opens in a new tab)
- Open in ChatGPT Ask questions about this page (opens in a new tab)
- Open in Claude Ask questions about this page (opens in a new tab)
- Open in Google AI Studio Ask questions about this page (Google account required) (opens in a new tab)
The account-age bonus is a small positive contribution to the trust score that rewards customers who’ve been ordering from your store for a long time. It’s not strictly a module signal — it’s computed by the scoring engine itself after module signals are collected — but it appears in the signal breakdown like any other contribution. This guide explains exactly how the bonus works, why it exists, and how it interacts with the rest of the scoring model.
The Three Tiers #
The bonus is stepped, not continuous. There are three tiers, with the boundaries measured from the customer’s first order date:
| Tenure | Bonus | Reason Text Shown on Profile |
|---|---|---|
| 1+ year (365 days or more) | +15 | Long-term customer (1+ year) |
| 6+ months (180–364 days) | +10 | Established customer (6+ months) |
| 3+ months (90–179 days) | +5 | Regular customer (3+ months) |
| < 3 months (under 90 days) | 0 | (no signal recorded) |
Tiers are mutually exclusive — only the highest tier the customer qualifies for is applied. A customer who has been a customer for 18 months gets +15, not +5 + +10 + +15.
How Tenure Is Measured #
The clock starts at the date of the customer’s first WooCommerce order, not their WordPress account creation date. This means:
- Guest checkouts count — the first guest order on the email establishes tenure
- WordPress accounts created but never used to place an order do not earn a bonus
- If a customer’s first order was 8 months ago but they only just placed their second order today, they still get the +10 bonus — the bonus reflects relationship tenure, not order frequency
The exact first-order date is stored in the customer’s first_order_date column. Historical Sync sets it to the date of the customer’s earliest order (completed, processing, refunded or cancelled); after activation it is set when a new customer’s first order is placed at checkout.
Why It’s Tiered, Not Continuous #
A continuous bonus — say, +0.04 points per day of tenure — would produce smoother score trajectories but introduce noise:
- Scores would change daily for every customer, just from the clock ticking
- The signal breakdown would never be a clean integer, undermining the auditability of the calculation
- Action Scheduler would need to recompute every customer every day, which scales poorly
The tiered design produces three notable “graduation” events per customer over the first year, each of which:
- Is a meaningful behavioral milestone you might want to act on
- Shows up clearly on the score trend chart as a step up
- Fires the
trustlens/segment_changedaction if it crosses a segment boundary
So a customer who’s been quietly Trusted for months can be promoted to VIP automatically at their first recalculation after the 1-year anniversary — and Pro automation rules can trigger on that event.
When the Bonus Is Applied #
The bonus is recomputed every time the trust score is recalculated. Since recalculations are event-driven (triggered by new orders, refunds, disputes, etc.), the bonus tier graduation doesn’t trigger a recalc on its own — there’s no daily cron checking who just crossed 90 days.
In practice this rarely matters because active customers place orders regularly enough that their score is recalculated and the new tier is picked up. For customers who are completely dormant, the bonus tier may lag behind their actual tenure until they place another order. This is by design — dormant customers don’t need their score updated.
If you do want the bonus tier reflected immediately (e.g. to set up a “5-year anniversary VIP” automation), you can:
- Use the Recalculate button on the customer detail page
- Bulk-recalculate from the Customers list
- Trigger recalculation via REST API:
POST /wp-json/trustlens/v1/customers/{hash}/recalculate
Interaction with the Allowlist #
The allowlist short-circuits scoring entirely — allowlisted customers get exactly 100 and no module signals are computed. The account-age bonus is therefore not applied to allowlisted customers; it doesn’t need to be, since they’re already at the maximum score.
If you remove a customer from the allowlist, the next recalculation includes the age bonus normally.
Interaction with the Full-Confidence Order Threshold #
Below the Full-confidence Order Threshold (Settings → General, default 3), most detection modules wait for more history — but the age bonus is still applied. A customer who placed one order 14 months ago and just placed a second order today gets the +15 bonus even though they haven’t reached 3 orders yet.
The same is true of the confidence-weighted Returns signal and linked-account penalties: they all count below the threshold, so a sub-threshold customer’s score can move away from 50 in either direction.
Capping Behavior #
The age bonus is a positive contribution and adds directly to the score. If a customer’s score before the bonus is 92 (already VIP), adding +15 would push them to 107, but the final clamp at 100 caps the displayed score. The internal arithmetic still includes the bonus — it’s just that the display can’t exceed 100.
Practically: the bonus is most impactful at the segment boundaries (lifting a 65 to 75 = Normal → Trusted; lifting an 85 to 100 = Trusted → VIP). At the extremes (very low or very high pre-bonus scores), the bonus has less proportional effect.
Worked Examples #
Example 1: New customer reaches 3 months #
- Tenure: 92 days
- Pre-bonus score: 55 (4 orders, no refunds: +5 from the Orders module’s 3+ clean orders tier)
- Bonus: +5 (3+ months)
- Final score: 60 (Normal)
Example 2: Established customer reaches 6 months #
- Tenure: 182 days
- Pre-bonus score: 65 (8 clean orders: +10 from the Orders module; coupons used on 3 orders with no refunds: +5 from Coupons)
- Bonus: +10 (6+ months)
- Final score: 75 (Trusted)
Example 3: Long-tenured customer reaches 1 year #
- Tenure: 367 days
- Pre-bonus score: 75 (10+ clean orders: +15 from Orders; no disputes on 10+ orders: +10 from Chargebacks)
- Bonus: +15 (1+ year), replacing the +10 they had at 6 months (score 85, Trusted)
- Final score: 90 (VIP) — promotion at the first recalculation after the anniversary
Example 4: Bonus offsetting negative signals #
- Tenure: 2 years
- Pre-bonus score: 35 (recent refund spike: -20 from a high return rate, offset by +5 from Orders)
- Bonus: +15 (1+ year)
- Final score: 50 (Normal) — the tenure cushions the recent issue but doesn’t erase it
Example 4 is important. Long tenure does not insulate a customer from negative signals — it raises the floor. A long-tenured customer with a recent abuse pattern still drops segments; they just drop one tier less than an equivalent new customer would.
Customizing the Bonus #
The bonus tiers are hard-coded in the scoring engine and not exposed as settings. If you need to customize them (e.g. add a 2-year tier, or move the 6-month threshold), use the trustlens/score_signals filter to modify the account_age signal after it’s been added:
add_filter( 'trustlens/score_signals', function( $signals, $email_hash ) {
$customer = wstl_get_customer( $email_hash );
if ( ! $customer || empty( $customer->first_order_date ) ) {
return $signals;
}
$days = ( time() - strtotime( $customer->first_order_date ) ) / DAY_IN_SECONDS;
// Remove the built-in account_age signal
$signals = array_values( array_filter( $signals, function( $s ) {
return $s['module'] !== 'account_age';
} ) );
// Add custom tiers
if ( $days >= 730 ) { // 2 years
$signals[] = array(
'module' => 'account_age',
'score' => 20,
'reason' => 'Veteran customer (2+ years)',
);
} elseif ( $days >= 365 ) {
$signals[] = array(
'module' => 'account_age',
'score' => 15,
'reason' => 'Long-term customer (1+ year)',
);
}
// ... etc
return $signals;
}, 20, 2 );
The filter runs after the built-in bonus is computed, so removing the built-in signal first is what gives custom code full control.
Why the Maximum Is +15 #
The cap is deliberate. Positive signals across the entire scoring engine are bounded; only negative signals stack arbitrarily. The maximum theoretical positive sum across all modules and the age bonus is roughly +50:
- Orders 10+ clean orders bonus: +15
- Orders $1,000+ net spend bonus: +5
- Chargebacks no-dispute bonus (10+ orders): +10
- Coupons legitimate-user bonus: +5
- Account age 1+ year: +15
That puts the ceiling for an organic VIP at 50 (base) + 50 (positives) = 100. Without the age bonus, the ceiling would be 85 — meaning no customer could ever reach VIP organically without allowlisting. The +15 cap is what makes the top tier accessible to long-tenured customers who haven’t been allowlisted.
Raising the cap (say, to +30) would push more customers into VIP and dilute the segment’s meaning. Lowering it would make VIP effectively allowlist-only. +15 is the value that produces a meaningful “earned VIP” tier without flooding it.
Auditing the Bonus on a Customer #
To verify the bonus on any customer:
- Open their customer detail page
- Look at the first order date field
- Calculate days between then and now
- Match against the tier table — you should see the corresponding signal in the breakdown
If the tenure looks right but the bonus signal isn’t showing, the most common causes are:
- Customer hasn’t been recalculated since the tier graduation — click Recalculate
- Customer is allowlisted (short-circuits)
- A custom filter is removing or modifying the signal
For new customers, the first-order date is recorded when their first order is placed at checkout (by the Order Tracking module, so it needs that module switched on), whatever the order’s later status. If the date is missing, run Historical Sync to fill it from your order history.
Updated on October 18, 2026