Skip to main content

Handle onboarding events in Flutter SDK

Onboardings configured with the builder generate events your app can respond to. The way you handle these events depends on which presentation approach you're using:

  • Full-screen presentation: Requires setting up a global event observer that handles events for all onboarding views
  • Embedded widget: Handles events through inline callback parameters directly in the widget

Before you start, ensure that:

  1. You have installed Adapty Flutter SDK 3.8.0 or later.
  2. You have created an onboarding.
  3. You have added the onboarding to a placement.

Full-screen presentation events

Set up event observer

To handle events for full-screen onboardings, implement the AdaptyUIOnboardingsEventsObserver and set it before presenting:

Flutter
AdaptyUI().setOnboardingsEventsObserver(this);

try {
await onboardingView.present();
} on AdaptyError catch (e) {
// handle the error
} catch (e) {
// handle the error
}

Handle events

Implement these methods in your observer:

Flutter
void onboardingViewDidFinishLoading(
AdaptyUIOnboardingView view,
AdaptyUIOnboardingMeta meta,
) {
// Onboarding finished loading
}

void onboardingViewDidFailWithError(
AdaptyUIOnboardingView view,
AdaptyError error,
) {
// Handle loading errors
}

void onboardingViewOnCloseAction(
AdaptyUIOnboardingView view,
AdaptyUIOnboardingMeta meta,
String actionId,
) {
// Handle close action
view.dismiss();
}

void onboardingViewOnPaywallAction(
AdaptyUIOnboardingView view,
AdaptyUIOnboardingMeta meta,
String actionId,
) {
_openPaywall(actionId);
}

void onboardingViewOnCustomAction(
AdaptyUIOnboardingView view,
AdaptyUIOnboardingMeta meta,
String actionId,
) {
// Handle custom actions
}

void onboardingViewOnStateUpdatedAction(
AdaptyUIOnboardingView view,
AdaptyUIOnboardingMeta meta,
String elementId,
AdaptyOnboardingsStateUpdatedParams params,
) {
// Handle user input updates
}

void onboardingViewOnAnalyticsEvent(
AdaptyUIOnboardingView view,
AdaptyUIOnboardingMeta meta,
AdaptyOnboardingsAnalyticsEvent event,
) {
// Track analytics events
}

Embedded widget events

When using AdaptyUIOnboardingPlatformView, you can handle events through inline callback parameters directly in the widget. Note that events will be sent to both the widget callbacks and the global observer (if set up), but the global observer is optional:

Flutter
AdaptyUIOnboardingPlatformView(
onboarding: onboarding,
onDidFinishLoading: (meta) {
// Onboarding finished loading
},
onDidFailWithError: (error) {
// Handle loading errors
},
onCloseAction: (meta, actionId) {
// Handle close action
},
onPaywallAction: (meta, actionId) {
_openPaywall(actionId);
},
onCustomAction: (meta, actionId) {
// Handle custom actions
},
onStateUpdatedAction: (meta, elementId, params) {
// Handle user input updates
},
onAnalyticsEvent: (meta, event) {
// Track analytics events
},
)

Event types

The following sections describe the different types of events you can handle, regardless of which presentation approach you're using.

Handle custom actions

In the builder, you can add a custom action to a button and assign it an ID.

Then, you can use this ID in your code and handle it as a custom action. For example, if a user taps a custom button, like Login or Allow notifications, the delegate method onboardingController will be triggered with the .custom(id:) case and the actionId parameter is the Action ID from the builder. You can create your own IDs, like "allowNotifications".

// Full-screen presentation
void onboardingViewOnCustomAction(
AdaptyUIOnboardingView view,
AdaptyUIOnboardingMeta meta,
String actionId,
) {
switch (actionId) {
case 'login':
_login();
break;
case 'allow_notifications':
_allowNotifications();
break;
}
}

// Embedded widget
onCustomAction: (meta, actionId) {
_handleCustomAction(actionId);
}
Event example (Click to expand)
{
"actionId": "allowNotifications",
"meta": {
"onboardingId": "onboarding_123",
"screenClientId": "profile_screen",
"screenIndex": 0,
"screensTotal": 3
}
}

Finishing loading onboarding

When an onboarding finishes loading, this event will be triggered:

Flutter
// Full-screen presentation
void onboardingViewDidFinishLoading(
AdaptyUIOnboardingView view,
AdaptyUIOnboardingMeta meta,
) {
print('Onboarding loaded: ${meta.onboardingId}');
}

// Embedded widget
onDidFinishLoading: (meta) {
print('Onboarding loaded: ${meta.onboardingId}');
}
Event example (Click to expand)
{
"meta": {
"onboarding_id": "onboarding_123",
"screen_cid": "welcome_screen",
"screen_index": 0,
"total_screens": 4
}
}

Closing onboarding

Onboarding is considered closed when a user taps a button with the Close action assigned.

important

Note that you need to manage what happens when a user closes the onboarding. For instance, you need to stop displaying the onboarding itself.

Flutter
// Full-screen presentation
void onboardingViewOnCloseAction(
AdaptyUIOnboardingView view,
AdaptyUIOnboardingMeta meta,
String actionId,
) {
await view.dismiss();
}

// Embedded widget
onCloseAction: (meta, actionId) {
Navigator.of(context).pop();
}
Event example (Click to expand)
{
"action_id": "close_button",
"meta": {
"onboarding_id": "onboarding_123",
"screen_cid": "final_screen",
"screen_index": 3,
"total_screens": 4
}
}

Opening a paywall

tip

Handle this event to open a paywall if you want to open it inside the onboarding. If you want to open a paywall after it is closed, there is a more straightforward way to do it – handle the close action and open a paywall without relying on the event data.

