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>();

Rejoining the server...

Rejoin failed... trying again in seconds.

Failed to rejoin.
Please retry or reload the page.

The session has been paused by the server.

Failed to resume the session.
Please retry or reload the page.