Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Onboarding Laravel Package

wallacemartinss/filament-onboarding

Database-driven onboarding for Filament v5: a progress checklist that follows users across every panel page, guided spotlight tours, video steps, and condition-based steps that complete automatically so existing users enter journeys already partly done.

View on GitHub
Deep Wiki
Context7

Getting Started

Confirm which line you are on — the version constraint changed. This package now ships two parallel lines that share a source tree and differ only in Composer constraints and Livewire internals:

  • 1.x → Filament v4. v1.2.0 is the backport of the 2.6.0 changes onto v4.
  • 2.x → Filament v5.

Earlier guidance said “Filament v5 only” — that is no longer true and was already misleading for the 1.x line. Check composer.json for the exact filament/filament constraint and pick the matching major of this package before requiring it. Getting this wrong is a Composer resolution fight, not a runtime warning.

Install and publish:

composer require wallacemartinss/filament-onboarding

php artisan vendor:publish --tag="filament-onboarding-config"
php artisan vendor:publish --tag="filament-onboarding-migrations"
php artisan migrate

php artisan filament:assets

The filament:assets call is new to v1.2.0 and is not optional: the tour runner changed in this release, and an un-republished asset bundle leaves you running old runner JS against new definitions. Treat it as part of both install and every upgrade. Publish tags and the plugin FQCN are still worth verifying against the README for the release you install; the package is young enough that install ergonomics may change between minors.

Register the plugin on the panel that should show onboarding:

use Wallacemartinss\FilamentOnboarding\FilamentOnboardingPlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        // ...
        ->plugin(FilamentOnboardingPlugin::make());
}

Where to look first:

  1. config/filament-onboarding.php — audience rules, render hooks, tour settings, translation behavior.
  2. The published migrations — learn the table names (journeys, steps, progress/completion tables) before writing any reporting or backfill jobs.
  3. src/Models — the models you will query for progress dashboards and support tooling.
  4. The panel resource for journeys/steps — the “no deploy” authoring surface product people will use.

First use case to validate the package: create a single “Getting started” journey with three step types:

  • Condition step: “Complete your profile” backed by profile_completed.
  • Page-reached step: “Visit the Billing page.”
  • Video step: “Watch the 90-second intro.”

Then log in as a test user and confirm the checklist follows you across pages, the condition step self-completes for a user whose profile was already complete, and the tour survives a page navigation — including a tour that crosses to another page and resumes, which is exactly the path v1.2.0 fixed (advance controls are now pressed when a stop is arrived at rather than walked to).

If you are on a multi-tenant panel, add a fourth check: a step pointing at the tenant profile page. As of v1.2.0 ->tenantProfile() destinations appear in the step destination picker; before this release they were silently absent because getPages() never listed them.

Implementation Patterns

Author in the database, seed in code. Product people should edit journeys in the panel, but environments still need reproducible onboarding. Write a seeder using updateOrCreate keyed by a stable slug so staging and production get the same starting journey without duplicating rows on every deploy. Never truncate onboarding tables in a deploy script — you will wipe real user progress.

Register conditions as named, testable units. The condition callback is the heart of the package: it lets existing users enter a journey already half-done instead of being nagged about work they completed years ago. Keep condition keys stable and centralize them in one service provider or dedicated registry class:

// Shape of the integration; adapt the facade/service name to the package API.
Onboarding::condition('profile_completed', fn (User $user) =>
    $user->profile()->whereNotNull('completed_at')->exists()
);

Onboarding::condition('has_created_invoice', fn (User $user) =>
    $user->invoices()->exists()
);

Write a test that asserts every key referenced by seeded steps exists in the registry. A typo in a condition key fails silently — the step simply never completes — and that is the single most likely support ticket you will receive.

Use the right step type for the job. Conditions are for state that exists independent of navigation (“has created a record”, “has connected Stripe”). Page-reached steps are for exposure (“opened the Reports page”). Video steps are for content consumption. Do not model “created your first invoice” as a page-reached step; users will hit the page, fail to create anything, and still get credit.

Treat tours as fragile UI contracts. Spotlight tours depend on selectors resolving to visible elements. Prefer stable Filament component IDs or your own data-onboarding="..." attributes over generated CSS classes. Add those attributes deliberately to the buttons and panels you want to highlight. Re-test tours after every Filament minor upgrade; a selector that resolves to null typically produces a tour with a missing step or a misplaced spotlight.

Target fields inside nested layouts — this now works, but it is worth an explicit test. v1.2.0 fixed the case where a field’s name (title) and its state path (form.details.title) diverged because a Group, Section, Tab or wizard step prefixed it. The matcher now accepts the name at the end of the path as well as the whole of it. That fix also means: build at least one tour against your most deeply nested form (a wizard inside a section inside a tab) and confirm it targets and completes. Older versions stalled on Next with no recovery short of Skip, and the stall was persisted to localStorage, so it recurred on every reload.

