# Market Research Market Research Report - Global

**Generated on:** 2026-10-14 10:53:03.790667  
**Industry:** Market Research  
**Geography:** Global  
**Details:** # Deep Research Prompt: Non-blocking "new version available" notice for long-open web app tabs

> Pipeline note: paste this full prompt into ChatGPT Deep Research, Gemini (Thinking), Perplexity, DeepSeek (Expert) and Claude. For Grok, prefix it with the contrarian framing in the final section before pasting.

---

## Context

Voxpopme is a B2B video research platform. Customers (market researchers, insight teams, product and marketing teams at enterprise clients) use a browser-based portal to set up studies, review respondent videos, read AI-generated analysis and build reports. Sessions can be long: a researcher may keep a portal tab open for hours or days while they work across other tools.

The portal is a single-page application served as code-split JavaScript chunks. When a new release is deployed, the old chunk files are replaced. A tab that is still running the previous build will fail when it tries to lazy-load a chunk that no longer exists.

Two situations are being handled separately:

1. **Deploy-time chunk errors.** When a user navigates and a chunk is missing, the app will now show an automatic "Reloading Voxpopmeâ€¦" message and reload itself. This is already decided and in progress (ticket VOXDEV-3283).
2. **Long-open tabs.** A user who has had the portal open since before the deploy may be mid-task (writing a question set, editing a report, reviewing clips). We do not want to interrupt them with a forced reload. This is the subject of this research.

The proposed solution is a **non-blocking notice**, modelled on the existing "you appear to be offline" warning already in the product. It would tell the user that a new version is available and let them refresh when it suits them.

**Scale of the problem.** Across roughly 13,900 sessions between 22 September and 12 October 2026, only 2 to 3 sessions were long-open tabs where in-progress work was genuinely at risk. This is rare. Any recommendation must be proportionate to that frequency and must not create more friction for the other 13,897 sessions than it removes for the 2 to 3.

**What we need from this research.** Evidence-based, implementation-ready guidance on how mature web products handle this, what the UX and technical trade-offs are, and a clear recommendation with reasoning. Where the evidence suggests that the proposed non-blocking notice is the wrong approach, or that no notice is needed at all, say so.

---

## Research sections

### 1. Problem framing and proportionality
- Given 2 to 3 affected sessions out of ~13,900, what is the realistic cost of doing nothing beyond the automatic reload already planned?
- What is the cost of a notice that is shown to every user after every deploy, including users with nothing at risk?
- How do mature product teams decide between "fix at the moment of failure" (reactive) and "warn in advance" (proactive) for stale-build problems?
- Are there documented cases of version notices becoming noise that users learn to ignore, and what caused that?
- What would need to be true (deploy frequency, session length, data loss risk) for a proactive notice to be clearly worth it?

### 2. Established patterns and precedent
- How do Gmail, Google Docs, Figma, Notion, Linear, Slack (web), Jira, Asana, Miro, Dovetail, Qualtrics and similar SaaS products tell users a new version is available in an open tab? Describe placement, wording, dismissal and timing for each, with sources or screenshots where available.
- Which of these products use a non-blocking banner, which use a toast, which use a subtle in-app indicator, and which silently reload or do nothing?
- Which products preserve unsaved work across the reload, and how?
- What do Nielsen Norman Group, Baymard, GOV.UK Design System, Material Design, Atlassian Design System, Polaris (Shopify), Carbon (IBM) and similar design systems say about system status notifications and non-blocking notices?

### 3. Placement and visual treatment
- Should the notice reuse the existing offline-warning pattern (same position, colour, component) or be a distinct component?
- What are the risks of reusing a pattern that currently means "something is wrong" for a message that means "nothing is wrong yet, but a refresh is recommended"?
- Where should a persistent, low-urgency notice sit in a dense web app: top banner, bottom banner, bottom-left toast, header indicator, sidebar badge or elsewhere? What does the evidence say about noticeability versus intrusiveness for each?
- How should the notice behave on narrow viewports and when the user is in a focused editing surface (full-screen editor, modal, video player)?
- What colour, iconography and motion are appropriate for an informational, non-urgent system message?

### 4. Wording and microcopy
- What wording do the best-in-class products use? Collect real examples.
- How should the message explain what will happen on refresh (work preserved or not) without being alarming?
- Should the call to action say "Refresh", "Reload", "Update", "Get the latest version" or something else, and does the choice affect click-through or comprehension?
- Should the notice name the product ("A new version of Voxpopme is available") or stay generic?
- Is there evidence on whether including a reason ("to get the latest improvements") increases or decreases action?
- All wording must work for both UK and US readers (avoid words spelt differently in UK and US English).

### 5. Dismissal, persistence and snoozing
- Should users be able to dismiss the notice? If so, should it come back, and after what trigger (next navigation, next session, next deploy, fixed time)?
- Is a "remind me later" or snooze option useful, or does it add complexity for little gain?
- Should the notice be dismissable per tab or per user across tabs?
- How do products avoid the notice reappearing repeatedly during a day with multiple deploys?
- What is the accessibility impact of a notice that cannot be dismissed?

### 6. Trigger timing
- Compare the three candidate triggers: show immediately on detecting a new version, show after the tab has been idle for a defined period, show on the next route navigation. For each: pros, cons, evidence and which products use it.
- Are there other triggers worth considering: on window focus or visibility change, after the user saves, when the user is not in an editing state?
- What idle threshold do products typically use, and how is idle detected (Page Visibility API, user input listeners, requestIdleCallback)?
- Should the notice be suppressed while the user is in a known mid-task state (unsaved form, active recording, in-progress upload)? How do products detect "mid-task" reliably?

### 7. Technical detection of a new version
- What are the standard methods for a running SPA to learn that a new build has been deployed: polling a version endpoint or manifest, comparing a build hash, service worker update events, WebSocket or server-sent push, response headers on API calls?
- What polling interval is typical, and what is the cost and load implication?
- How do products coordinate the notice across multiple open tabs (BroadcastChannel, SharedWorker, localStorage events)?
- How should detection handle rollbacks, hotfix deploys in quick succession, and canary or partial rollouts?
- Provide concrete implementation sketches for a React code-split application.

### 8. Failure handling when the notice is ignored
- If the user dismisses or ignores the notice and later hits a missing chunk, what should happen? Should the automatic "Reloading Voxpopmeâ€¦" behaviour apply unchanged, or should the earlier notice change the handling?
- Can the app preload the new build's critical chunks in the background so that a later navigation does not fail?
- Can the app keep serving old chunks for a defined window after deploy (versioned asset paths, retained previous build on the CDN) so that long-open tabs never hit a missing chunk at all? What are the hosting and cache implications?
- What are the trade-offs between "retain old assets" and "notify the user" as solutions to the same problem?

### 9. Mid-task safety and work preservation
- What techniques do products use to preserve unsaved work across a reload: local draft autosave, sessionStorage snapshots, server-side drafts, restoring scroll and route state?
- Which of these is realistic for a research platform where in-progress work includes question sets, report edits, clip selections and video playback position?
- How should the notice wording change depending on whether work will be preserved?
- Is it better to invest in work preservation than in the notice itself?

### 10. Accessibility and compliance
- How should a non-blocking system notice be announced to screen readers (ARIA live region politeness, role=status versus role=alert)?
- What are the WCAG 2.2 requirements relevant to persistent notices, dismissal, focus management, timing and motion?
- How should the notice behave for keyboard-only users and for users with reduced-motion preferences?
- Are there any legal or contractual considerations for enterprise customers around forced reloads and data loss?

### 11. Edge cases and failure modes
- Multiple tabs on different builds, including one tab that already refreshed.
- A deploy while a video upload or live session is in progress.
- A deploy that also expires the user's auth session.
- The user refreshes and the new build has a bug, then a rollback happens.
- The notice appears during a screen-shared client presentation or a live interview.
- Users on slow or intermittent connections where "offline" and "new version" states overlap.
- What production failure modes have teams reported publicly for version notice features?

### 12. Measurement and success criteria
- What should be measured to know whether the notice works: impressions, click-through, dismissals, time to refresh, chunk-error rate after deploy, support tickets?
- What baseline should be captured before launch?
- What would indicate the notice is causing harm (notice fatigue, drop in task completion, increased dismissals over time)?
- Given the low incidence (2 to 3 in ~13,900 sessions), what sample sizes and timeframes would be needed to see any effect at all?

---

## Output instructions

- Write for a UX designer and a front-end engineer who will act on this directly. Be specific: give concrete values (pixel positions, idle thresholds in minutes, polling intervals, exact wording candidates), not ranges where a single recommendation is possible.
- Cite sources for every claim about what a named product or design system does. Prefer primary sources (official docs, design system pages, engineering blogs, changelogs) over secondary commentary.
- Clearly separate: (a) established evidence, (b) common practice without strong evidence, (c) your own reasoning.
- For every design choice, state the trade-off and who it costs.
- End with a single recommended approach covering placement, wording, dismissal, timing and fallback behaviour, plus one alternative if the recommendation is rejected.
- Explicitly answer: is the non-blocking notice the right solution at all, given the incidence data, or would "retain old chunks after deploy" or "invest in draft autosave" solve the underlying problem better?
- Flag anything surprising or counterintuitive you found.
- Use UK English in the report. Any proposed UI wording must use spellings that are identical in UK and US English.
- No em dashes.

---

## Grok contrarian prefix (use only for Grok)

I want you to be maximally contrarian about this topic. Challenge every assumption in the brief, including the assumption that a notice is needed at all when only 2 to 3 of ~13,900 sessions were affected. What do engineers secretly hate about "new version available" banners? What are the production failure modes nobody talks about? What wrong assumptions do product and design teams make about users' willingness to refresh? Where is the team solving the wrong problem? Then work through the research prompt below with that lens.

---

# Protecting Voxpopme Work Without Creating Update-Notice Fatigue

## Executive Summary

**Scope:** Global B2B research SaaS and comparable collaborative web applications. This is a product-reliability and UX market study, not a market-size forecast.

- **Do Not Broadcast A Rare Problem**: The supplied Voxpopme brief identifies **2-3 at-risk sessions in approximately 13,900**, equivalent to **0.014%-0.022%**. These are sessions with work at risk, not confirmed data-loss incidents -> do not introduce a routine notice after every deploy.
- **Prevent The Missing File**: Vite documents the exact failure mechanism: an old running application requests a deleted chunk. Vercel and Netlify address the broader problem through deployment version locking -> retain old immutable assets before asking users to manage deployments. [10][12][13]
- **Protect Work Independently**: Figma's engineering account describes local autosave that restores disconnected edits after reopening, using IndexedDB -> prioritise durable drafts for question sets and reports. A banner does not preserve work. [20]
- **Keep Recovery, Add A Safety Gate**: The decided automatic reload remains useful for safe navigation failures. However, a previous warning or dismissal cannot make an unsafe reload safe -> check current draft, upload and recording state before automatic recovery.
- **Do Not Copy Offline Severity**: Atlassian reserves its banner for critical messages and uses an assertive alert; Polaris supports lower-priority status messages -> share notification infrastructure, not the offline warning's urgency or accessibility semantics. [9][23]
- **Make Any Notice Optional And Targeted**: If a notice is required, the proposed specification is an informational strip immediately below the app header, **Refresh** and **Not now**, with no countdown. Show it at a safe task boundary or after **2 minutes** without input and with no protected activity. These are recommendations, not proven industry thresholds.
- **Separate Detection From Interruption**: For the optional implementation, check a scoped release manifest every **5 minutes while visible**, and on return to the tab with a **60-second** cooldown. Never reload merely because the build IDs differ.
- **Treat Precedents Honestly**: Public evidence does not establish the current long-open-tab update UX of most requested brands. Documented saving, desktop updates and feature announcements are not proof of a web deployment-notice pattern.
- **Measure Safety, Not Refresh Clicks**: At the supplied incidence, a conventional trial to detect a **50% reduction** would require approximately **436k-655k total sessions** under stated assumptions -> use deployment tests, restoration tests and incident-level monitoring rather than a short conversion-style A/B test.

**Bottom line:** Retaining old chunks solves the stated technical cause better than a notice. Draft autosave solves the more consequential work-loss risk better than a notice. Use both, with guarded reactive recovery; keep the notice as an alternative, not the default.


## 1. The 0.014%-0.022% Risk Does Not Justify A Broadcast

### Voxpopme's incident economics

The supplied period, **22 September-12 October 2026**, contains approximately **13,900 sessions** and **2-3 long-open sessions with in-progress work genuinely at risk**. It does not establish how much work was lost, the number of all chunk errors, the number of unique users, or the number of tabs open during each deploy. Those distinctions matter: the proposed banner addresses version staleness, while the reported numerator concerns a narrower, higher-consequence condition.

| Metric | Calculation from the supplied brief | Decision significance |
|---|---:|---|
| At-risk session rate | 2/13,900 to 3/13,900 = 0.0144%-0.0216% | A rare event, not a widespread workflow failure |
| Incidents per 10,000 sessions | 1.44-2.16 | A deployment-wide notice has a large potential exposure multiplier |
| Sessions per at-risk occurrence | Approximately 4,633-6,950 | Targeting matters more than visual prominence |
| Confirmed lost-work cost | Not supplied | Do not treat every at-risk session as actual loss |

The realistic cost of doing nothing beyond the planned reload is occasional interruption, possible loss of unpreserved edits, and associated support effort. At an unchanged rate, the supplied 21-day volume implies approximately **2.9-4.3 at-risk sessions per 30 days**. This is a conditional extrapolation, not a forecast or a count of confirmed losses.

Consider a deliberately hypothetical case: each affected session loses **15 minutes** of work. Across the supplied period, that represents **30-45 minutes**. If all 13,900 sessions instead spend just **2 seconds** noticing and evaluating an update message, the aggregate attention cost is **7.7 hours**. The break-even cost is only **0.13-0.19 seconds per exposed session**, before maintenance. Actual banner exposure could be much smaller; measure it rather than assuming every session overlaps a deploy.

### Evidence favours relevance, not maximum visibility

GOV.UK explicitly warns that people often miss notification banners and that overuse is likely to worsen this. Carbon similarly says notifications are disruptive and should be used sparingly. These are reasons to constrain exposure, not proof that a Voxpopme banner would necessarily fail. [2][11]

The academic framework **dual-task interference**, studied by Jenkins and colleagues, explains a second cost: the timing of an interruption affects attention to the message. The study concerns security warnings, so its numerical effects should not be transferred to this feature. Its mechanism nevertheless challenges the assumption that nonmodal means cost-free. [24]

A proactive notice becomes worthwhile when consequential stale-session exposure rises, losses are substantial, a safe refresh prevents them, and the message reaches those sessions without repeatedly distracting everyone else. Frequent deploys alone strengthen the case for retention: they also multiply opportunities for notice fatigue.

**Decision:** Compare expected avoided loss against actual exposed-tab attention and engineering cost. With the present evidence, prevent deployment skew and preserve drafts rather than broadcasting release activity.


## 2. SaaS Precedents Favour State Protection Over Copying Banners

### What the named products actually establish

**NE** below means **not established in the reviewed public evidence**. It does not mean the product does nothing, silently reloads, or lacks an internal mechanism. Customer reports are observations, not confirmed current product specifications.

| Product | Placement in an open web tab | Actual version/reload wording | Dismissal | Timing | Work preservation and evidence |
|---|---|---|---|---|---|
| Gmail | NE | NE | NE | Google says a supported browser opens the latest version; long-open-tab timing is NE | No reload-preservation mechanism established by that article. [15] |
| Google Docs | NE | NE | NE | NE | Configured offline editing stores documents locally; setup requires supported browsers, extension and device space. This is not a universal reload guarantee. [34] |
| Figma | NE | NE | NE | NE | Its 2020 engineering account describes disconnected edits saved to disk, restored and uploaded after reopening; IndexedDB is used. [20] |
| Notion | NE | NE | NE | NE | Official offline-page functionality is for desktop/mobile apps, **not web browsers**. Do not transfer that protection to the browser portal. [37] |
| Linear | NE | NE | NE | NE | A reload-specific draft guarantee was not established |
| Slack, web | NE | NE | NE | NE | Slack documents automatic unsent-message drafts; that article does not establish the web reload mechanism or an absolute preservation guarantee. [38] |
| Jira Cloud | NE | NE | NE | NE | A reload-specific draft guarantee was not established |
| Asana | Location NE; a customer reports a reload error | "Asana needs to be Reloaded" in the report | Reported Reload button did not resolve it | Reported when posting a long summary | The summary reportedly remained in draft. This is an error report, not verified deploy-notice behaviour. [17] |
| Miro | NE | NE | NE | NE | Board history provides recovery, but backups are hourly when changed and at collaborative-session end; network issues can prevent backup. [18] |
| Dovetail | NE | NE | NE | NE | A reload-specific draft guarantee was not established |
| Qualtrics | NE | NE | NE | NE | Survey changes are automatically saved; publication separately controls when respondents see them. [16] |
| Discourse | Screenshot supplied; exact location NE | "We've updated this site, please refresh..." | Reportedly persisted despite refresh | Reported after a forum upgrade | A rebuild resolved the reported condition; its root cause was not proven. [19] |
| Microsoft Power Apps code apps | Customer describes a host-rendered banner; exact position NE | "Refresh to use the latest version." | Reportedly disappears after refresh | Reportedly first opening an outdated cached build after publication | Customer requests control over the banner; this does not establish long-open-tab behaviour. [21] |

The comparison does **not** support a reliable classification of Gmail, Figma, Notion or Linear as current banner, toast, indicator or silent-reload implementations. The Discourse thread includes a screenshot, but it is not evidence for the other products. [19]

### The market-research workflow makes continuity valuable

The relevant competitive direction is richer, interconnected research work. Qualtrics describes video feedback, AI summarisation and highlight reels. Dscout supports longitudinal studies lasting days, weeks or a year; Outset places diary studies alongside interviews, surveys and usability studies with a shared analysis layer. These features describe the workflow context, not measured researcher tab duration or update UX. [50][51][52]

Qualtrics provides a particularly useful case: **saving and publishing are separate decisions**. Researchers can retain edits without immediately changing an active survey, and responses already in progress are unaffected by publication. The transferable principle is to distinguish persistence from externally visible activation, not to assume that a saved draft means a live study has changed. [16]

**Decision:** Benchmark independently against reliable saving and recovery mechanisms. Do not approve a version notice because a familiar brand is said to use one without a source establishing its actual web behaviour.


## 3. Use Informational Semantics, Not The Offline Warning's Urgency

### Design systems disagree on what a banner means

| Source | Established guidance | Implication for Voxpopme |
|---|---|---|
| Nielsen Norman Group | Alert-fatigue guidance prioritises critical values rather than endless unprioritised alerts. [53] | Do not give every release equal prominence |
| Baymard | Describes banners as persistent until dismissal/resolution and toasts as transient; temporary banners should not carry critical information. This is component guidance, not a stale-build experiment. [36] | A disappearing toast is unsuitable as the only route to a refresh action |
| GOV.UK | Use sparingly, before the page heading; show only the highest-priority message when messages cannot be combined. [2] | Avoid simultaneous offline and update banners |
| Material Design 2 | Banners are persistent, nonmodal, below the app bar, with only one at a time. [6] | Provides an appropriate structural precedent, not proof of effectiveness |
| Atlassian | Banners are critical, not dismissible, and use an assertive alert role; flags are bottom-left overlays. [9][8] | Its banner is the wrong semantic template for routine updates |
| Shopify Polaris React | Lower-priority banners should be dismissible; informational variants use status rather than alert. [23] | A better semantic match for an optional update |
| IBM Carbon | Notification urgency should determine disruption; newer guidance treats actionable notifications as persistent until dismissal. [1][11] | Use low-emphasis information and explicit user control |

**Surprising finding:** "Use a banner" does not specify a consistent severity, dismissal model or screen-reader behaviour. Atlassian and Polaris provide materially different components under the same name.

In Atlassian's case, the banner deliberately signals loss of data, functionality or important app-wide capability. Its alert role is acknowledged as noisy for assistive-technology users. Reusing that treatment for "nothing is wrong yet" would import both visual urgency and auditory interruption. [9]

Polaris takes a different approach: a low-priority default banner is dismissible, and noncritical variants use `role="status"`. The implication is to separate message intent from the existing component's appearance. [23]

### Placement trade-offs and the proposed specification

| Placement | Benefit | Cost and who pays | Recommendation |
|---|---|---|---|
| Top, below header | Discoverable, persistent, outside content controls | Uses vertical space for all exposed users | Best optional-notice location |
| Bottom banner | Persistent without moving top navigation | Can compete with video controls and narrow-screen actions | Avoid here |
| Bottom-left toast | Compact and familiar | Overlays clips/navigation; can disappear before use | Do not use as the sole refresh route |
| Header indicator | Lowest interruption | Easier to miss; may require exploration | Suitable only if updating is genuinely optional |
| Sidebar badge | Small footprint | Depends on an expanded sidebar; ambiguous to newcomers | Avoid as the main message |

These placement costs are product-specific reasoning, not measured cross-product superiority.

If the alternative notice is built, use **0 px gap below the main header**, in normal document flow, **48 px minimum height**, **16 px horizontal padding**, **12 px action spacing**, and no fixed overlay. Use the product's informational colour token, a static **16 px information icon**, and no entrance animation. Do not use warning amber, error red, a spinner or a countdown.

At widths below **600 CSS px**, use **12 px padding**, wrap the full message, place actions below it, and provide **44 px-high** action targets. Do not truncate essential copy. Queue it while a modal, full-screen editor, presentation or active video surface hides the app shell. Once visible, do not make it blink in and out on every keystroke.

**Decision:** Reuse the offline warning's infrastructure only if it supports a separate information variant and priority policy. Sharing position is reasonable; sharing severity is not.


## 4. Choose "Refresh" And State Only The Safety You Can Guarantee

### Real examples are useful, but not conversion evidence

The available examples are concise: Discourse's "We've updated this site, please refresh...", a Power Apps customer's reported "Refresh to use the latest version.", and Asana's reported error "Asana needs to be Reloaded". They illustrate different purposes: release information, host-version replacement and error recovery. None establishes a winning click-through rate. [19][21][17]

The Power Apps discussion is instructive. A customer requests the ability to suppress or control a host-rendered update banner, describing a message the app itself cannot manage because it is cross-origin. That observation highlights an ownership problem: deploying an application and deciding when to interrupt its user can belong to different layers. It is a reported concern, not proof of population-wide fatigue. [21]

For Voxpopme, keep that ownership in the app's task-safety layer. A release detector should supply facts; it should not generate marketing copy or decide that a refresh is safe.

### Exact wording candidates

All proposed UI text below uses spellings shared by UK and US English.

| Verified work state | Proposed message | Actions | Trade-off |
|---|---|---|---|
| No proven preservation guarantee | **"A new version of Voxpopme is available. Save your work, then refresh when ready."** | **Not now** / **Refresh** | Honest, but asks the user to assess saving; use only where a clear save path exists |
| Current edits are durably saved and restoration is tested | **"A new version of Voxpopme is available. Your changes are saved. Refresh when you're ready."** | **Not now** / **Refresh** | Reassuring, but must remain true at click time |
| Restorable local draft, not yet server-saved | **"A new version of Voxpopme is available. Your draft is saved on this device. Refresh when you're ready."** | **Not now** / **Refresh** | Precise about the limitation; longer message |

Do not say "You won't lose any work" unless that includes all current edits, clip state and relevant active operations. Do not use "Your changes are saved" merely because an autosave request was sent; the current revision must be acknowledged or a restorable local transaction committed.

**Refresh** is the recommended label because the action reloads the current browser page. **Reload** is technically accurate but need not be mixed with Refresh. **Update** can suggest an installation or a changed feature; **Get the latest version** is longer and less explicit about the immediate action. These are comprehension hypotheses, not established comparative results.

Name Voxpopme once to give context in a multi-tool workflow and in screen-reader announcements. Omit "to get the latest improvements" by default: it adds an unverified benefit without explaining safety. If a specific release fixes a relevant failure, state that concrete reason instead.

**Decision:** Use plain action language and truthful persistence status. Test comprehension, not just whether the message produces more clicks.


## 5. Dismiss Once Per Tab And Loaded Build

### The component does not solve persistence policy

Polaris React advises dismissal for lower-priority information. Shopify's newer web-component API separately documents that dismissal does **not** persist across page loads or sessions and that multiple banners have no built-in priority queue. A UI component alone therefore cannot provide a sensible release-notice policy. [23][22]

This is a useful implementation case: a team can adopt a visually correct banner and still ship repeated notices because persistence belongs to application state. For Voxpopme, that state must distinguish the tab's running build, the latest eligible release, and the user's decision to dismiss. The component should render a policy already decided elsewhere.

### Recommended optional-notice policy

| Event | Behaviour | Trade-off and affected party |
|---|---|---|
| User selects **Not now** | Hide the notice for this tab's loaded build | User control outweighs potential lost refresh clicks |
| Next route navigation | Do not re-show | Avoid punishing normal research work |
| Tab focus or another poll | Do not re-show | Detection is not a reminder |
| Another compatible hotfix | Do not override dismissal | Engineers cannot use every deploy as a fresh interruption |
| Reload into another build | Re-evaluate normally | A new running build is a new technical state |
| New independent tab | Compare its own build; do not inherit a global "updated" flag | Some duplication is preferable to suppressing a genuinely stale tab |
| Critical security/compatibility incident | Handle through a separate incident policy | Do not silently escalate a routine information component |

Keep a per-tab suppression marker keyed to the running build in `sessionStorage`, with an in-memory fallback if storage is unavailable. This is **not** a timed snooze. The marker should survive route changes and should not become a permanent user preference across devices.

Share release metadata across tabs, not the assertion that "the user has updated". A refreshed tab and an old tab can coexist; only each tab knows the JavaScript it is running. A global dismissal can hide useful information in the wrong tab, while broadcasting dismissal to all tabs can disregard the distinct task being performed in each.

Do not add "Remind me later", a duration picker or repeated eight-hour reminders for this incidence. **Not now** makes no promise of a future reminder and needs no scheduling logic. If multiple releases arrive before display, coalesce them into one current message; do not announce each build ID.

A non-dismissible static notice is not automatically a WCAG AA failure. Nevertheless, it consumes space and can obstruct magnified layouts; WCAG's interruption-suppression criterion is **AAA**, with emergency exceptions, rather than a universal AA close-button rule. [33]

**Decision:** Honour dismissal until this tab changes its running build. Do not optimise persistence for refresh conversion at the expense of user control.


## 6. Detect On Return, Display At A Safe Task Boundary

### Compare the candidate triggers

| Trigger | Advantage | Risk and who pays | Evidence and precedent limits |
|---|---|---|---|
| Immediately on version detection | Earliest opportunity to refresh | Interrupts editors, reviewers and presenters | No current named-product timing specification established; not recommended |
| After user inactivity | Defers during typing | Reading and video viewing may still be active work | Timing research supports task-sensitive interruption, not a particular idle threshold. [24] |
| Next route navigation | A possible task boundary | Navigation may itself request the missing chunk; leaving a dirty editor is not safe | No verified named-product attribution for this specific trigger |
| Window focus/visibility return | Finds tabs that missed timer checks | Returning users may urgently resume work | Page Visibility detects visibility, not safe-to-interrupt state. [28] |
| After a save and exit from editing | Clearer persistence boundary | Requires trustworthy app-state integration | Recommended for Voxpopme, not claimed as an industry standard |

The three requested triggers are not equally meaningful. Version detection is a technical event; a route change is a navigation event; neither is inherently a cognitive or persistence boundary.

### What the timing study does and does not support

Jenkins and colleagues find that interruption timing affects dual-task interference and security-message disregard. This supports reducing overlap with a primary task. It does not establish that two minutes, five minutes or any universal duration makes a SaaS user available. [24]

The practical implication is to ask the application about the task, not just the browser about visibility. A researcher who has stopped typing to watch a respondent's clip is not idle in the relevant sense. Likewise, a client presentation may contain little input while still being a poor moment for a release notice. These are contextual deductions, not measured findings from that study.

**Recommended optional display rule:** The tab is visible, no protected activity is running, work state is known, and either the user has saved and left the editing surface or there has been **120 seconds without user input**. Inactivity is a fallback opportunity, not proof of safety.

Reset the inactivity timestamp on `keydown`, `pointerdown`, `input`, `wheel` and touch input. Do not count every mouse movement as work. Separately track dirty editors, pending writes, uploads, recording, live-session activity, video playback, presentation mode and immersive editing. An unknown safety state is unsafe, not permission to reload.

The **Page Visibility API** distinguishes hidden and visible documents. `requestIdleCallback()` schedules work when the event loop has spare capacity; it does **not** detect human inactivity and has limited browser availability. [28][32]

Do not use a generic dirty flag inferred from typing alone. Editors and operations should register their own state in a central work-state registry and unregister on completion. A successful server save clears dirty status only for the revision actually saved.

**Decision:** Check for releases when the user returns, but defer display until a safe task boundary. Never use the idle threshold to authorise an automatic reload.


## 7. A Scoped Release Manifest Is Enough For An Optional Notice

### Detection choices

| Method | Mechanism | Advantages | Costs and limits |
|---|---|---|---|
| Release endpoint plus build ID | Compare the running build with the eligible manifest | Small, explicit, rollback-aware | Requires cache and rollout discipline |
| Version/hash manifest or ETag | Compare an immutable identifier | Simple where a manifest already exists | A hash is an identity, not an ordered version or transport |
| Service-worker update lifecycle | Observe installation/waiting state | Appropriate for an existing PWA | Adds another versioned runtime if introduced solely for a notice |
| WebSocket or server-sent event | Push release metadata | Fast; reuses an existing live channel | Reconnect, cohort and connection-management complexity |
| API response header | Piggyback release metadata on real requests | Little additional traffic | No detection when a tab makes no requests; shared APIs must identify the relevant front end |

These are engineering options, not a comparative study proving one is universally best. The service-worker lifecycle ordinarily lets a newly installed worker wait while the previous worker still controls clients; `skipWaiting()` deliberately overrides waiting. Do not introduce a service worker or immediate activation merely to implement this feature. [30][26]

### Proposed protocol and traffic budget

If the alternative is launched, use `/release.json`, served with **`Cache-Control: no-store`**, excluded from service-worker caches. Return `buildId`, `generation`, `scope` and `noticeRequired`. The scope binds the response to the authenticated rollout cohort and environment. `generation` increases for every publication action, **including rollback**; the build ID itself is opaque.

Poll every **300 seconds while visible** and on focus/visibility return with a **60-second minimum interval**. These are proposed values; no authoritative cross-product "typical" interval was established. At 1,000 continuously visible tabs, periodic polling produces **12,000 requests/hour**, averaging **3.3 requests/second**. A 1 KB response body adds approximately **12 MB/hour**, excluding headers, TLS and focus checks. The supplied session total is not a concurrent-tab count.

Use `BroadcastChannel` for same-origin, same-storage-partition metadata sharing. Do not broadcast user drafts. A `storage` event can be a fallback; a SharedWorker can centralise polling, but leader election and worker lifecycle management are disproportionate initially. BroadcastChannel alone does not eliminate duplicate polling. [25]

For canaries, the endpoint must report the build eligible for **this cohort**, not the globally newest deployment. Publish metadata only after assets are available. Coalesce hotfixes, reject older manifest generations arriving late, and clear a pending notice if a rollback makes the running build current again. On endpoint errors, keep the app usable, emit diagnostics and back off; never treat a failed request as an available update.

### React implementation sketch

The following is application code to adapt, not a claimed implementation from another product. `readWorkState()` must return trustworthy state from editors, uploads and live operations. The default policy is `noticeRequired: false` for ordinary compatible deployments.

```tsx
// Release identity is embedded at build time.
const RUNNING_BUILD = __BUILD_ID__;
const POLL_MS = 300_000;
const CHECK_COOLDOWN_MS = 60_000;
const USER_IDLE_MS = 120_000;

type Release = {
  buildId: string;
  generation: number; // publication order, including rollbacks
  scope: string;      // environment + authenticated rollout cohort
  noticeRequired: boolean;
};

function useReleaseNotice(scope: string) {
  const [release, setRelease] = React.useState<Release | null>(null);
  const [shown, setShown] = React.useState(false);
  const [dismissed, setDismissed] = React.useState(false);
  const lastInput = React.useRef(Date.now());
  const key = `vox:update-dismissed:${scope}:${RUNNING_BUILD}`;

  React.useEffect(() => {
    try { setDismissed(sessionStorage.getItem(key) === '1'); }
    catch { /* in-memory state still works */ }
  }, [key]);

  React.useEffect(() => {
    let stopped = false, inFlight = false, lastCheck = 0;
    let acceptedGeneration = -1;
    const channel = typeof BroadcastChannel === 'function'
      ? new BroadcastChannel(`vox:release:${scope}`) : null;

    const accept = (m: Release) => {
      if (stopped || m.scope !== scope ||
          typeof m.buildId !== 'string' ||
          !Number.isFinite(m.generation) ||
          m.generation < acceptedGeneration) return;
      acceptedGeneration = m.generation;
      setRelease(m);
    };
    if (channel) channel.onmessage = e => accept(e.data);

    const check = async () => {
      if (document.hidden || inFlight ||
          Date.now() - lastCheck < CHECK_COOLDOWN_MS) return;
      lastCheck = Date.now();
      inFlight = true;
      try {
        const response = await fetch('/release.json', {
          cache: 'no-store', credentials: 'same-origin'
        });
        if (!response.ok) return;
        const m: Release = await response.json();
        accept(m);
        if (!stopped && m.scope === scope) channel?.postMessage(m);
      } catch { /* record failure; do not refresh */ }
      finally { inFlight = false; }
    };
    const timer = window.setInterval(check, POLL_MS);
    document.addEventListener('visibilitychange', check);
    window.addEventListener('focus', check);
    void check();
    return () => {
      stopped = true;
      clearInterval(timer);
      document.removeEventListener('visibilitychange', check);
      window.removeEventListener('focus', check);
      channel?.close();
    };
  }, [scope]);

  React.useEffect(() => {
    const input = () => { lastInput.current = Date.now(); };
    const events = ['keydown', 'pointerdown', 'input', 'wheel', 'touchstart'];
    events.forEach(name => window.addEventListener(name, input, { passive: true }));
    const timer = window.setInterval(() => {
      const w = readWorkState();
      const pending = release?.noticeRequired &&
        release.buildId !== RUNNING_BUILD;
      if (!pending) { setShown(false); return; }
      if (dismissed || document.hidden || !w.known ||
          w.dirty || w.pendingWrites || w.uploading || w.recording ||
          w.liveSession || w.videoPlaying || w.presenting || w.immersive) return;
      if (w.atSafeTaskBoundary || Date.now() - lastInput.current >= USER_IDLE_MS) {
        setShown(true); // do not hide again merely because typing resumes
      }
    }, 1_000);
    return () => {
      clearInterval(timer);
      events.forEach(name => window.removeEventListener(name, input));
    };
  }, [release, dismissed]);

  const dismiss = () => {
    setDismissed(true);
    setShown(false);
    try { sessionStorage.setItem(key, '1'); } catch { /* optional storage */ }
  };
  const refresh = async () => {
    // Re-read state now; the user may have edited since display.
    if (await prepareSafeReload()) window.location.reload();
  };
  return { shown: shown && !dismissed, dismiss, refresh };
}
```

Production additions include manifest schema validation, request timeouts, scope-specific server responses, failure backoff and telemetry. The app shell should suppress the already-shown strip in immersive/offline states without losing its dismissal state. `prepareSafeReload()` must refuse active recordings/uploads and unknown safety, flush recoverable drafts, and report failures without silently reloading.

**Decision:** Keep release detection small and independent of task safety. Do not put polling on the critical route-navigation path, and do not build cross-tab leadership until measured load requires it.


## 8. Retain Old Assets Before Asking Users To Refresh

### Deployment skew is the underlying failure

Vite's documentation describes old running code attempting to import a chunk deleted by a later deployment. It offers a `vite:preloadError` handler and warns that HTML must revalidate rather than keep referencing obsolete assets. This closely matches the supplied Voxpopme mechanism. [10]

Vercel addresses a broader contract: framework-managed asset, navigation and server-action requests can be pinned to the initial deployment. Custom fetches are not automatically pinned. Netlify similarly describes clients identifying the deployment they expect so requests can be served against it. These are substantive prevention mechanisms, not notice patterns. [12][13]

The distinction matters. Keeping a JavaScript chunk available prevents a 404, but does not ensure that old client code understands a changed API response. Retention must be paired with backwards-compatible APIs or explicitly version-pinned backend behaviour. Vercel also documents a finite protection age and loss of protection when deployments are deleted. No finite retention policy guarantees that every indefinitely open tab will work forever. [13][12]

### Proposed deployment policy

Use release-qualified or content-hashed asset URLs, never overwrite bytes at an immutable URL, and retain the complete dependency graph of previous builds for an initial **7-day window**. Seven days is a Voxpopme starting recommendation based on the supplied hours-to-days usage, not an industry standard. Extend it if measured stale-tab ages exceed it; do not retain merely "the previous build" when several deploys can occur per day.

| Resource | Proposed policy | Reason and cost |
|---|---|---|
| Hashed JS/CSS/media assets | `Cache-Control: public, max-age=31536000, immutable` | Efficient reuse; additional origin storage for retained objects |
| HTML/app entry document | `Cache-Control: no-cache` | Revalidate before reuse; conditional-request cost |
| Release manifest | `Cache-Control: no-store` | Do not reuse stale release metadata; small repeated requests if enabled |
| Previous build graph | Retain at origin for 7 days initially | Works even when a CDN edge never cached an old chunk |
| APIs used by supported builds | Keep compatible or pin versions | Backend complexity, but avoids silent client/server contract failure |

MDN explicitly distinguishes `no-cache`, which permits storage but requires revalidation, from `no-store`, which prevents storage; its immutable-asset example uses a one-year maximum age. A long cache TTL is not a substitute for retaining the origin object. [40]

Do not preload and execute the **new** build's chunks inside the **old** runtime. At best, prefetching the new release warms a subsequent reload; it does not rewrite the old import graph. The Vite issue includes reports of incompatibility when old files resolve to new files with different exports. Removing hashes is therefore not a safe fix. [14]

### If a dismissed notice is followed by a chunk failure

The earlier notice must not change recovery entitlement or safety. Use the decided **"Reloading Voxpopme..."** path only when the reload is safe. If work is unpreserved or an operation is active, retain the page, offer save/copy/export through eagerly loaded UI, and recover once safe. Offline or unrelated network failures should not start a reload loop.

Limit automatic recovery to **one attempt per target build per tab within 10 minutes**, then stop and provide manual recovery/support. Validate the latest release before retrying; do not reload on every generic `TypeError`.

**Decision:** Retention is the first fix. A notice is an optional transition aid, never compensation for deleting assets still referenced by supported clients.


## 9. Draft Autosave Protects More Than Deployment Failures

### Figma's crash-recovery case

Figma's engineering account describes saving only changes made since disconnection rather than serialising and replacing the entire document. The pending changes already existed in its collaboration system; they were committed to disk using IndexedDB and later applied to the reopened document and uploaded. The documented outcome is preservation even when the tab closes. [20]

This was not merely a local-file feature. Long-lived offline changes can conflict with newer collaborative edits, so Figma introduced checkpoints before and after applying the recovered changes. The system is described as crash recovery, not long-term local storage. The lesson for Voxpopme is that restoration, ownership and merge rules are as important as writing a draft. [20]

### A proportionate Voxpopme preservation plan

The following techniques are recommendations for the stated workflows, not claims about existing Voxpopme functionality.

| Work item | Recommended persistence | Restoration requirement | Principal trade-off |
|---|---|---|---|
| Question set | Server draft plus IndexedDB pending edits | Study ID, user/tenant, revision and schema migration | Development and conflict handling; highest value |
| Report edits | Server draft plus local pending edits | Report ID, block IDs, version/conflict policy | Rich-text serialisation and merge complexity |
| Clip selections | Persist clip IDs and intended ordering | Validate permissions and whether clips still exist | Small payload; selections can become stale |
| Route, filters and scroll | Small per-tab `sessionStorage` snapshot | Restore only to a valid route after authentication | Convenience, not work-loss protection |
| Video playback | Clip ID and playback time | Resume once media is ready and seekable | Helpful continuity; not a durable edit |
| Upload or recording | Explicit operation state and resumable protocol where supported | Upload/session identifiers and actual resumption capability | Cannot be solved by serialising a React state object |

Start with question sets and report drafts. A proposed local policy is a **1-second debounce** with a **5-second maximum write delay** during continuous editing, plus flushing at explicit saves and visibility changes. These are implementation targets, not a zero-loss promise. The UI must show whether the latest revision is still pending.

Use server drafts as the durable cross-device source and IndexedDB as an offline/recovery supplement. Browser storage is best-effort by default, may be evicted, and can fail with quota errors. Test blocked storage, private browsing, large drafts and schema upgrades. Do not persist respondent video blobs or sensitive transcript material merely to preserve view state. [47]

`beforeunload` can warn about unsaved edits, but it is unreliable, especially on mobile, and the browser controls its wording. MDN recommends visibility changes as a more reliable saving signal and registering `beforeunload` only when needed. [3]

Miro's recovery feature is a useful contrast: hourly/session-end backups and 90-day version history help recover previous states, but can miss the latest work when network problems prevent backup. Recovery history and current-draft durability are different guarantees. [18]

**Decision:** Invest in preservation before reassuring copy. Bind local drafts to tenant and identity, clear acknowledged recovery data deliberately, and handle authentication expiry without exposing one user's draft to another.


## 10. A Polite Status Must Not Steal Focus Or Block Work

### Announce once, without demanding attention

Use a live region that exists before the message is inserted:

```html
<div id="release-status"
     role="status"
     aria-live="polite"
     aria-atomic="true"></div>
```

`role="status"` has implicit polite live behaviour and atomic announcement. W3C advises having the status container in place before the message occurs. Keep the visible Refresh and Not now buttons outside the live text container, and do not reinsert the message after every poll. [31]

Polaris demonstrates the useful semantic split: critical/warning banners use alert, while other banners use status. Atlassian warns that its assertive banner can be noisy. The actionable implication is not to inherit `role="alert"` from an offline-warning component for a nonurgent release. [23][9]

### WCAG 2.2 requirements and applicability

| Criterion | Relevant requirement | Application here |
|---|---|---|
| 4.1.3 Status Messages, AA | Status can be determined without receiving focus. [7] | Polite, programmatically exposed message |
| 2.1.1 Keyboard, A | Functionality operates through a keyboard interface. [44] | Native buttons; no mouse-only dismissal |
| 2.4.3 Focus Order, A | Sequential focus preserves meaning and operability. [39] | Insert controls in a logical header/content order |
| 2.4.7 Focus Visible, AA | Keyboard focus has a visible indicator. [41] | Visible, non-time-limited button focus |
| 2.4.11 Focus Not Obscured, AA | Focused components are not entirely hidden by author content. [45] | Do not overlay focused editor controls |
| 1.4.3 Contrast, AA | Ordinary text at least 4.5:1; large text 3:1. [33] | Test information-tone text and buttons |
| 1.4.11 Non-text Contrast, AA | Required UI/graphics at least 3:1 against adjacent colours. [33] | Test meaningful icons and control states |
| 1.4.10 Reflow, AA | Preserve content/functionality at 320 CSS px width, with specified exceptions. [33] | Wrap message and actions rather than truncate |
| 2.5.8 Target Size, AA | At least 24 by 24 CSS px, subject to exceptions. [33] | Proposed 44 px mobile targets exceed the minimum |
| 2.2.1 Timing Adjustable, A | Content-imposed time limits need adjustment/extension unless exempt. [33] | No forced-refresh countdown |
| 2.2.2 Pause, Stop, Hide, A | Addresses moving, blinking, scrolling and auto-updating visual information. [49] | Avoid persistent animation or repeatedly changing release text |
| 2.2.4 Interruptions, AAA | Users can postpone/suppress interruptions, except emergencies. [33] | Not now is helpful; do not mislabel this as an AA mandate |
| 2.3.3 Animation from Interactions, AAA | Nonessential interaction-triggered animation can be disabled. [43] | No animation; honour reduced-motion settings |

Do not move focus when the notice appears. If a user dismisses it while focus is on Not now, place focus on a stable, logically adjacent header control; otherwise leave focus untouched. Suppress the strip within modal/full-screen workflows rather than inserting it inside their focus sequence.

WCAG 3.3.4 covers specified consequential submissions or changes to stored user data, but its explanation does not require confirmation for every save or ordinary document edit. It should not be stretched into a universal rule that every refresh requires a confirmation dialog. [46]

For enterprise procurement, review actual accessibility commitments, SLAs, DPAs and incident terms. UK GDPR Article 32 explicitly addresses confidentiality, integrity, availability, resilience and restoration, with measures proportionate to risk and implementation cost. It does not prescribe a version banner. Applicable duties vary globally; the supplied brief does not establish Voxpopme's contractual liability. [48]

**Decision:** Make the optional notice politely discoverable and fully operable, not assertively announced or focus-stealing. Accessibility is another reason to reduce unnecessary messages.


## 11. Test The Release Boundary, Not Just The Banner

### Required production scenarios

| Scenario | Required behaviour | Risk owner / cost |
|---|---|---|
| Several tabs on different builds | Each compares its own running build; share manifest generations, not "all updated" state | Front end: avoid false clearing and repeated alerts |
| One tab already refreshed | Its current state must not force another tab to reload | User: preserve independent research tasks |
| Deploy during upload or recording | No automatic reload; finish, cancel safely or resume through a real supported protocol | Platform/operations: track activity explicitly |
| Deploy also expires authentication | Save recoverable local drafts before redirect where possible; restore only under the same identity/tenant | Security and UX: reconcile privacy with recovery |
| Faulty new build followed by rollback | Publish a new generation pointing to the approved older build; do not assume greater hash/version means newer | Release engineering: control cohort and metadata consistency |
| Client presentation or live interview | Suppress notices in explicit presentation/live modes | Product: visibility alone cannot identify external screen sharing |
| Offline and update states overlap | Offline wins the single notification slot; retain update metadata silently and refuse unsafe refresh | User: avoid contradictory "refresh" advice |
| Slow or intermittent connection | Keep the app usable; do not interpret a manifest timeout as a release or loop on chunk retries | Front end: distinguish connectivity from missing assets |
| Tab older than asset-retention window | Guarded recovery with draft restoration; do not imply indefinite compatibility | Platform: document finite support window |
| Storage unavailable or quota exceeded | Mark preservation as unavailable and do not claim changes are safely saved | UX/engineering: expose recovery limitations |

The priority policy follows the design-system guidance to avoid multiple competing banners and prefer the highest-priority message where combination is inappropriate. BroadcastChannel communication itself is limited to compatible same-origin storage partitions, so not every embedded or partitioned context can be treated as one tab group. [2][25]

### Public failure cases reveal the hidden work

In the Discourse case, the update notice persisted after refresh, browser changes, computer changes and logout. A deployment rebuild resolved the reported condition, while missing CSS was only a suggested cause. The failure was therefore not solved by asking the user more forcefully to refresh. [19]

For Voxpopme, that case argues for testing release-manifest/CDN consistency and missing-asset handling. A notice can become an endless symptom of an inconsistent deployment; repeatedly refreshing does not repair a wrongly published asset graph.

The Asana report supplies a different warning: a long summary with attachments triggered a reload-related error, and the Reload action reportedly did nothing, leaving the summary in draft. Staff directed the case to support rather than confirming a generic update-notice mechanism. This is a customer report, not evidence that Asana routinely loses work on deployments. [17]

The engineering implication is to keep recovery controls and draft export in eagerly loaded code. A missing lazy chunk must not also prevent the error boundary, saving path or recovery UI from rendering. Test missing JS, wrong MIME/HTML responses, failed API compatibility, stale manifests, auth redirects and a second chunk failure after reload.

There is no reliable general browser signal for "the user is presenting this tab through another application". Offer an explicit presentation suppression mode rather than claiming to detect every screen-sharing situation. This is a practical limitation to address in product design, not a reason to delay all detection.

**Decision:** Acceptance tests must cross deploy, task and authentication boundaries. The expensive risks are lost operations, loops and inconsistent state, not whether the banner is attractive.


## 12. Measure Restored Work And Repeated Exposure, Not Just Clicks

### Establish the correct baseline

Separate **all chunk failures**, **confirmed stale-build asset failures**, **at-risk sessions**, and **confirmed lost work**. Record running/eligible build IDs, asset URL/status, rollout cohort, task state, draft revision and recovery outcome. The supplied 2-3 count is a starting risk signal, not a measured loss rate.

| Measurement | Recommended event or denominator | Interpretation |
|---|---|---|
| Update exposure | Visible impression per session/tab/build | How much attention the alternative consumes |
| Refresh and dismissal | Actions per exposed tab; repeated impressions separately | Behaviour, not proof of benefit |
| Time to safe refresh | From first eligible detection to successful safe reload | Preserve task context; background time can distort it |
| Chunk errors | Confirmed stale asset failures per session and deployment | Direct architecture outcome |
| Draft restoration | Attempts, successful current-revision restores, conflicts and unrecoverable drafts | Primary work-safety outcome |
| Operations | Reloads during upload/recording; interrupted or resumed operations | Zero-tolerance safety failures for the pilot |
| Task completion | Completion, abandonment and repeat editing for exposed versus comparable tasks | Detect friction beyond refresh conversion |
| Support | Version-loop, lost-work and reload-related tickets with severity | Captures consequences outside telemetry |

Rising dismissal alone is not proof of harm: Not now is intended to be legitimate. More concerning combinations are repeated impressions, declining task completion, frequent immediate dismissal, accessibility complaints and no improvement in stale-session outcomes. W3C specifically cautions against making an application too chatty for screen-reader users. [7]

### Why a short A/B test will be underpowered

Using the supplied baseline, a conventional two-proportion planning calculation assumes independent sessions, an unchanged underlying rate, **95% two-sided significance**, **80% power**, equal allocation and a **50% relative reduction**. It yields:

| Baseline assumed | Approximate sessions per arm | Approximate total | Time at supplied 13,900 sessions per 21 days |
|---|---:|---:|---:|
| 2/13,900 | 327k | 655k | 2.7 years |
| 3/13,900 | 218k | 436k | 1.8 years |

These are approximate planning calculations, not a promised test duration. Sessions cluster within users and deployments; baseline uncertainty and rare events can materially change a formal design. Restricting enrolment to genuinely stale, active-work tabs could increase the event rate, but requires a new denominator.

Zero events after launch are not decisive. With zero in another 13,900 sessions, the rule-of-three one-sided 95% upper bound is approximately **0.0216%**, close to the original higher point estimate. Under an unchanged independent-event model, zero events in such a window has approximately **13.5%** probability at the lower baseline and **5.0%** at the higher one.

### A practical evaluation programme

Capture comparable pre-release metrics, then run scripted retained-asset and restoration tests across two builds, a hotfix and a rollback. Prototype-test the optional notice with **8 research users**, including keyboard and screen-reader workflows; that sample is for comprehension and task interference, not rare-event inference.

For a **30-day monitored rollout**, investigate every stale-build failure individually. Pause on any confirmed notice/recovery-caused lost draft, active-operation reload, repeated automatic-reload loop, or repeated impression contrary to the dismissal policy. Require current-draft restoration to pass the supported workflow test matrix before using reassuring copy.

**Decision:** The leading success criteria are fewer stale-asset failures and safe restoration. Refresh click-through is secondary and can rise even when the experience gets worse.


## Synthesis: Prevention First, Recovery Second, Notification Last

### Compare the mechanisms, not the logos

| Strategy and relevant evidence | Mechanism | Scope and time horizon | Trade-off / residual risk |
|---|---|---|---|
| Vercel/Netlify-style deployment protection | Keep client requests consistent with a deployment | Assets and supported server interactions during a finite retention window. [12][13] | Infrastructure/storage and API discipline; no automatic draft protection |
| Figma-style draft recovery | Persist pending changes locally and restore/merge | Work survives a crash/reopen in the documented design. [20] | Storage, identity and conflict complexity; not long-term archival storage |
| Qualtrics-style save/publish separation | Save edits independently of live publication | Protect researcher control over when changes reach respondents. [16] | Does not itself establish a front-end deployment policy |
| Miro-style history recovery | Periodic/session-end versions | Retrospective recovery, not necessarily the last unsaved moment. [18] | Can miss recent changes or network-failed backups |
| Guarded reactive reload | Recover when the old client actually cannot load | Affected navigation rather than all deployments; Vite documents the error hook. [10] | Safe only if current work and operations are protected |
| Non-blocking release notice | Ask the user to choose a refresh time | Only helps if seen, understood and acted on before failure | Attention and policy maintenance; does not save work or restore deleted files |
| Immediate service-worker activation | Replace the controlling worker without waiting | Existing and other active clients can be affected. [26] | Adds lifecycle complexity and is not an unsaved-work solution |

The non-obvious tension is that **the best update experience can be no update experience**. Retention removes the immediate need to act, while autosave reduces the consequences of an eventual restart. A banner makes most sense during a deliberately managed compatibility transition, not as a routine announcement of deployment activity.

The named products establish different layers of protection. Gmail's source establishes freshness when opening; Google Docs provides configured offline persistence; Slack documents drafts; Notion's documented offline feature is not browser support. These are not interchangeable guarantees. Linear, Jira and Dovetail remain unclassified for the requested current web-update UX rather than being assigned an invented precedent. [15][34][38][37]

Design systems also diverge: Atlassian's critical, assertive banner and Polaris's dismissible informational status are not the same strategy. The Asana, Discourse and Power Apps reports expose operational and ownership problems, but do not prove that update banners routinely improve outcomes. [9][23][17][19][21]

### Single recommended approach

**Do not ship a routine "new version available" notice now.** Retain every supported build's immutable asset graph for **7 days initially**, maintain compatible/version-pinned APIs, and add durable drafts first for question sets and reports. Extend retention if observed stale-tab ages require it.

- **Placement:** No routine update banner, toast or badge. Keep the offline warning for actual connectivity status.
- **Wording:** No routine release copy. At a safe confirmed chunk failure, use the decided **"Reloading Voxpopme..."** message. If reload is unsafe, use **"This page needs to refresh. Save your work first."** with the existing save/copy recovery path.
- **Dismissal:** No routine notice to dismiss. A recovery message must not hide the only path back to usable work.
- **Timing:** Do not refresh on build mismatch. Recover only at an actual failure and after current work is safely saved/restorable and active operations have ended.
- **Fallback:** One automatic attempt per target build per tab within **10 minutes**; then manual recovery and support. Earlier notice dismissal, if present in future, must never bypass these safety rules.

This puts the recurring cost on deployment and persistence systems rather than on researchers, and addresses the stated cause instead of merely warning about it.

### One alternative if that recommendation is rejected

Ship a **targeted, dismissible informational strip**, not a deploy-wide warning. Put it **immediately below the header**, in flow, with **48 px minimum height** and **16 px horizontal padding**; use an information tone, static icon and no animation. Say **"A new version of Voxpopme is available. Save your work, then refresh when ready."** with **Not now** and **Refresh**. Use stronger saved-work wording only when the current revision is genuinely restorable.

Detect through the scoped manifest every **5 visible minutes**, plus focus/visibility checks with a **60-second cooldown**. Display after a successful save and exit from editing, or **2 minutes without input** when work state is known and no protected activity is running. Suppress during offline, immersive, presentation, video, upload, recording and live-session states. Dismiss for this tab's loaded build, including subsequent compatible hotfixes; no timed snooze or repeated navigation reminders.

Keep the same guarded chunk-error fallback, and retain assets where feasible even with the notice. **A banner is not a substitute for either retention or autosave.**

## References

1. *Notifications – Carbon Design System*. https://v10.carbondesignsystem.com/patterns/notification-pattern
2. *Notification banner – GOV.UK Design System*. https://design-system.service.gov.uk/components/notification-banner
3. *Window: beforeunload event - Web APIs | MDN*. https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event
4. *Document: visibilitychange event - Web APIs | MDN*. https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilitychange_event
5. *Understanding Success Criterion 4.1.3: Status Messages | WAI | W3C*. https://www.w3.org/WAI/WCAG21/Understanding/status-messages.html
6. *Banners - Material Design*. https://m2.material.io/components/banners
7. *Understanding Success Criterion 4.1.3: Status Messages | WAI | W3C*. https://www.w3.org/WAI/WCAG22/Understanding/status-messages.html
8. *Overview - Designing messages - Atlassian Design*. https://atlassian.design/foundations/content/designing-messages
9. *Banner - Usage - Components - Atlassian Design*. https://atlassian.design/components/banner/usage
10. *vite/docs/guide/build.md at main · vitejs/vite · GitHub*. https://github.com/vitejs/vite/blob/main/docs/guide/build.md
11. *Notification | Carbon Design System*. https://preview.carbondesignsystem.com/building-blocks/core/components/notification/guidelines
12. *Skew Protection*. https://vercel.com/docs/skew-protection
13. *Introducing Netlify Skew Protection | Netlify*. https://www.netlify.com/blog/introducing-netlify-skew-protection
14. *TypeError: Failed to fetch dynamically imported module · Issue #11804 · vitejs/vite · GitHub*. https://github.com/vitejs/vite/issues/11804
15. *Use the latest version of Gmail in your browser - Gmail Help*. https://support.google.com/mail/answer/15049?hl=en
16. *Survey Publishing & Versions - Qualtrics*. https://www.qualtrics.com/support/survey-platform/survey-module/survey-publishing-versions/
17. *Getting a Reload notification every time I try to post my very long Summary Report - Closed - Asana Community*. https://forum.asana.com/t/getting-a-reload-notification-every-time-i-try-to-post-my-very-long-summary-report/112838
18. *Board history: versions – Miro Help Center*. https://help.miro.com/hc/en-us/articles/360021668819-Board-history-versions
19. *How do I get rid of "We've updated this site, please refresh..." message? - Support - Discourse Meta*. https://meta.discourse.org/t/how-do-i-get-rid-of-weve-updated-this-site-please-refresh-message/186083
20. *Behind the feature: the hidden challenges of autosave | Figma Blog*. https://www.figma.com/blog/behind-the-feature-autosave/
21. *Allow code apps to configure the "new version available" update banner (silent auto-update / suppression) · microsoft/PowerAppsCodeApps · Discussion #383 · GitHub*. https://github.com/microsoft/PowerAppsCodeApps/discussions/383
22. *Banner*. https://shopify.dev/docs/api/app-home/latest/web-components/feedback-and-status-indicators/banner
23. *Banner — Shopify Polaris React*. https://polaris.shopify.com/components/feedback-indicators/banner
24. [
"More Harm than Good? How Messages that Interrupt Can Make Us Vulnerabl" by Jeffrey L. Jenkins, Bonnie Anderson et al.
](https://scholarsarchive.byu.edu/facpub/1957/)
25. *Broadcast Channel API - Web APIs | MDN*. https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API
26. *ServiceWorkerGlobalScope: skipWaiting() method - Web APIs | MDN*. https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/skipWaiting
27. *Understanding perceptions: user responses to browser warning messages*. https://nrc-publications.canada.ca/eng/view/author/version?id=97c3a514-69a0-47fe-a454-f96cc9383e2f
28. *Page Visibility API - Web APIs | MDN*. https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API
29. *Tales of Software Updates: What users learn from updating software*. http://users.umiacs.umd.edu/~tudor/courses/ENEE657/Fall17/papers/Vaniea16.pdf
30. *The service worker lifecycle  |  Articles  |  web.dev*. https://web.dev/articles/service-worker-lifecycle
31. *ARIA22: Using role=status to present status messages | WAI | W3C*. https://www.w3.org/WAI/WCAG22/Techniques/aria/ARIA22.html
32. *Window: requestIdleCallback() method - Web APIs | MDN*. https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback
33. *Web Content Accessibility Guidelines (WCAG) 2.2*. https://www.w3.org/TR/WCAG22/
34. *Work on Google Docs, Sheets, & Slides offline - Computer - Google Docs Editors Help*. https://support.google.com/docs/answer/6388102?hl=en
35. *Getting started with docs*. https://docs.dovetail.com/help/docs/getting-started-with-docs
36. *What is a Banner UI Element? Definition & Design Usage – Baymard*. https://baymard.com/blog/banner-ui
37. *Use Notion pages offline | Notion Help – Notion Help Center*. https://www.notion.com/help/use-pages-offline
38. *Send and read messages | Slack*. https://slack.com/help/articles/201457107-Send-and-read-messages
39. *Understanding Success Criterion 2.4.3: Focus Order | WAI | W3C*. https://www.w3.org/WAI/WCAG22/Understanding/focus-order.html
40. *HTTP caching - HTTP | MDN*. https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Caching
41. *Understanding Success Criterion 2.4.7: Focus Visible | WAI | W3C*. https://www.w3.org/WAI/WCAG22/Understanding/focus-visible.html
42. *Understanding Success Criterion 2.2.4: Interruptions | WAI | W3C*. https://www.w3.org/WAI/WCAG22/Understanding/interruptions.html
43. *Understanding Success Criterion 2.3.3: Animation from Interactions | WAI | W3C*. https://www.w3.org/WAI/WCAG22/Understanding/animation-from-interactions.html
44. *Understanding Success Criterion 2.1.1: Keyboard | WAI | W3C*. https://www.w3.org/WAI/WCAG22/Understanding/keyboard.html
45. *Understanding Success Criterion 2.4.11: Focus Not Obscured (Minimum) | WAI | W3C*. https://www.w3.org/WAI/WCAG22/Understanding/focus-not-obscured-minimum.html
46. *Understanding Success Criterion 3.3.4: Error Prevention (Legal, Financial, Data) | WAI | W3C*. https://www.w3.org/WAI/WCAG22/Understanding/error-prevention-legal-financial-data.html
47. *Storage quotas and eviction criteria - Web APIs | MDN*. https://developer.mozilla.org/en-US/docs/Web/API/Storage_API/Storage_quotas_and_eviction_criteria
48. *Regulation (EU) 2016/679 of the European Parliament and of the Council of 27 April 2016 on the protection of natural persons with regard to the processing of personal data and on the free movement of such data (United Kingdom General Data Protection Regulation) (Text with EEA relevance)*. https://www.legislation.gov.uk/eur/2016/679/article/32
49. *Understanding Success Criterion 2.2.2: Pause, Stop, Hide | WAI | W3C*. https://www.w3.org/WAI/WCAG22/Understanding/pause-stop-hide.html
50. *Qualitative + Quantitative Research & Analytics Software*. https://www.qualtrics.com/en-au/strategy/research/qualitative-quantitative
51. *Diary Studies For Longitudinal UX Research | Dscout*. https://www.dscout.com/platform/methods/diary-studies
52. *Introducing Diary Studies | Outset*. https://outset.ai/resources/blog/diary-studies
53. *Alert Fatigue in User Interfaces - Nielsen Norman Group*. https://www.nngroup.com/videos/alert-fatigue-user-interfaces

