Notification Permission β Requesting and Managing User Consent
In this tutorial, you will learn about Notification Permission. We cover key concepts, practical examples, and best practices to help you master this topic.
Notification permission in PWAs requires explicit user consent through the Notification API, with strategies for graceful requests, handling denial, and respecting user preferences.
What You'll Learn
By the end of this tutorial, you will understand how to request notification permission, handle the three permission states (granted, denied, default), implement permission priming, and design permission UX that maximizes opt-in rates.
Why It Matters
Poorly timed permission requests annoy users and hurt opt-in rates. Once denied, most browsers never ask again β the user is lost forever. A thoughtful permission Strategy can increase opt-in rates from 10% to 60% or more.
Real-World Use
A travel PWA waits until the user has viewed 3 destinations before requesting notification permission. The request appears in-context: "Want to know when flight prices drop for these destinations?" Opt-in rate: 68%. Without priming and context, the rate was 12%.
Permission States
Notification Permission Flow
ββββββββββββββββββββββ
β Permission State β
β = 'default' β β Never asked, can prompt
ββββββββββ¬ββββββββββββ
β User clicks "Subscribe"
ββββββββββββββββββββββ
β Browser shows β
β permission dialog β
ββββββββββ¬ββββββββββββ
β β β
ββββββββββ ββββββββββ ββββββββββββββ
βGranted β β Denied β β Dismissed β
βββββ¬βββββ βββββ¬βββββ βββββββ¬βββββββ
β β β
Can send Cannot send Still default,
notifications Never ask can prompt again
again
Think of permission states like a door. Default means the door is closed but unlocked β you can knock and ask to enter. Granted means you have a key. Denied means the door is bolted from the inside and you can never enter again.
Basic Permission Request
async function requestNotificationPermission() {
if (!('Notification' in window)) {
console.log('Notifications not supported');
return 'unsupported';
}
try {
const permission = await Notification.requestPermission();
console.log('Permission result:', permission);
if (permission === 'granted') {
console.log('Notification permission granted');
// Now subscribe to push
await subscribeToPush();
} else if (permission === 'denied') {
console.log('Notification permission denied');
showPermissionDeniedUI();
} else {
console.log('Notification permission dismissed');
}
return permission;
} catch (error) {
console.error('Permission request failed:', error);
throw error;
}
}
Permission Priming
Always explain why you need notifications BEFORE requesting permission:
// Permission priming with user interaction
let permissionPrimed = false;
function primeForPermission() {
if (permissionPrimed) return;
if ('Notification' in window && Notification.permission !== 'default') return;
const banner = document.createElement('div');
banner.className = 'permission-prime';
banner.innerHTML = `
<div class="prime-content">
<h3>Stay Updated</h3>
<p>Get notified when new content is available,
even when you are not on this page.</p>
<button id="enable-notifications" class="btn-primary">
Enable Notifications
</button>
<button id="maybe-later" class="btn-secondary">
Maybe Later
</button>
</div>
`;
document.body.appendChild(banner);
document.getElementById('enable-notifications').onclick = async () => {
banner.remove();
permissionPrimed = true;
await requestNotificationPermission();
};
document.getElementById('maybe-later').onclick = () => {
banner.remove();
permissionPrimed = true;
};
}
// Show the primer after user has engaged
document.addEventListener('DOMContentLoaded', () => {
// Wait 30 seconds or after specific user action
setTimeout(primeForPermission, 30000);
});
Checking Permission State
function getNotificationStatus() {
if (!('Notification' in window)) {
return {
supported: false,
permission: null,
canPrompt: false,
message: 'Notifications not supported'
};
}
const permission = Notification.permission;
return {
supported: true,
permission: permission,
canPrompt: permission === 'default',
message: permission === 'granted'
? 'Notifications enabled'
: permission === 'denied'
? 'Notifications blocked'
: 'Notifications not yet requested'
};
}
// React to permission state
const status = getNotificationStatus();
if (status.supported && status.canPrompt) {
console.log('We can still ask for permission');
showPrimeBanner();
} else if (status.permission === 'denied') {
console.log('Permission denied, show alternate engagement');
showEmailSubscribeOption();
} else if (status.permission === 'granted') {
console.log('Already subscribed');
updatePushSubscriptionUI();
}
Handling Permission Denial
When permission is denied, offer alternatives:
function showPermissionDeniedUI() {
const container = document.createElement('div');
container.className = 'permission-denied-info';
container.innerHTML = `
<div class="denied-content">
<h3>Notifications are blocked</h3>
<p>You blocked notifications for this site.
You can enable them in your browser settings:</p>
<ol>
<li>Click the lock icon in the address bar</li>
<li>Find "Notifications" in the site settings</li>
<li>Change to "Allow"</li>
</ol>
<p>Alternatively, follow us on social media for updates:</p>
<div class="social-links">
<a href="https://twitter.com/example">Twitter</a>
<a href="https://facebook.com/example">Facebook</a>
</div>
</div>
`;
document.body.appendChild(container);
}
async function checkAndHandleBlocked() {
const permission = Notification.permission;
if (permission === 'denied') {
// You can detect this after a failed request
// Browsers remember the 'denied' state
console.log('Permission was previously denied and cannot be re-requested');
showPermissionDeniedUI();
}
}
In-Context Permission Requests
Instead of asking on page load, ask at a natural moment:
// Ask permission when user performs an action that benefits from notifications
document.getElementById('subscribe-updates').addEventListener('click', async () => {
const permission = await requestNotificationPermission();
if (permission === 'granted') {
// User subscribed, show success
showToast('You will now receive updates!');
} else if (permission === 'denied') {
showToast('Notifications blocked. You can change this in settings.');
}
});
// Ask when user completes a meaningful action
checkoutForm.addEventListener('submit', async (event) => {
event.preventDefault();
await processCheckout();
// After successful checkout, ask about order updates
if (Notification.permission === 'default') {
const wantsUpdates = confirm(
'Would you like to receive order status updates via notification?'
);
if (wantsUpdates) {
await requestNotificationPermission();
}
}
});
Respecting User Preferences
// Store user preference server-side
async function updateNotificationPreference(enabled) {
const subscription = enabled
? await subscribeToPush()
: await unsubscribeFromPush();
await fetch('/api/notification-preference', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
enabled,
endpoint: subscription?.endpoint
})
});
}
// Preference toggle in settings
document.getElementById('notification-toggle').addEventListener('change', async (event) => {
const enabled = event.target.checked;
if (enabled && Notification.permission === 'default') {
// Need to request first
const permission = await requestNotificationPermission();
if (permission === 'granted') {
await updateNotificationPreference(true);
} else {
event.target.checked = false;
}
} else {
await updateNotificationPreference(enabled);
}
});
Common Mistakes
- Requesting permission immediately on page load. Users who just arrived are not ready to grant permission. Always wait for engagement or a natural moment.
- Not priming before requesting. Users who understand WHY they need notifications are 3-5x more likely to accept. Always explain the value first.
- Not handling the 'default' state. Users may dismiss the prompt (not accept or deny). This is different from 'denied' β you can ask again later.
- Requesting permission for users who already denied. Most browsers do not show the prompt again. Check permission state before requesting.
- No fallback when permission is denied. Users who deny notifications are not bad users. Offer alternatives like email, RSS, or social media follow.
Practice Questions
- What are the three possible states of Notification.permission?
- What is permission priming and why is it important?
- Why should you avoid requesting permission immediately on page load?
- What happens when a user denies the permission prompt?
- How can you re-engage users who denied notifications?
Challenge: Design and implement a complete permission flow: prime banner that explains value (shown after 30 seconds or 3 page views), permission request at a natural moment, handling of grant/denial/dismissal states, and an alternative engagement option for denied users.
FAQ
Mini Project
Build a complete notification permission management system: a permission priming banner that appears after the user clicks 3 articles, an in-context permission request during checkout flow, a toggle in settings to enable/disable notifications, and a fallback email subscription option for users who deny notifications. Track opt-in rate.
What's Next
Permission is handled. Now learn about Background Sync β deferring server actions until connectivity returns, enabling true offline-first functionality.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro