
Recognize when people reach meaningful progress
Value moments describe activity that matters to your product, such as first value or an activation step. Wildo matches declared signals and exposes achieved moments for the application to use.
You define what counts as progress; the framework connects those definitions to application events and persisted achievement state.
Example — Recognize a first useful action
A product defines its first completed action as a value moment. Once the matching signal is observed, an onboarding surface can reflect the achievement instead of inferring progress from page visits alone.
For engineers
Declare the meaning before collecting the signal
Use the application’s shared analytics configuration and enable its analytics capability. This illustrative declaration uses a custom event, so the application controls exactly when the meaningful action has happened:
analytics: {
enabled: true,
providers: [],
valueMoments: [{
identifier: 'first-useful-result',
role: ValueMomentRole.TTFV,
scope: ValueMomentScope.USER,
mode: ValueMomentMode.ANY,
signals: [{
signalType: ValueSignalType.CUSTOM_EVENT,
eventName: 'useful-result-completed',
}],
onAchieved: {
frontendEvent: true,
},
}],
},
Import the four enums from @wildo-ai/saas-models. This is an illustrative configuration fragment, not an existing Wonder Todos moment. An empty provider list allows internal progression without selecting an external analytics destination; frontend evaluation still follows the analytics context’s activation and consent conditions.
After the successful application action, useAnalytics().track('useful-result-completed', properties) supplies the custom event. Emit success only after the action succeeds, and keep its properties appropriate for the selected collection policy. A backend can emit its own custom signal through ValueMomentEngineBackendService.emitSignal when that is the relevant source.
Choose signals and scope deliberately
| Choice | Meaning |
|---|---|
| Resource operation | Match the named operation, optionally with shallow field filters |
| Resource state | Compare a scoped record count with a threshold |
| View/feature/custom event | Observe a browser or explicitly emitted application event |
| ANY / ALL | One qualifying signal or all declared signals |
| User / organization | Whose progression state owns the achievement |
| Anti-pattern | A repeatable signal with cooldown, not a persisted achievement |
A record-state signal needs the expected scope field and repository. The backend applies the moment’s scope when counting. Filters compare primitive values by shallow equality; they are not a query language.
Match the example to its evaluator
The single custom-event ANY example above does not need occurrence counting or multi-signal accumulation. More elaborate declarations cross different evaluation paths:
| Contract | Browser | Backend |
|---|---|---|
| Custom/operation occurrence threshold | Counts occurrences | Currently handles the first matching event without that counter |
| Anti-pattern prerequisites and stage suppression | Evaluated before reaction | The anti-pattern branch goes directly to scope/cooldown handling |
| Anti-pattern ALL composition | Accumulates required signals | A matching signal can invoke the reaction without accumulating ALL |
| Ordinary ALL progress | Accumulates observed signals | Persists progress, but concurrent partial writes can overwrite each other |
These distinctions matter when choosing which side owns a product reaction. Do not base access or accounting on analytics progression. A single-event progress indicator and a coordinated multi-event workflow need different guarantees; the latter should have its own application state and transaction rules.
Follow persistence and the reaction
Ordinary achievements are stored on the progression-state row in valueMomentsAchieved, separately from authored milestones. Backend writes guard against an existing achievedAt. getAchievedMoments reads user and organization state; the browser’s backend-sync path restores more than local storage alone.
The achievement callback can raise the frontend event or resolve a registered backend handler. Register a named handler before referring to it. The persistence outcome distinguishes recorded, already achieved, absent scope and failed persistence; do not treat an accepted HTTP request as an unqualified accounting guarantee.
ANTI_PATTERN intentionally does not persist achievement and uses an in-process cooldown. This is product guidance and behavioral measurement, not an authorization decision or a financial ledger. Design the application reaction accordingly.