Meta refresh must not auto-refresh under 20 hours in HTML
Last updated:
Related Guides
Do not use meta refresh with a delay under 20 hours
Pages must not auto-refresh or redirect using the meta refresh tag unless the delay is 20 hours or longer. This pattern interrupts users, resets reading and input focus, and can cause loss of work. Use server redirects or user-controlled updates instead.
Why It Matters
An automatic reload can throw users back to the top of the page. Screen reader users lose their place because the DOM is rebuilt and reading is interrupted.
Keyboard-only and motor-impaired users may be filling a form or navigating a menu when a refresh clears input or changes context.
People with cognitive and attention disabilities can be disoriented by unexpected movement or a sudden redirect without consent.
Common Causes
- Using
<meta http-equiv="refresh">for scheduled page reloads (e.g., every few seconds/minutes). - Using meta refresh to redirect to a new URL after site changes or maintenance.
- CMS or theme settings that add a timed refresh by default.
- Copying legacy snippets that include meta refresh without understanding the impact.
- Implementing inactivity timeouts via meta refresh instead of proper session handling.
How to Fix
- Remove meta refresh
- Search the head for
<meta http-equiv="refresh">. - Delete it, or set the delay to 20 hours (>= 72,000 seconds) as a last resort. Recommendation: remove or replace rather than extending the delay.
- Search the head for
- For redirects, use the server
- Configure HTTP 301/302 redirects on the server or CDN. This avoids client-side surprises and preserves assistive tech context.
- For updating data, use user-controlled scripts
- Replace auto-reload with JavaScript that updates specific regions.
- Provide controls to start/stop auto-refresh, pause/resume, and adjust the interval.
- Do not shift focus on update. Use
aria-liveregions for announcements when needed.
- For time limits, provide adjustment options
- Give users a way to turn off or adjust the timer, or extend it by at least 10x the default duration. Also allow users to continue without data loss.
- Communicate clearly
- If timing is essential, show a visible notice and controls to pause or extend. Ensure controls are keyboard-accessible and labeled.
How to Test
Keyboard check
- Confirm no meta refresh is present. If timed updates exist, ensure Pause/Stop/Adjust controls are reachable with Tab and operable with Enter/Space.
- Verify no unexpected focus shifts occur during updates.
Screen reader check
- With NVDA/JAWS/VoiceOver, confirm the page does not automatically reload or redirect.
- If live updates occur, ensure announcements are brief and the reading cursor is not hijacked.
Code check
- Inspect the head for
<meta http-equiv="refresh">. - If found, parse the content attribute. Fail if the delay is less than 72,000 seconds (20 hours), including values like "10", "300", or "5; url=/path".
Mobile/touch check
- Ensure any timing controls are visible, finger-accessible, and not obscured. Verify the page does not auto-reload.
Good Example
!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Orders Dashboard</title>
<!-- No meta refresh tag -->
</head>
<body>
<h1>Orders</h1>
<div id="updates" role="status" aria-live="polite">Last updated: never</div>
<label for="auto">Enable auto-refresh every 5 minutes</label>
<input type="checkbox" id="auto" />
<button type="button" id="pause" aria-pressed="false" disabled>Pause</button>
<button type="button" id="refresh-now">Refresh now</button>
<script>
const updates = document.getElementById('updates');
const auto = document.getElementById('auto');
const pauseBtn = document.getElementById('pause');
const refreshNow = document.getElementById('refresh-now');
let timer = null;
let paused = false;
function updateData() {
// Simulate fetching new data without reloading the page
updates.textContent = 'Last updated: ' + new Date().toLocaleTimeString();
}
function startAuto() {
timer = setInterval(() => { if (!paused) updateData(); }, 5 * 60 * 1000);
pauseBtn.disabled = false;
}
function stopAuto() {
clearInterval(timer);
timer = null;
paused = false;
pauseBtn.setAttribute('aria-pressed', 'false');
pauseBtn.disabled = true;
}
auto.addEventListener('change', (e) => {
e.target.checked ? startAuto() : stopAuto();
});
pauseBtn.addEventListener('click', () => {
paused = !paused;
pauseBtn.setAttribute('aria-pressed', String(paused));
});
refreshNow.addEventListener('click', updateData);
</script>
</body>
</html>Bad Example
!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Redirecting…</title>
<meta http-equiv="refresh" content="8; url=/dashboard">
</head>
<body>
<p>You will be redirected shortly.</p>
</body>
</html>Quick Checklist
- No
<meta http-equiv="refresh">with a delay below 20 hours (72,000s). - Use HTTP 301/302 for redirects; avoid client-side delayed redirects.
- Provide clear Pause/Stop/Adjust controls for any timed updates.
- Keep focus stable; do not move focus on update.
- Use
aria-livefor incremental content changes, not full page reloads. - Controls work with keyboard and are labeled for screen readers.
- Warn before timeouts and let users extend time without losing work.