Events & persistence
Every moment of a tour is published as an event, including how long each step was on screen.
Subscribe to IBonboardingService.EventRaised for something quick, or register an
IBonboardingObserver in DI to forward the stream to your analytics provider.
Live event stream
Active projects
12
Usage this month
68%
Team members
7
Nothing yet. Start the tour above.
Persistence
Progress is written to the registered IBonboardingStore after every step. The default
store uses localStorage with an in-memory mirror, so reads still work while
prerendering and in private browsing. Swap it for a server-side store with one call.
Wiring it up
public sealed class TourAnalytics(IAnalyticsClient client) : IBonboardingObserver
{
public ValueTask OnEventAsync(BonboardingEvent e, CancellationToken ct = default)
{
return e.Kind switch
{
BonboardingEventKind.StepShown =>
client.TrackAsync("tour_step_shown", new
{
tour = e.Tour.Id,
step = e.Step?.Id,
position = e.StepIndex,
}),
BonboardingEventKind.StepLeft =>
client.TrackAsync("tour_step_left", new
{
step = e.Step?.Id,
ms = e.Duration?.TotalMilliseconds,
}),
BonboardingEventKind.TourCompleted or BonboardingEventKind.TourSkipped =>
client.TrackAsync("tour_ended", new { tour = e.Tour.Id, reason = e.Reason }),
_ => ValueTask.CompletedTask,
};
}
}
builder.Services.AddBitBonboardingObserver<TourAnalytics>();A custom store
public sealed class ProfileOnboardingStore(IUserProfiles profiles) : IBonboardingStore
{
public ValueTask<BonboardingRecord?> GetAsync(string tourId, CancellationToken ct = default)
=> profiles.GetOnboardingAsync(tourId, ct);
public ValueTask SetAsync(BonboardingRecord record, CancellationToken ct = default)
=> profiles.SaveOnboardingAsync(record, ct);
public ValueTask RemoveAsync(string tourId, CancellationToken ct = default)
=> profiles.DeleteOnboardingAsync(tourId, ct);
public ValueTask ClearAsync(CancellationToken ct = default)
=> profiles.DeleteAllOnboardingAsync(ct);
}
builder.Services.AddBitBonboardingServices();
builder.Services.AddBitBonboardingStore<ProfileOnboardingStore>();