OOnboard v2.0.0
A self-hosted WordPress onboarding flow builder with 15 step types, 8 visual skins, audience targeting, conditional branching, A/B testing, drop-off analytics, NPS and surveys, WooCommerce hooks, signed webhooks, and OEngage / OMailer integration. Your data, your database, no SaaS fees.
What OOnboard does
Multi-step guided experiences for new users, from welcome screens to quiz-driven branching flows with registration gating, NPS surveys, WooCommerce coupons, and post-completion automation. Self-hosted, WordPress-native, no monthly SaaS cost.
oob_register_skins filter.and / or rules across role, meta, device, registration date, prior completionnext_step_index; per-step conditional gating with skip-or-route fallback{{user_name}}, {{site_name}}, Woo totals, and custom tags| Feature | OOnboard | UserGuiding | Appcues |
|---|---|---|---|
| Self-hosted | ✓ | ❌ SaaS | ❌ SaaS |
| WordPress-native | ✓ | ✗ | ✗ |
| Data stays in your DB | ✓ | ✗ | ✗ |
| Registration gating in-flow | ✓ | ✗ | ✗ |
| OEngage + OMailer integration | ✓ | ✗ | ✗ |
| Cost | $79 once | $89 to 249/mo | $249+/mo |
Getting installed
oonboard folder to /wp-content/plugins/ or install via WP Admin → Plugins → Add New → Upload.oob_progress, oob_events, oob_flow_versions, oob_checklists, oob_checklist_progress, oob_survey_responses, oob_webhook_log) and registers the oo_flow and oo_checklist custom post types.Your first flow in minutes
[oonboard_trigger id="YOUR_FLOW_ID" label="Start"]Admin interface
Persistent two-row sticky header: brand bar (icon + name + version + light/dark toggle) plus a horizontal tab nav. Theme preference persisted to localStorage under key oob_theme.
Dashboard
Four-stat summary row (Total Flows, Flow Starts, Completions, Avg Completion Rate) followed by a table of recent flows with per-flow conversion stats.
Flows tab
Lists all flows with name, display style, trigger type, status pill (Active / Draft), start count, and completion rate. Actions: Edit (opens Builder), Duplicate, Delete. Live search filters flows by name.
Flow builder
| Panel | Contents |
|---|---|
| Left: Steps list | Ordered steps with index + type. + Add Step opens the type picker (15 types, gated by license tier). Each row has Edit, Move Up, Move Down, Delete. |
| Right: Step Editor | Appears when editing a step. Common fields: Title, Content, Button Text, Skip Text. Type-specific fields appear below. |
| Right: Flow Settings | Always visible: Flow Name, Display Style, Progress Style, Trigger, Target Page ID, Allow Skip, Resume Position, Back Button, A/B Test, Post-Flow Actions (redirect, message, XP, OMailer, role, webhook). |
Progress tab
Paginated table of all user interactions. Filter by flow or status. Delete individual records with the trash icon.
| Column | Description |
|---|---|
| User | Display name + email, or "Guest" for anonymous users |
| Flow | Flow name |
| Variant | A or B (for A/B tests) |
| Status | started completed abandoned |
| Step | Current step number |
| Timestamps | Started at / Completed at |
Analytics tab
Per-flow analysis. Select a flow from the dropdown to see stats.
| Component | Description |
|---|---|
| Stats row | Total Starts, Completions, Completion Rate, Avg Completion Time |
| Daily Completions chart | Canvas bar chart of daily completions over last 30 days |
| Step Drop-Off table | Per-step view counts and abandonment percentage |
| A/B Test Results | Side-by-side cards for Variant A and B; "Winner" badge on the higher completion rate |
Global settings
| Setting | Description |
|---|---|
| Default Display Style | Applied to new flows; can be overridden per flow |
| Disable for admins | Auto-trigger flows won't fire for WordPress admin users |
| Load assets globally | Enqueue frontend CSS/JS on all pages, needed for manual trigger buttons in headers/footers |
| Default OMailer List ID | Default list for post-flow OMailer subscriptions |
| OEngage XP event key | The event key sent to OEngage on flow completion |
The Settings tab also shows a Merge Tags Reference and Shortcode Reference panel in-admin.
Fifteen step types
auto_advance when video ends via API.user_meta.wp_create_user().all_required gate before advancing. Standalone widget version available.next_step_index per option for conditional branching paths.redirect_delay seconds.oob_survey_responses.Four display styles
Set per-flow in Flow Settings. Can also be overridden by the style attribute on the trigger shortcode.
Eight built-in skins
Skins control the full visual treatment of a flow card (typography, color tokens, motion, border treatment). Set per-flow via the skin setting. Default is atelier.
| Skin | Mood | Accent |
|---|---|---|
atelier | Cream paper, serif, slow fades. Default Orravo identity. | #C9A84C |
aurora | Frosted glass with animated conic gradient border. Reduced-motion safe. | #7c5cff |
brutal | Pure black on white. Zero radius. Hard 100ms transforms. | #000000 |
neon | Pixel font, scanline overlay, magenta and cyan glow. Retro arcade. | #ff2bd6 |
linear | Linear.app dark palette, thin borders, monospace numerals. | #5e6ad2 |
stripe | Pastel gradients, micro-shadows, friendly rounded corners. | #635bff |
apple | Translucent material, San Francisco type, spring-physics buttons. | #0a84ff |
notion | Off-white, generous spacing, minimal accents, clean sans. | #2eaadc |
PHP · register a custom skinadd_filter('oob_register_skins', function(array $skins): array {
$skins['my_brand'] = [
'id' => 'my_brand',
'label' => 'My Brand',
'mood' => 'Custom palette',
'description' => 'Brand-aligned colors and motion.',
'accent' => '#ff3d00',
'preview_bg' => 'linear-gradient(135deg,#0a0a0a,#1a1a1a)',
'featured' => 11,
'has_motion' => true,
];
return $skins;
});
// Then style with .oob-skin-my_brand selectors in your theme's CSS
Progress indicators
| Type | Description |
|---|---|
bar | Thin accent-colored progress bar at the top of the flow card |
steps | "Step 2 / 5" text label |
dots | Row of clickable dots, one per step |
percent | Percentage text, e.g. "40%" |
none | No progress indicator shown |
Flow triggers
| Trigger | When it fires |
|---|---|
| Manual | Only when the user clicks a [oonboard_trigger] button or OOBFrontend.launchFlow() is called |
| First Login | Hooks into wp_login. Queues the flow after the first login and auto-launches it on the next page load. |
| Page Load | Auto-launches when a user visits the configured Target Page ID. |
| Time-Based | Schedules via wp_schedule_single_event('oob_fire_delayed_flow', ...). Configure trigger_delay_value and trigger_delay_unit (minutes, hours, days). |
| WooCommerce: First Purchase | Fires on woocommerce_order_status_completed when the customer has only one completed order. |
| WooCommerce: Any Purchase | Fires on every completed Woo order. |
| WooCommerce: Product Purchase | Fires when a specific trigger_product_id appears in the order. |
| WooCommerce: Thankyou | Fires on woocommerce_thankyou page render. |
| WooCommerce: Account Dashboard | Fires on woocommerce_account_dashboard. |
Audience targeting
Restrict who sees a flow with a rule set evaluated by OOB_Audience_Evaluator. Stored in flow settings under audience as { logic: 'and' | 'or', rules: [...] }. Pro feature (audience_targeting).
| Field | Operators |
|---|---|
user_role | equals, not_equals |
user_meta (with meta_key) | equals, not_equals, contains, not_contains, starts_with, ends_with |
previous_form_answer (with step_index, field_id) | All comparison operators |
flow_completed | has_completed, has_not_completed |
device_type | desktop, tablet, mobile |
user_logged_in | yes, no |
user_registered_before / user_registered_after | YYYY-MM-DD comparison |
Per-step conditions use the same evaluator (OOB_Condition_Evaluator). When a step's conditions fail, conditions_else picks the fallback: skip (default) or jump to conditions_else_step.
Add custom rule fields with the oob_condition_rule filter.
Conditional branching
Implemented via the Quiz step type. Each answer option has a next_step_index field that overrides the default sequential next step.
When a user selects an option, OOB_Engine::ajax_complete_step() reads the chosen option's next_step_index and jumps there instead of current_index + 1. If next_step_index is null, the flow advances normally.
Merge tags
Double-brace {{placeholders}} replaced at render time by OOB_Merge_Tags::process(). Work in step title, content, and subheading fields.
| Tag | Replaced with |
|---|---|
| {{user_name}} | User's display name; "there" for guests |
| {{user_first}} | User's first name |
| {{user_last}} | User's last name |
| {{user_email}} | User's email address |
| {{site_name}} | WordPress site name |
| {{site_url}} | WordPress home URL |
| {{current_date}} | Today's date (WordPress date format) |
| {{current_year}} | Current year (4 digits) |
| {{admin_email}} | Admin email address |
| {{user_id}} | WordPress user ID |
| {{user_role}} | User's first WordPress role; guest if logged out |
| {{woo_order_count}} | WooCommerce completed order count (when Woo is active) |
| {{woo_total_spent}} | WooCommerce lifetime spend, formatted (when Woo is active) |
Custom merge tags
PHPadd_filter('oob_available_merge_tags', function(array $tags): array {
$tags['{{plan_name}}'] = 'Customer plan name';
return $tags;
});
// Then push the value at render time via the context
OOB_Merge_Tags::process('Hello {{plan_name}}', [
'custom' => ['plan_name' => 'Pro'],
]);
Post-flow actions
Run automatically when a user completes the final step, via OOB_Actions::run(). Configure in Builder → Flow Settings.
| Action | Description |
|---|---|
| Redirect URL | Redirect the user's browser to a specified URL |
| Success Message | Display a custom message on the completion screen |
| Award XP | Calls oengage_award_xp($user_id, $amount, $event_key); requires OEngage |
| Award Badge ID | Calls oengage_award_badge($user_id, $badge_id); requires OEngage |
| OMailer List ID | Subscribes user to an OMailer list via om_subscribe(); requires OMailer |
| Assign WP Role | Changes the user's WordPress role on completion |
| Webhook URL | Sends a POST request with a JSON payload to an external URL |
| Webhook Secret | HMAC-SHA256 signs the payload; header: X-OOnboard-Signature |
JSON · webhook payload{
"event": "flow_completed",
"flow_id": 42,
"user_id": 7,
"time": 1745625600
}
A/B testing
Enable per-flow in Builder → Flow Settings → A/B Test checkbox. New users are randomly assigned 50/50 to Variant A (original steps) or Variant B (separate step set).
| Detail | Value |
|---|---|
| Variant assignment | Random 50/50 for new users. Stored in {prefix}oob_progress.variant so users always see the same variant. |
| Variant B steps | Stored in _oob_variant_b post meta. A "Variant B" step list appears in the builder when A/B testing is enabled. |
| Results | Analytics tab → A/B Test Results section. Side-by-side starts, completions, completion rate. "Winner" badge on the higher-performing variant. |
Flow versioning, import, export
Every save snapshots the flow into {prefix}oob_flow_versions. Restore any prior version through the builder UI (Pro feature: flow_versioning). Export any flow to JSON for transfer between sites.
| Surface | Description |
|---|---|
| Snapshot on save | OOB_Versions::snapshot() writes steps_json + settings_json per save with version_number auto-incremented per flow |
| Restore | AJAX oob_restore_version swaps the live flow back to a chosen version_id |
| Export | AJAX oob_export_flow returns JSON containing steps, settings, post_actions, variant_b |
| Import | AJAX oob_import_flow creates a new flow from a JSON export |
| Templates | AJAX oob_create_flow_from_template spawns a flow from a packaged template (Pro: template_library_cloud) |
Shortcodes
[oonboard id="X"]
Embeds a flow inline on any page or post in Embedded display style.
[oonboard id="42"]
| Attribute | Required | Description |
|---|---|---|
id | Yes | Flow post ID |
[oonboard_trigger id="X" label="Start"]
Renders a styled button that launches a flow when clicked.
[oonboard_trigger id="42" label="Start the Tour" style="modal"]
| Attribute | Default | Description |
|---|---|---|
id | (required) | Flow post ID (required) |
label | Start | Button text |
style | modal | modal, full-page, slide-in, embedded |
class | (none) | Additional CSS classes for the button element |
Gutenberg block
OOnboard registers an OOnboard Flow block in the Gutenberg editor under the Widgets category.
OOB_Shortcode::render_embed() at display time. In the editor it shows a preview card with the flow name and ID.Orravo integrations
oengage_award_xp() and oengage_award_badge() on flow completion. XP event key configurable in Settings. OEngage must be installed and active.om_subscribe() with first_name, last_name, list_id, and source on completion. OMailer must be installed and active.PHP · OMailer callom_subscribe( $user_email, [
'first_name' => $user->first_name,
'last_name' => $user->last_name,
'list_id' => $list_id,
'source' => 'oonboard',
] );
Developer API
PHP helper functions
PHP// Check if the current user has completed a flow
oob_has_completed_flow( int $flow_id, int $user_id = 0 ): bool
// Get the admin builder URL for a flow
oob_get_flow_url( int $flow_id ): string
// Queue a flow for a specific user (via OOB_Triggers)
oob_queue_flow( int $flow_id, int $user_id = 0 ): void
// Read a single progress row
oob_get_progress( int $flow_id, int $user_id = 0 ): ?object
OOB_Flow: flow CRUD
PHPOOB_Flow::create( string $name, array $settings = [] ): int
OOB_Flow::update( int $id, array $data ): bool
OOB_Flow::delete( int $id ): bool
OOB_Flow::duplicate( int $id ): int
OOB_Flow::get( int $id ): ?WP_Post
OOB_Flow::get_all( array $args = [] ): array
OOB_Flow::get_steps( int $id ): array
OOB_Flow::get_settings( int $id ): array
OOB_Flow::get_post_actions( int $id ): array
OOB_Flow::get_variant_b_steps( int $id ): array
OOB_Pro: license + capability gating
PHPOOB_Pro::is_pro(): bool // delegated to orravo_is_licensed('oonboard')
OOB_Pro::tier(): string // 'free' | 'pro' | 'agency'
OOB_Pro::can( string $feature ): bool // ab_testing, audience_targeting, webhooks_advanced, etc.
OOB_Pro::free_limit( string $key ) // max_flows: 3, max_steps: 10, allowed step_types: 5
OOB_Skins, OOB_Audience_Evaluator, OOB_Condition_Evaluator
PHPOOB_Skins::get_all(): array // all registered skins
OOB_Audience_Evaluator::matches( int $flow_id, int $user_id ): bool
OOB_Condition_Evaluator::evaluate( array $conditions, int $user_id, array $context = [] ): bool
OOB_Progress: progress tracking
PHPOOB_Progress::upsert( int $flow_id, int $user_id, string $session_key ): int
OOB_Progress::update_step( int $flow_id, int $step_index, int $user_id, string $session_key ): void
OOB_Progress::complete( int $flow_id, int $user_id, string $session_key ): void
OOB_Progress::abandon( int $flow_id, int $user_id, string $session_key ): void
OOB_Progress::has_completed( int $flow_id, int $user_id ): bool
OOB_Progress::log_event( int $flow_id, string $event, int $step_index, ... ): void
OOB_Analytics
PHPOOB_Analytics::get_flow_stats( int $flow_id ): array
OOB_Analytics::get_dashboard_totals(): array
OOB_Analytics::get_dropoff_by_step( int $flow_id ): array
OOB_Analytics::get_ab_stats( int $flow_id ): array
OOB_Merge_Tags
PHPOOB_Merge_Tags::process( string $content, array $context = [] ): string
OOB_Merge_Tags::get_available_tags(): array
JavaScript API
JS// Programmatically launch a flow
OOBFrontend.launchFlow( flowId, displayStyle );
// Close a running flow
OOBFrontend.closeFlow( flowId );
Database schema
oob_progress
| Column | Type | Description |
|---|---|---|
id | BIGINT UNSIGNED | Primary key |
user_id | BIGINT UNSIGNED | WordPress user ID; 0 for guests |
flow_id | BIGINT UNSIGNED | Post ID of the oo_flow CPT |
variant | VARCHAR(8) | A or B (A/B tests) |
step_index | SMALLINT | Current step the user is on |
status | VARCHAR(20) | started, completed, or abandoned |
session_key | VARCHAR(64) | PHP session key for guest users |
started_at | DATETIME | UTC timestamp of flow start |
updated_at | DATETIME | UTC timestamp of last update |
completed_at | DATETIME | UTC timestamp of completion (NULL if incomplete) |
Indexes: (user_id, flow_id), (flow_id, status)
oob_events
| Column | Type | Description |
|---|---|---|
id | BIGINT UNSIGNED | Primary key |
user_id | BIGINT UNSIGNED | WordPress user ID |
flow_id | BIGINT UNSIGNED | Flow post ID |
step_index | SMALLINT | Step the event occurred on |
event_type | VARCHAR(30) | start, step_view, step_complete, complete, skip, abandon |
variant | VARCHAR(8) | A/B variant |
session_key | VARCHAR(64) | Guest session key |
created_at | DATETIME | UTC event timestamp |
Indexes: (flow_id, event_type, created_at), (flow_id, step_index, event_type)
oob_flow_versions
Version snapshot per flow save. Restore via OOB_Versions::restore() or the AJAX endpoint oob_restore_version (Pro).
Columns: id, flow_id, version_number, steps_json, settings_json, saved_by, saved_at. Index (flow_id, version_number).
oob_checklists / oob_checklist_progress
Standalone frontend checklist widgets, separate from in-flow checklist steps. oob_checklists stores titles, items, and settings. oob_checklist_progress tracks per-user, per-item completion with a unique key on (checklist_id, user_id, item_index). Rendered in the page footer by OOB_Checklist::inject_widgets().
oob_survey_responses
NPS scores and survey answers. Columns: id, flow_id, step_index, user_id, session_key, question_key, response, score, created_at. Indexes on (flow_id, step_index) and (flow_id, question_key).
oob_webhook_log
Outgoing webhook deliveries with status code, response body, attempt count. Failed deliveries (non-2xx) are auto-retried at 5min, 15min, then 1hr (Pro: webhooks_advanced).
Custom post types
| CPT | Description |
|---|---|
oo_flow | Onboarding flow. Meta: _oob_steps, _oob_settings, _oob_post_actions, _oob_variant_b (all JSON). |
oo_checklist | Standalone checklist widget configuration. |
REST and AJAX endpoints
REST routes live under the oonboard/v1 namespace and require manage_options plus the rest_api Pro capability. AJAX endpoints registered via wp_ajax_* hooks require a valid nonce from the OOB JS object.
REST API · /wp-json/oonboard/v1/
| Method | Route | Description |
|---|---|---|
| GET | /flows | List all flows with stats summary |
| POST | /flows | Create a new flow. Body: name, settings |
| GET | /flows/{id} | Read full flow with steps, settings, post_actions |
| PUT | /flows/{id} | Update name, status, steps, settings, post_actions, variant_b |
| DELETE | /flows/{id} | Delete a flow |
| GET | /flows/{id}/analytics | Per-flow stats. Query: days (1 to 365) |
| POST | /flows/{id}/trigger | Queue a flow for a user. Body: user_id |
| POST | /flows/{id}/reset | Reset progress for a user. Body: user_id |
| GET | /progress | Paginated progress list. Query: flow_id, status, per_page, page |
| DELETE | /progress/{id} | Delete a progress row |
Frontend AJAX (public + logged-in)
| Action | Method | Description |
|---|---|---|
oob_get_flow_init | POST | Get flow metadata and resume index. Params: flow_id |
oob_get_step | POST | Fetch a step's rendered data. Params: flow_id, step_index |
oob_complete_step | POST | Mark step complete, get next step index. Params: flow_id, step_index, quiz_answer (opt), form_data (opt) |
oob_skip_step | POST | Skip a step, advance to next |
oob_abandon_flow | POST | Mark flow as abandoned |
oob_checklist_mark | POST | Toggle a checklist widget item complete |
Admin AJAX (requires manage_options)
| Action | Description |
|---|---|
oob_create_flow | Create a new flow |
oob_save_flow | Save steps, settings, and post-actions |
oob_delete_flow | Delete a flow |
oob_duplicate_flow | Duplicate a flow |
oob_save_settings | Save global plugin settings |
oob_get_flow_data | Get full flow data as JSON |
oob_delete_progress | Delete a progress record by ID |
oob_create_flow_from_template | Create a flow from a packaged template |
oob_import_flow | Import a flow from a JSON export |
oob_export_flow | Export a flow as JSON |
oob_restore_version | Restore a prior flow version (Pro) |
oob_create_checklist | Create a standalone checklist |
oob_save_checklist | Save a checklist |
oob_delete_checklist | Delete a checklist |
oob_toggle_checklist_status | Publish or unpublish a checklist |
oob_preview_step | Render a single step for live preview in the builder |
Hooks & filters
Actions
| Hook | Arguments | Description |
|---|---|---|
oob_flow_completed | $flow_id, $user_id, $actions | Fired when a user completes a flow |
oob_flow_started | $flow_id, $user_id | Available for custom extension on flow start |
PHPadd_action('oob_flow_completed', function($flow_id, $user_id, $actions) {
if ($flow_id === 42) {
update_user_meta($user_id, 'onboarding_complete', '1');
}
}, 10, 3);
Filters
| Filter | Arguments | Description |
|---|---|---|
oob_register_skins | $skins | Add or modify visual skins available to flows |
oob_available_merge_tags | $tags | Add custom merge tag definitions to the registry |
oob_condition_rule | $result, $rule, $user_id, $context | Implement custom condition rule fields |
oob_is_pro | $is_pro | Override the Pro license check (testing / dev environments) |
oob_can_{feature} | $enabled | Per-capability override; e.g. oob_can_webhooks_advanced |
orravo_register_product / orravo_mini_admin_pages | $products / $pages | Mini-Core hooks for Orravo Core menu integration |
Frequently asked questions
{prefix}oob_progress with user_id = 0 and a session_key.OOB_Progress::reset($flow_id, $user_id) programmatically, or provide a restart button using [oonboard_trigger].[oonboard] shortcodes or trigger buttons on the same page.OOB_DB::uninstall() drops all seven OOnboard tables (oob_progress, oob_events, oob_flow_versions, oob_checklists, oob_checklist_progress, oob_survey_responses, oob_webhook_log), deletes every oo_flow and oo_checklist post, and removes OOnboard options. This is permanent.DELETE FROM {prefix}oob_events WHERE flow_id = X and DELETE FROM {prefix}oob_progress WHERE flow_id = X directly in your database.variant column of {prefix}oob_progress. Once assigned, they always see the same variant. New users are randomly assigned 50/50.What's shipped
- 15 step types (added tour_step, nps, survey, woo_product, woo_coupon)
- 8 visual skins (atelier, aurora, brutal, neon arcade, linear, stripe light, apple os, notion) registered via filter
- Modal, full-page, slide-in, embedded display styles
- Progress bar, step numbers, dots, percentage, none
- Audience targeting with
and/orrules across role, meta, device, registration date, prior completion - Per-step conditional gating with skip-or-route fallback
- Quiz branching via
next_step_index - NPS step with detractor / passive / promoter routing
- Multi-question survey step (text, textarea, rating, stars, choices)
- Resume from last position; anonymous progress via session key
- Auto-launch triggers: manual, first-login, page-load, time-based, plus 5 WooCommerce triggers
- User progress table with status and step tracking
- Drop-off analysis per step with color coding
- Daily completions chart (30-day canvas)
- A/B flow testing with variant assignment, comparison, and winner detection
- Post-flow actions: redirect, success message, role, XP, badge, OMailer subscribe, webhook
- HMAC-SHA256 signed webhooks with auto-retry (Pro)
- Merge tags:
{{user_name}},{{site_name}}, Woo totals, custom viaoob_merge_tag_context - Shortcodes:
[oonboard id],[oonboard_trigger id] - Gutenberg block with server-side rendering
- OEngage (XP and badges) and OMailer (list subscribe) integration hooks
- WooCommerce step types and triggers
- Standalone checklist widget (frontend, footer-injected)
- Flow versioning with rollback (Pro)
- Import / export flows as JSON
- Goal tracking with conversion windows
- Email notifications on complete or abandon (Pro)
- REST API at
/wp-json/oonboard/v1/with 7 routes (Pro) - Auto-detects Orravo Core and nests under its menu via mini-core fallback
oob_flow_completedaction plusoob_register_skins,oob_merge_tag_context,oob_step_html,oob_flow_settingsfilters for extensibility
Got a question about OOnboard?
Reach out directly. Kenneth replies within 24 hours.

