Custom pre-permission
The pre-permission approach is commonly used to improve opt-in rates for push notifications while complying with browser requirements. A pre-permission is a custom, website-controlled prompt shown before the browser’s native permission dialog. It allows you to explain the purpose of notifications, provide context, or guide the user toward the system-level prompt in a controlled manner. For Web Push, you can rely on our default pre-permission modes, which offer a simple and integrated way to request permission.
While these modes cover most use cases, some scenarios require a fully customized onboarding experience that aligns with your user flow and your website’s visual identity. This section explains how to create your own pre-permission dialog using the methods provided by our Web SDK.
Implementing our SDK
After completing the setup guides and selecting the None mode in the Launch Configurator, you can start building your own pre-permission flow.
If you are customizing your own pre-permission dialog, let our support team know so that we can adapt your Launch Configurations to None.
Begin by integrating the library in the same way you would when using any of the managed approaches. The Web SDK can be included in a project either via NPM or CDN.
Once the SDK is included, the next step is the same for both methods: initialize Actito Push:
import { launch, onReady } from 'notificare-web/core';
onReady(() => {
});
await launch();
At this stage, if the configuration is correct, the library should already initialize successfully. During development, it is often useful to enable debug messages. This can be done by adding the following line immediately before the launch() method:
import { launch, onReady, setLogLevel } from 'notificare-web/core';
setLogLevel('debug');
onReady(() => {});
await launch();
The pre-permission
With the SDK initialized, you can now request push notification permission from users. In the following example, a banner is added at the top of the web application. The banner contains a short message along with Cancel and Accept buttons. An example structure is shown below:

To do something like this, we would need to add the following markup in our pages:
<div id="prePermissionBanner" style="display: none;">
<div class="text">We would like to send you notifications for our latest news, updates and events.</div>
<button id="cancelButton">No, thanks</button>
<button id="acceptButton">Yes, definitely</button>
</div>
The previous example is only a reference implementation. This is the point where you can customize the pre-permission dialog to match your own UI and user experience. Regardless of the markup or CSS you apply, it is important to provide clear information that helps users understand the value of enabling push notifications.
In all cases, the dialog should include two actions:
- one button to dismiss the pre-permission,
- and one button to trigger the native notification permission prompt.
Next, you can implement the interactive behavior of the pre-permission dialog using helper methods provided by the Web SDK.
Before displaying the dialog, it is necessary to confirm that it is appropriate to do so. The pre-permission should only appear when:
- the browser supports Web Push, and
- the user has not yet granted or denied notification permission.
To enforce these conditions, use the onReady() callback as shown below:
import { launch, onReady } from 'notificare-web/core';
import { enableRemoteNotifications, hasWebPushCapabilities, getPushPermissionStatus } from 'notificare-web/push';
onReady(() => {
const prePermissionBanner = document.getElementById('prePermissionBanner'),
cancelButton = document.getElementById('cancelButton'),
acceptButton = document.getElementById('acceptButton');
if (hasWebPushCapabilities() && getPushPermissionStatus() === 'default') {
prePermissionBanner.style.display = 'block';
cancelButton.addEventListener('click', () => {
prePermissionBanner.style.display = 'none';
});
acceptButton.addEventListener('click', async () => {
prePermissionBanner.style.display = 'none';
await enableRemoteNotifications();
});
}
});
await launch();
The previous code implements the interactive behavior of the pre-permission dialog.
- Import necessary methods from the Push module. These methods allow the application to determine whether the pre-permission should be displayed based on the user’s current notification status and browser support.
- Reference DOM elements for the banner and the buttons. These references are used to show or hide the banner and to attach click event handlers for user actions.
- Display the pre-permission conditionally. Using the imported helper methods, the code checks if the user meets the criteria (browser supports Web Push and the user has not yet granted or denied permission). The banner is displayed only if these conditions are satisfied.
- Handle user actions:
- Clicking Cancel hides the banner without requesting permission.
- Clicking Accept hides the banner and calls
enableRemoteNotifications(), which triggers the native browser permission prompt
This structure ensures that the pre-permission dialog appears only when appropriate and that user interactions are handled correctly.
Other customizations
The pre-permission dialog can be customized to any level of complexity. This flexibility is one of the main reasons to implement a custom pre-permission instead of using one of the managed launch modes.
For instance, in the previous example, the banner is hidden when the user clicks Cancel, but it will reappear when the page reloads. To prevent this, you can implement additional logic. For example, using sessionStorage(), you can ensure the pre-permission is not shown again during the current browser session, until the user closes the tab or window.
The code can then be updated accordingly:
import { launch, onReady } from 'notificare-web/core';
import { enableRemoteNotifications, hasWebPushCapabilities, getPushPermissionStatus } from 'notificare-web/push';
onReady((application) => {
const prePermissionBanner = document.getElementById('prePermissionBanner'),
cancelButton = document.getElementById('cancelButton'),
acceptButton = document.getElementById('acceptButton');
if (hasWebPushCapabilities() && getPushPermissionStatus() === 'default' && !sessionStorage.get('prePermission')) {
prePermissionBanner.style.display = 'block';
cancelButton.addEventListener('click', () => {
prePermissionBanner.style.display = 'none';
sessionStorage.set('prePermission', 1);
});
acceptButton.addEventListener('click', async () => {
prePermissionBanner.style.display = 'none';
await enableRemoteNotifications();
});
}
});
await launch();