If a user clicks a button that opens a paywall, you will get a button action ID that you set up manually. The most seamless way to work with paywalls in onboardings is to make the action ID equal to a paywall placement ID:

Flutter
// Full-screen presentation
void onboardingViewOnPaywallAction(
AdaptyUIOnboardingView view,
AdaptyUIOnboardingMeta meta,
String actionId,
) {
_openPaywall(actionId);
}

Future<void> _openPaywall(String actionId) async {
// Implement your paywall opening logic here
}

// Embedded widget
onPaywallAction: (meta, actionId) {
_openPaywall(actionId);
}
Event example (Click to expand)
{
"action_id": "premium_offer_1",
"meta": {
"onboarding_id": "onboarding_123",
"screen_cid": "pricing_screen",
"screen_index": 2,
"total_screens": 4
}
}

Updating field state

When your users respond to a quiz question or input their data into an input field, the state update event will be triggered:

Flutter
// Full-screen presentation
void onboardingViewOnStateUpdatedAction(
AdaptyUIOnboardingView view,
AdaptyUIOnboardingMeta meta,
String elementId,
AdaptyOnboardingsStateUpdatedParams params,
) {
saveUserResponse(elementId, params.value);
}

// Embedded widget
onStateUpdatedAction: (meta, elementId, params) {
saveUserResponse(elementId, params.value);
}
note

If you want to save or process data, you need to implement the methods yourself.

The params object contains user input data, which can be one of the following types:

  • select: Single selection from a list of options
  • multiSelect: Multiple selections from a list of options
  • input: Text input from the user
  • datePicker: Date selected by the user
Saved data examples (Click to expand)
// Example of a saved select action
{
"elementId": "preference_selector",
"meta": {
"onboardingId": "onboarding_123",
"screenClientId": "preferences_screen",
"screenIndex": 1,
"screensTotal": 3
},
"params": {
"type": "select",
"value": {
"id": "option_1",
"value": "premium",
"label": "Premium Plan"
}
}
}

// Example of a saved multi-select action
{
"elementId": "interests_selector",
"meta": {
"onboardingId": "onboarding_123",
"screenClientId": "interests_screen",
"screenIndex": 2,
"screensTotal": 3
},
"params": {
"type": "multiSelect",
"value": [
{
"id": "interest_1",
"value": "sports",
"label": "Sports"
},
{
"id": "interest_2",
"value": "music",
"label": "Music"
}
]
}
}

// Example of a saved input action
{
"elementId": "name_input",
"meta": {
"onboardingId": "onboarding_123",
"screenClientId": "profile_screen",
"screenIndex": 0,
"screensTotal": 3
},
"params": {
"type": "input",
"value": {
"type": "text",
"value": "John Doe"
}
}
}

// Example of a saved date picker action
{
"elementId": "birthday_picker",
"meta": {
"onboardingId": "onboarding_123",
"screenClientId": "profile_screen",
"screenIndex": 0,
"screensTotal": 3
},
"params": {
"type": "datePicker",
"value": {
"day": 15,
"month": 6,
"year": 1990
}
}
}

Tracking navigation

You receive an analytics event when various navigation-related events occur during the onboarding flow:

Flutter
// Full-screen presentation
void onboardingViewOnAnalyticsEvent(
AdaptyUIOnboardingView view,
AdaptyUIOnboardingMeta meta,
AdaptyOnboardingsAnalyticsEvent event,
) {
trackEvent(event.type, meta.onboardingId);
}

// Embedded widget
onAnalyticsEvent: (meta, event) {
trackEvent(event.type, meta.onboardingId);
}

The event object can be one of the following types:

TypeDescription
onboardingStartedWhen the onboarding has been loaded
screenPresentedWhen any screen is shown
screenCompletedWhen a screen is completed. Includes optional elementId (identifier of the completed element) and optional reply (response from the user). Triggered when users perform any action to exit the screen.
secondScreenPresentedWhen the second screen is shown
userEmailCollectedTriggered when the user's email is collected via the input field
onboardingCompletedTriggered when a user reaches a screen with the final ID. If you need this event, assign the final ID to the last screen.
unknownFor any unrecognized event type. Includes name (the name of the unknown event) and meta (additional metadata)

Each event includes meta information containing:

FieldDescription
onboardingIdUnique identifier of the onboarding flow
screenClientIdIdentifier of the current screen
screenIndexCurrent screen's position in the flow
screensTotalTotal number of screens in the flow
Event examples (Click to expand)
// onboardingStarted
{
"name": "onboarding_started",
"meta": {
"onboarding_id": "onboarding_123",
"screen_cid": "welcome_screen",
"screen_index": 0,
"total_screens": 4
}
}

// screenPresented

{
"name": "screen_presented",
"meta": {
"onboarding_id": "onboarding_123",
"screen_cid": "interests_screen",
"screen_index": 2,
"total_screens": 4
}
}

// screenCompleted

{
"name": "screen_completed",
"meta": {
"onboarding_id": "onboarding_123",
"screen_cid": "profile_screen",
"screen_index": 1,
"total_screens": 4
},
"params": {
"element_id": "profile_form",
"reply": "success"
}
}

// secondScreenPresented

{
"name": "second_screen_presented",
"meta": {
"onboarding_id": "onboarding_123",
"screen_cid": "profile_screen",
"screen_index": 1,
"total_screens": 4
}
}

// userEmailCollected

{
"name": "user_email_collected",
"meta": {
"onboarding_id": "onboarding_123",
"screen_cid": "profile_screen",
"screen_index": 1,
"total_screens": 4
}
}

// onboardingCompleted

{
"name": "onboarding_completed",
"meta": {
"onboarding_id": "onboarding_123",
"screen_cid": "final_screen",
"screen_index": 3,
"total_screens": 4
}
}