skip to content

You own the frontend of a product that wants two browser permissions — notifications and geolocation. Given that a denial is stored per origin and no script can reset it, how do you decide when and how each prompt is triggered?

level: principalimportance: should knowfreq 26%

answer

  1. one-shot, irreversible resource
  2. never on page load
  3. soft ask before the hard ask
  4. read state before asking
  5. design the denied path first

basics

~20 s

Treat each prompt as a one-shot resource. Ask only at the moment the feature is obviously useful, always behind an explicit user action, gate the real prompt behind your own in-app ask you can safely repeat, and design a working experience for users who never grant.

solid answer

~60 s

A permission prompt is a **one-shot, irreversible resource**: a denial is stored per origin, no API can clear it, and only the user can undo it in browser site settings — which almost nobody does. So the decision is not "when do we ask" but "what is the least risky moment to spend our single chance". I would never prompt on page load; I would tie each prompt to a user action that makes the reason obvious — a click on "notify me when this ships", a click on "use my location" — and put a soft, in-app ask in front of it, so a user who is not interested declines *my* dialog, which I can show again later, rather than the browser's, which I cannot. Before asking I read `navigator.permissions.query()` so a denied user gets a settings hint instead of a dead button. Every feature needs a degraded path: manual address entry, in-app inbox. Then instrument grant, deny and dismiss rates and treat them as a product metric.

go deeper

for a junior

Know that a permission prompt can only be answered once per site and that a block cannot be undone by your code. Never trigger one on page load; attach it to a button the user deliberately pressed.

for a middle

Explain the double-prompt pattern and why checking the stored state first matters: a denied user should see a settings hint, not a button that silently does nothing when clicked.

for a senior

Show you would build the degraded experience first, instrument grant, deny and dismiss outcomes per surface, and account for browser heuristics such as quiet notification UI and dismissal embargoes when reading those numbers.

for a principal

Own the origin-level budget: prompts are a shared, exhaustible resource across teams, so set rules about who may ask, at what moment, and with what fallback, and be ready to say no to a feature whose value depends on a permission you cannot guarantee.

## Why this is a strategy question at all Most API decisions are reversible. This one is not. When a user clicks "Block" on a browser permission prompt, the decision is stored against your origin, and nothing in your code can undo it or ask again — repeated calls to the feature simply fail without UI. The only recovery is the user opening the browser's own site settings, a path with a conversion rate close to zero. So each permission is effectively a single request you may make of each user, forever. Browsers have also stopped being neutral referees. Firefox requires a user gesture before `Notification.requestPermission()` will do anything. Chrome shows a quieter, less interruptive notification prompt for sites with historically poor acceptance rates and for users who habitually block. Both engines embargo a permission after repeated dismissals, silently converting "the user ignored it" into "stop asking". Aggressive prompting therefore does not merely annoy users; it degrades your ability to ask at all, and the penalty attaches to your origin's reputation rather than to the individual page. ## The decision framework **Does the feature need a permission at all?** The cheapest win is often designing it away. Location can come from a typed postcode or a coarse IP lookup on the server; "notify me" can be an email or an in-app inbox that needs nothing. Reserve real prompts for cases where the platform capability is genuinely the product. **When is the moment?** Prompt at the point of obvious value, immediately after an explicit user action that expresses the intent — a click on "Find stores near me", not a page load, not a scroll, not a timer. The user's mental model must be "I asked for this and the browser is confirming", never "a dialog appeared". **Use a soft ask in front of the hard ask.** Show your own inline explanation with a clear opt-in. Only when the user accepts *your* dialog do you call the browser API. A user who declines your dialog costs you nothing — you may show it again next week, in a better context. A user who declines the browser's dialog is gone permanently. This double-prompt pattern is the single highest-leverage decision here, and the honest tradeoff is that it adds a step for users who would have granted anyway. **Read the state before asking.** `navigator.permissions.query()` distinguishes the three cases with no UI. `'granted'` means proceed straight to the feature. `'prompt'` means the soft ask is worth showing. `'denied'` means never call the feature: render a short explanation of where the setting lives instead of a button that appears broken. Remember that Chromium exposes clipboard-related names that other engines do not, and an unrecognised name rejects, so wrap the call. ## What has to exist regardless Design the denied path first, not last. If the product is unusable without notifications, the permission has become a load-bearing dependency on a decision you do not control. A store locator needs manual entry; an alerting feature needs an in-app inbox and optionally email. Building these first also removes the temptation to nag, because the denial stops being catastrophic. Separately, remember the technical preconditions that sit underneath the whole discussion: these APIs are restricted to secure contexts, and in an embedded document a Permissions Policy may disable the feature entirely — in which case there is no prompt to strategise about. A permission strategy that has not verified those is measuring the wrong thing. ## Instrumentation Treat prompt outcomes as a product metric with a named owner. Record, per feature and per surface: how many users saw the soft ask, how many accepted it, how many then granted, denied or dismissed the browser prompt, and what proportion of denied users later engage with the degraded path. Without this, permission strategy is folklore. With it, you can compare two placements honestly and detect the moment a browser changes its heuristics and your grant rate quietly halves. One caution on measurement: browsers deliberately do not tell you whether a prompt was dismissed rather than denied, and quiet UI means some users never see it. Your numbers are a lower bound on interest, not a clean signal. ## Organisational rules worth writing down - No permission prompt fires without an immediately preceding user action. - Every prompt is preceded by an in-app explanation that names what the user gets. - Every permission-backed feature ships with a working degraded path. - A team wanting a new permission must state the recovery experience for denial before the request is approved. These are cheap to state and prevent the common failure, which is not a bad prompt but three teams independently deciding their feature deserves one at page load.

  • What is the cost of the soft-ask pattern, and when would you skip it?
    It inserts a step for users who would have granted immediately, which measurably reduces completion on a high-intent flow. I would skip it where the action is unambiguous and the feature is the whole point — a user clicking "share my live location" already understands what happens next. Reserve it for features whose value is not self-evident from the click.
  • A team wants to prompt on page load because their grant rate is higher that way. How do you respond?
    Ask what they measured. Load-time prompts often show a high grant rate among the users who stay, because the users who blocked or bounced are missing from the denominator. Then point at the origin-wide cost: dismissals feed browser embargoes and quiet UI, so their local optimisation degrades every other permission the product will ever want.
  • How would you help a user who blocked notifications and now wants them?
    Detect it — `navigator.permissions.query({ name: 'notifications' })` returning 'denied' — and replace the broken-looking control with a short, browser-appropriate instruction pointing at the site settings for the page, plus the alternative channel. Listen for the `change` event so the moment they flip it, the page updates without a reload.

saying these in an interview costs you the question

  • Requests notification permission on first page load
  • Believes a denial can be reset from JavaScript
  • Treats repeated dismissals as free retries
  • Ships a feature with no path for denied users
  • Assumes browsers show every prompt they are asked to

context