Do not fight a target picker that looks empty. If a form resource offers no targets at all, and it calls anything that reaches the Livewire component from inside the schema, you were hitting the Schema::getLivewire() TypeError that v1.2.0 fixed by building the schema against the resource’s own page. On the reporting panel this was measured against, 8 of 34 form resources were blank for this reason. On ≥1.2.0 they should populate; if one still doesn’t, that is a bug report, not a workaround.

Scope the checklist per panel and tenant. In multi-panel apps, register the plugin only where onboarding belongs, or configure the audience per panel. In multi-tenant apps, add tenant identity to the audience/condition logic and verify that progress rows cannot leak across tenants. This is the area where a generic “show checklist to authenticated user” default becomes a security-adjacent bug.

Localize content at the journey level, not in lang files. The selling point is that translators can edit step titles, descriptions, and tour copy in the database. Decide early whether you store translations as JSON columns or per-locale step rows, configure a sensible fallback locale, and test with a user whose locale differs from app.locale. Keep an export/import path (JSON seed file or command) so translations are versioned in Git rather than living only in production.

Wire completion events into the rest of the app. When a step or journey completes, use the package’s events/listeners to update your CRM, send a “you’re set up” email, or record analytics. Guard listeners for idempotency — a re-evaluated condition or a page revisit should not double-count a conversion.

Expose progress to support and success teams. Query the package models directly for a small “onboarding status” column on your Users resource, or build a lightweight progress page. This turns the package from a UI widget into an operational tool.

Gotchas and Tips

  • Pin Filament to the matching line. 1.x is Filament v4; 2.x is Filament v5. Installing the 2.x line on a v4 panel (or the reverse) either fails resolution or registers a plugin whose hooks no longer exist. Upgrade Filament and this package together, as a pair.
  • Run php artisan filament:assets on install and on every upgrade of this package. v1.2.0 changed the tour runner; a stale asset bundle is the kind of failure that looks like a logic bug in a step you have already configured correctly.
  • Migrate before registering the panel. Registering the plugin against missing tables produces confusing panel errors. v1.2.0 adds no migrations, so upgrading is safe on that axis — but the ordering still matters for fresh installs.
  • A hidden target now counts as a missing one. Filament hides (rather than removes) the tab, wizard step or collapsed section a subject just left, so the element stays connected with a zero-size rectangle. Previously the spotlight would collapse to a padding-sized square in the corner with the popover still claiming to point at something; it is now dropped. If you were relying on the old behaviour to “hold” a highlight across a tab switch, re-check that tour.
  • Wide tables scroll horizontally now. “Already visible” was once judged on the vertical axis only, so far columns of a horizontally scrolling table — every table, on a phone — were treated as on-screen. Both axes are checked and the scroll centres. Test any tour pointing at a column near the right edge of a wide table.
  • Conditions run on page loads. A condition that performs an uncached aggregate query will quietly tax every panel request. Keep conditions to indexed existence checks, or cache results per user per request. If a condition needs a heavy computation, maintain a denormalized boolean on the user/tenant record instead.
  • Backfill is lazy. Condition-backed steps catch up when the user’s progress is evaluated — typically on a panel visit. If you need immediate backfill for a large existing user base, write an artisan command or queued job that iterates users and touches their progress. Do not assume the package will do a global sweep on migration.
  • Do not re-show dismissed journeys on deploy. If your seeder recreates journeys or steps with new IDs, users may see “don’t show again” content again. Use stable slugs and updateOrCreate, and verify how versioning a journey affects existing progress.
  • Beware selector drift after Filament upgrades. Spotlight tours are the first thing to break when Filament changes markup. Keep a smoke test that opens each tour page and asserts the target elements exist.
  • Long-lived workers no longer serve stale definitions — but still restart them. Before v1.2.0 the definitions memo was “once per request” only on FPM; under Octane and queue:work the manager object persists, so a worker kept serving a flow the author had switched off, because the cache-clearing write fires its model events in whichever process handled it. v1.2.0 ties the memo to the worker’s actual request/job boundaries. This is a correctness fix you get for free, not a reason to stop restarting queue workers after a deploy — and php artisan optimize:clear after config changes remains good practice.
  • Restrict who can edit journeys. The panel authoring screen is powerful. Put it behind a policy/permission so any panel user cannot rewrite onboarding for everyone. Product editors need the resource; ordinary users do not.
  • Test idempotency of completion. Completing a step twice, revisiting a page, or re-evaluating a condition should not create duplicate completion rows or duplicate analytics events. Add a unique constraint or guard in your listener.
  • Small ecosystem risk. With modest adoption and zero dependents, treat this as a young dependency: pin the version, wrap progress checks behind a small application service, and avoid scattering package model queries throughout your codebase. If the package stalls, you want one adapter to replace rather than fifty call sites.
  • Watch the changelog on every bump. The package is pre-1.0 in spirit; method names, config keys, and publish tags are more likely to shift than in a mature Filament plugin — and it now maintains two lines, so a fix landing in 2.x may reach 1.x only as a backport. Read the release notes and run your onboarding smoke test after each update.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus