Notifications

An embed can schedule a notification on the user's device and can ask the host application for notification consent. Calling requestConsent() also lets the mobile app prepare the device for remote push notifications when your service has an MBP backend notification integration.

The SDK does not send remote pushes. It does not expose a device token either. Your backend continues to send notifications through its agreed MBP backend integration, the Notificaties API.

Scheduled notification Remote push notification
Starts from Your embed frontend Your service backend
Timing Now or at a chosen date When your backend sends an event
SDK method scheduleNotification() No send method in the SDK
Consent path May ask for consent while scheduling Call requestConsent() from an explicit user action
Needs the user to be signed in to the app No Yes, when consent is requested

Use a scheduled notification for a local reminder. For example, remind someone about an appointment at a date they chose in the embed.

Use remote push when your backend needs to notify the user later. For example, when a submitted application changes. A successful requestConsent() makes the device ready for that delivery. It does not make your backend send anything.

Do not schedule a local notification just to ask for push consent. Call requestConsent() from a clear "Turn on notifications" action instead.

Read the permission state when the embed opens and whenever it returns from a host application screen:

const permissions = await mbpClient.notifications.getNotificationPermissions();

if (permissions.granted) {
showNotificationsEnabled();
} else {
showNotificationsDisabled();
}

For normal embed flows, use these two values:

const { granted, canAskAgain } = permissions;

granted is the value that matters to an embed. It is true only when both of these are true:

  • the operating system allows the app to show notifications
  • the user has allowed this embed to use notifications

canAskAgain says whether requestConsent() can currently show a useful consent flow. The host application returns false when system settings block another prompt, a prompt is already open, or the embed asked too recently. It intentionally does not say which reason applies.

Treat these states as follows:

granted canAskAgain What to do
true either value Notifications are available.
false true Show an enable action when it makes sense for the user.
false false Do not keep asking. Leave notifications off and, if useful, point to the app notification settings.

The host application can allow notifications at operating-system level while they remain disabled for this embed.

Call requestConsent() only after a user action. A settings toggle or a button labelled "Turn on notifications" are good places. Do not call it when the page loads, during rendering, after a route change, or from a retry loop.

async function enableNotifications() {
const permissions = await mbpClient.notifications.requestConsent();

if (permissions.granted) {
showNotificationsEnabled();
return;
}

showNotificationsDisabled();

if (!permissions.canAskAgain) {
showNotificationSettingsLink();
}
}

The host application may show one or more screens during this call:

  1. If remote push needs an app account and the user is not signed in, the app can ask them to sign in first.
  2. The operating system may show its notification permission prompt.
  3. The app may show its own consent prompt for the embed.

The promise resolves after that flow finishes, then returns a fresh permission snapshot. A user declining a prompt is a normal result. Check granted; do not treat a declined prompt as an error.

The host application limits repeated consent prompts. When it cannot prompt again, requestConsent() resolves with the unchanged permission state. It does not repeatedly display a dialog. The exact cooldown can change, so do not show a countdown based on it.

A successful call lets the host application prepare the device for remote delivery. It does not subscribe the user to a provider-side preference list. Keep any service-specific notification preferences in your own product and explain them separately.

Expose a deliberate "Turn off notifications" action if your embed has an in-embed notification setting:

async function disableNotifications() {
const permissions = await mbpClient.notifications.revokeConsent();

showNotificationsDisabled();
}

revokeConsent() turns off this embed's consent and removes its request for remote delivery. It also cancels local notifications scheduled by the embed. It does not change the operating system's app-level notification permission.

Do not call revokeConsent() when a component unmounts, when a user signs out of your service, or as part of a failed request. It is a user choice, not cleanup.

revokeConsent() only manages consent in the host application. If your service also keeps its own notification preferences, update those separately.

When notifications are blocked and canAskAgain is false, offer a link to the app's notification settings. The user can review system permission and embed settings there.

import { AppHostRoutes } from '@govflanders/mbp-embed-sdk';

await mbpClient.navigation.openHostRoute(AppHostRoutes.Notificaties);

Read the permission state again when the user returns. Opening an app route covers the embed, but the page stays alive in the mobile app. The browser visibilitychange event is a reliable return signal:

document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
void refreshNotificationPermission();
}
});

async function refreshNotificationPermission() {
const permissions =
await mbpClient.notifications.getNotificationPermissions();
updateNotificationUi(permissions);
}

Only refresh state from this handler. Never call requestConsent() from visibilitychange. The user did not ask for a prompt by returning to the embed.

The host application's notification screen can link to a settings URL configured for your embed. That page opens as your embed and is the right place for choices the host application cannot manage on your behalf, such as notification topics, individual subscriptions, or provider-side quiet hours.

Ask the Mijn Burgerprofiel team to configure the URL as part of onboarding. The host application uses the embed label for the link. A user can then open the page from the host application's notification settings.

Keep two levels of control separate on that page:

  • General consent controls whether this embed may use notifications at all. Read it with getNotificationPermissions(). Change it only through requestConsent() or revokeConsent().
  • Service preferences control which notifications your service sends. Store and apply those preferences in your own backend. A user turning off one topic should not revoke general consent for the whole embed.

For example, a page might offer a general "Notifications on" switch backed by requestConsent() and revokeConsent(), followed by topic switches such as "Appointment reminders" or "Application updates" backed by your service. When general consent is off, keep the topic selections visible if that helps the user, but make clear that the service cannot deliver remote notifications until they turn general consent back on.

The detail page can use the same notification SDK methods as the rest of your embed. Refresh permissions when it becomes visible again, as shown above. This matters when the user moves between the detail page and the host application's settings.

scheduleNotification() creates a notification on the device. It returns its identifier when scheduling succeeds, or undefined when notifications are unavailable or the user does not give consent.

const identifier = await mbpClient.notifications.scheduleNotification({
content: {
subtitle: 'Appointment reminder',
body: 'Your appointment starts in one hour.',
priority: 'high',
data: {
appointmentId: 'a1b2c3',
},
},
trigger: {
date: new Date('2026-06-18T09:00:00+02:00'),
},
action: {
type: 'embed',
url: '/appointments/a1b2c3',
},
});

if (!identifier) {
showReminderWasNotScheduled();
return;
}

saveScheduledReminder(identifier);

The host application supplies the notification title. Your embed supplies subtitle, body, optional priority, and data. Do not put secrets or personal data in data; a notification can appear on a locked device.

Omit trigger to show the notification immediately. Pass a Date for a one-time scheduled notification. The SDK serialises dates across the embed boundary, so always construct the date in your own timezone-aware application code.

A schedule request may start the local consent flow if consent is absent. It does not request remote-push registration. That difference is deliberate: a user asking for a reminder has not necessarily agreed to receive backend-driven notifications.

An embed action opens an embed URL. Relative URLs resolve against the current embed URL. Use one for a page within your own embed:

action: {
type: 'embed',
url: '/appointments/a1b2c3',
}

A hostRoute action opens a route in the host application. Use it only for routes that make sense outside your embed:

import { AppHostRoutes } from '@govflanders/mbp-embed-sdk';

action: {
type: 'hostRoute',
route: AppHostRoutes.Notificaties,
}

If you omit action but put a string url in content.data, the host application treats that URL as an embed action. Prefer the explicit action field in new code.

getAllNotifications() returns the local notifications scheduled by the current embed. Keep the identifier if the user needs to cancel a specific reminder:

const notifications = await mbpClient.notifications.getAllNotifications();

await mbpClient.notifications.cancelNotification(identifier);

Cancel a reminder when the event it refers to is cancelled or its time changes. Schedule a new one after changing a date; do not assume an existing notification updates itself.

A simple notification preference screen normally needs these pieces:

  1. Read permissions when the screen opens.
  2. Use requestConsent() from an explicit enable action.
  3. Use revokeConsent() from an explicit disable action.
  4. When consent is unavailable, link to AppHostRoutes.Notificaties instead of showing the same prompt again.
  5. Refresh permissions after the embed becomes visible again.
  6. If the embed has provider-specific topics or subscriptions, configure a detail settings page and keep those preferences separate from general consent.

Local reminders fit alongside that screen, but do not make a local reminder the only way a user can enable remote notifications. The two actions have different consequences.

scheduleNotification(), requestConsent(), and revokeConsent() can reject when the SDK cannot communicate with the host application. This can happen when the embed is not configured to use notifications or when the host application does not support them. Catch those failures and show a normal technical-error state with a retry action.

A returned permission result with granted: false, or an undefined result from scheduleNotification(), is not a communication error. It means the notification could not be scheduled under the current consent and system-permission state.

Connect the SDK client before using notifications, as with every other SDK feature:

await mbpClient.connect();
  • Give users a clear reason before asking for consent.
  • Ask for remote-push consent from an explicit user action.
  • Treat a declined or rate-limited prompt as a normal outcome.
  • Keep provider-side subscription settings separate from SDK consent.
  • Configure an embed detail settings page when users need topic-level or subscription-level choices.
  • Cancel obsolete local reminders.
  • Test a denied system permission and a return from the host application notification settings.
  • Test notification taps on a real device.