Requesting Desktop Notification Permissions in JS

Learn the correct way to request notification permission in JavaScript, handle user denial, and build a permission-aware notification flow.

5 min read

Browsers block desktop notifications by default. Before your web app can display a notification, the user must explicitly grant permission through a browser dialog. How you ask for that permission determines whether the user accepts or permanently blocks your app.

The permission model is simple: check the current state first, then ask at the right moment on a user action.

javascriptjavascript
if (Notification.permission === "granted") {
  console.log("Permission already granted");
} else if (Notification.permission === "denied") {
  console.log("Permission was denied, cannot ask again");
} else {
  console.log("Permission is default, ready to ask");
}

The three permission states are "granted", "denied", and "default". The default state means the user has not made a decision yet, and this is your one opportunity to ask.

The permission request flow

The flow from no permission to granted permission follows a clear path. Understanding each step helps you build a user experience that maximizes acceptance:

Notification permission request flow

The flow starts by checking the current permission. If already granted, you can send notifications immediately, and if denied, there is nothing more you can do.

If the state is default, show your own opt-in prompt before triggering the browser dialog.

Asking at the right time

Never call requestPermission on page load. Modern browsers silently ignore it. The call must come from a user gesture like a click:

javascriptjavascript
document.querySelector("#enableNotifications").addEventListener("click", () => {
  Notification.requestPermission().then((permission) => {
    if (permission === "granted") {
      console.log("Notifications enabled");
    } else {
      console.log("User declined notifications");
    }
  });
});

The button click satisfies the user gesture requirement. The browser shows its native permission dialog, and the promise resolves with the user's choice. The best time to show your enable button is after the user has experienced value from your app, not on the first page load where they have no reason to say yes.

Building a custom opt-in prompt

The most effective pattern uses a two-step approach: show a custom prompt explaining why notifications are useful, then call requestPermission only after the user agrees. Start with a function that builds and inserts the prompt element:

javascriptjavascript
function createOptInPrompt() {
  const prompt = document.createElement("div");
  prompt.innerHTML = `
    <p>Get notified when your builds finish.</p>
    <button id="allowBtn">Enable notifications</button>
    <button id="dismissBtn">Not now</button>
  `;
  document.body.appendChild(prompt);
  return prompt;
}

This function only builds and displays the prompt, it does not wire up any behavior yet. A second function creates the prompt and attaches the click handlers that respond to the user's choice:

javascriptjavascript
function showOptInPrompt() {
  const prompt = createOptInPrompt();
 
  document.querySelector("#allowBtn").addEventListener("click", () => {
    prompt.remove();
    Notification.requestPermission();
  });
 
  document.querySelector("#dismissBtn").addEventListener("click", () => {
    prompt.remove();
  });
}

This separates your messaging from the browser's native prompt. Users who click Enable in your UI are far more likely to click Allow in the browser dialog than users who see the browser dialog with no context.

Handling the denied state

Once the user denies permission, you cannot ask again from code. The only way to reset it is for the user to manually change the site settings in their browser preferences. Your app must handle this state gracefully:

javascriptjavascript
function setupNotifications() {
  if (Notification.permission === "granted") {
    return;
  }
  if (Notification.permission === "denied") {
    console.log("Notifications are blocked. The user can re-enable them in browser settings.");
    return;
  }
  showOptInPrompt();
}

Do not show the opt-in prompt when the permission is already denied. It wastes the user's time and creates frustration. Instead, show a message explaining how to re-enable notifications through browser settings if your app critically depends on them.

Checking permission on page load

The permission state persists across page reloads and browser restarts. Check it every time your page loads to know whether you can send notifications:

javascriptjavascript
document.addEventListener("DOMContentLoaded", () => {
  if (Notification.permission === "granted") {
    console.log("Ready to send notifications");
  } else if (Notification.permission === "default") {
    console.log("Show opt-in prompt after user engagement");
  }
});

This lets you show the opt-in prompt at the right moment without repeatedly calling requestPermission. Once the user decides, the state sticks.

Common mistakes

  • Calling requestPermission immediately on page load. Browsers require a user gesture and silently ignore the call.
  • Showing the opt-in prompt when permission is already denied. The user cannot change their decision from your code.
  • Assuming the user will grant permission. Design your app so notifications are an enhancement, not a requirement.
  • Not providing a way to disable notifications after the user enables them. Respect user preference changes.

Quick reference

ScenarioCode
Check permissionNotification.permission
Request permissionNotification.requestPermission()
Only ask on gestureWrap in a click event listener
Denied is permanentCannot re-request from code
Build double opt-inShow custom prompt, then call requestPermission
Check on page loadRead Notification.permission in DOMContentLoaded
Rune AI

Rune AI

Key Insights

  • Check Notification.permission before calling requestPermission.
  • Only call requestPermission from a user gesture like a button click.
  • Build a custom opt-in UI that explains the value before the browser prompt appears.
  • A denied permission is permanent for that origin. Design your UX for the denied state.
  • The permission state persists across page reloads and browser restarts.
RunePowered by Rune AI

Frequently Asked Questions

Why does Notification.requestPermission do nothing on page load?

Modern browsers require requestPermission to be called from a user gesture like a button click. Calling it automatically on page load is silently ignored to prevent spammy permission prompts.

Can I ask for permission again after the user denies it?

No. Once the user clicks Deny or Block, the permission state becomes 'denied' permanently for that origin. The only way to reset it is for the user to manually change the site settings in their browser preferences.

How do I show a custom prompt before the browser permission dialog?

Show a custom UI explaining why notifications are useful, and only call requestPermission when the user clicks your custom Allow button. This two-step pattern is called a 'double opt-in' and improves acceptance rates.

Does the permission persist across page reloads?

Yes. Once the user grants or denies permission, that decision is stored by the browser for your origin. You only need to call requestPermission once per user.

Conclusion

Requesting notification permission the right way means checking the current state first, asking only on a user gesture, and respecting the user's decision whether they grant or deny. A custom opt-in step before the browser prompt dramatically improves the chance the user says yes.