You need to move a page, but the platform will not let you touch the server. There is no .htaccess, no redirect manager, no access to response headers. So you do what thousands of site owners do: paste a <meta http-equiv="refresh"> tag into the old page, or add a line of JavaScript that sends visitors on their way. It works in your browser. The question is whether it works for Google.
The short answer is “usually, with conditions”. Google does follow both kinds of client-side redirect, but it treats them as weaker and less reliable than a server response, and the details matter: a zero-second meta refresh and a three-second one are interpreted differently, and a JavaScript redirect only exists if rendering succeeds. Get those details wrong during a migration and you can split signals between old and new URLs for months.
This guide explains exactly how Google processes each type, which platforms force you into them, how to test what Googlebot actually sees, and how to replace client-side redirects with proper server-side ones when you get the chance.
Where client-side redirects sit in Google’s reliability ranking
A server-side redirect happens before any HTML is delivered: the server answers with a 3xx status code and a Location header, and the browser or crawler goes straight to the new URL. A client-side redirect happens after a normal 200 response: the page loads (at least partly), and an instruction inside it moves the visitor. Google’s redirect documentation lists the methods in order of how reliably it can interpret them, with server-side first.
| Method | Where it runs | Google’s interpretation | Reliability |
|---|---|---|---|
| HTTP 301 / 308 | Server | Permanent | Highest |
| HTTP 302 / 303 / 307 | Server | Temporary | Highest |
Meta refresh, 0 seconds (HTML or HTTP Refresh header) | Browser after HTML parse | Permanent | Good fallback |
| Meta refresh, delay above 0 | Browser after a wait | Temporary | Good fallback, weaker intent |
JavaScript location redirect | Browser after script execution | Permanent | Only if rendering succeeds |
| “Crypto” redirect (a visible link explaining the move) | User clicks | May or may not be treated as a redirect | Last resort |
For the server-side half of this table, our explainers on 301 versus 302 redirects and writing redirects in .htaccess cover the syntax. The rest of this article is about the bottom four rows.
How Googlebot reads a meta refresh: zero seconds versus a delay
A meta refresh is an instruction in the page’s <head>:
<meta http-equiv="refresh" content="0; url=https://www.example.com/new-page/">
The first number is the delay in seconds. The same instruction can also be sent as an HTTP response header (Refresh: 0; url=https://www.example.com/new-page/) if you can set headers but not status codes, which some edge and serverless setups allow. Google is explicit about how the delay changes the meaning:
“Google Search interprets instant meta refresh redirects as permanent redirects.”
— Google Search Central, Redirects and Google Search
A delayed refresh, one that fires after a number of seconds set by the site owner, is interpreted as temporary. That has a practical consequence. With a temporary redirect, Google tends to keep the source URL as the canonical one shown in results. So a “You are being redirected in 5 seconds” page, a pattern still common on old intranets and university sites, is telling Google the old URL is the one that matters.
- Use
content="0; url=..."for any move you want treated as permanent. - Use an absolute URL in the
url=part to avoid ambiguity with relative paths. - Place the tag as early in the
<head>as possible, before scripts and stylesheets. - Add a
rel="canonical"link to the target as a supporting signal. Google’s canonicalisation guide notes that combining methods strengthens the signal. - Include a plain visible link to the new URL in the body for users whose browsers block refreshes.
Why a JavaScript redirect only exists after rendering
A JavaScript redirect sets window.location:
<script>
window.location.replace("https://www.example.com/new-page/");
</script>
Google handles JavaScript in three phases: crawling, rendering and indexing. When Googlebot first fetches the URL, it gets a 200 response and HTML that contains no redirect at all, only a script. The redirect is discovered later, when the page goes through Google’s Web Rendering Service and the script runs in headless Chromium. Google’s JavaScript SEO basics page notes that pages can wait in the render queue for a few seconds or longer. And rendering is not guaranteed:
“While Google attempts to render every URL Googlebot crawled, rendering may fail for various reasons.”
— Google Search Central, Redirects and Google Search
Google’s own advice is to use JavaScript redirects only when neither server-side nor meta refresh redirects are possible. Three practical risks follow from the rendering dependency:
- Timing. The redirect is seen later than a server or meta redirect, so during a migration the old URL can stay indexed longer.
- Script blocking. If the redirect script, or a file it depends on, is blocked by robots.txt or fails to load, the redirect never fires for Googlebot.
- Other crawlers. Many crawlers, including some AI and social preview bots, do not execute JavaScript, so they index the empty source page instead.
Single-page applications also use JavaScript to show “not found” states. Google’s JavaScript guide suggests either redirecting with JavaScript to a URL that returns a real 404 status, or adding a noindex robots tag via JavaScript, to avoid soft 404s. Our wider JavaScript SEO guide and the release checklist in SEO for developers go deeper on routing.
One more rule for JavaScript sites: navigation itself must use real links. Google states that it can only discover links that are <a> elements with an href. A button with an onclick that changes window.location is effectively a JavaScript redirect triggered by a click, and Google may never follow it.
The accessibility cost of timed refreshes
Delayed meta refreshes are not only an SEO problem. The W3C’s Web Content Accessibility Guidelines list using meta refresh with a time limit as a failure technique (F41) for several success criteria, because an unexpected reload or redirect can send a screen reader back to the top of the page or move someone before they have finished reading.
“Content developers should avoid periodic refresh and allow users to choose when they want the latest information.”
— W3C Web Accessibility Initiative, Technique F41: Failure due to using meta refresh
The F41 test procedure flags refresh values between 1 and 72,000 seconds, so an instant redirect with a value of 0 does not trigger the failure. That lines up neatly with Google’s preference: if you must use a meta refresh, make it instant.
Platforms that push you towards client-side redirects
Most people who use meta refresh or JavaScript redirects do so because of their hosting, not by choice. Here is how common setups compare.
| Platform or setup | Server-side redirects available? | Typical fallback | What to do |
|---|---|---|---|
| GitHub Pages | No server config files | jekyll-redirect-from plugin generating redirect pages | Accept the plugin for small moves; front with a CDN or move host for migrations |
| Netlify | Yes: _redirects file or netlify.toml | None needed | Write 301 rules; order matters |
| Hosted CMSs (Shopify, Wix, Squarespace, Webflow) | Yes, via built-in redirect managers | None needed | Use the platform’s redirect settings rather than theme code |
| Object storage static hosting (for example S3 buckets) | Limited without a CDN | Meta refresh HTML stubs | Add redirect rules at the CDN layer |
| Single-page app on a static host | Depends on host | Router-level JavaScript redirect | Move redirects to the host or edge config |
| Legacy CMS without plugin access | Rarely | Meta refresh in page template | Edge redirects via CDN worker |
GitHub’s documentation explains that GitHub Pages does not allow server configuration files for security reasons and supports redirects through the jekyll-redirect-from plugin, where you list old paths in a page’s redirect_from front matter. Netlify, by contrast, processes rules from a plain-text _redirects file and defaults to 301 for rules in netlify.toml. Rule order matters on Netlify:
“The redirects engine will process the first matching rule it finds, reading from top to bottom.”
— Netlify Docs, Redirects and rewrites
The edge option is often the cleanest escape hatch. A CDN worker can answer requests for old URLs with a 301 before they ever reach a host that cannot do it. Our article on edge SEO explains how that works, and whether your CDN speaks HTTP/2 or HTTP/3 to visitors is covered in our guide to web protocols and SEO.
Testing exactly what Googlebot sees on a redirecting URL
A redirect that works in your browser can be invisible to a crawler, so test at three levels.
- Check the raw HTTP response. Run
curl -I https://www.example.com/old-page/. A server-side redirect showsHTTP/2 301(or 1.1) and alocation:header. A client-side redirect shows200, which is your cue to look inside the HTML. - Read the source, not the DOM. Use View Source (not DevTools Elements) to confirm a meta refresh is in the original
<head>, with a zero delay and an absolute URL. - Run the URL Inspection live test in Search Console. The “View tested page” panel shows the rendered HTML, a screenshot, the HTTP response and JavaScript console messages. Google’s help page notes that the live test follows redirects but does not say it did so or show the final URL, so compare the screenshot and rendered HTML with what you expect from the target page.
- Crawl the redirect list. Use a crawler in both text-only and JavaScript-rendering modes, or a short script such as the bulk checker in our Python for SEO guide, to list every old URL with its status code and final destination.
- Watch the index over the following weeks. In the Page indexing report, old URLs should move into “Page with redirect” as Google processes them. Persistent “Indexed” status for old URLs means the redirect is not being picked up.
| What you see | Likely redirect type | What it means for Google |
|---|---|---|
curl -I shows 301 or 308 with a location header | Server-side permanent | Strongest signal; nothing more to do |
curl -I shows 200; source has content="0; url=..." | Instant meta refresh | Treated as permanent once the HTML is processed |
200; source has content="5; url=..." | Delayed meta refresh | Treated as temporary; old URL may stay canonical |
| 200; no refresh in source, but the live test screenshot shows the new page | JavaScript redirect | Works only after rendering; check console errors |
| 200; live test screenshot shows the old page | Redirect not firing for Googlebot | Blocked script, runtime error or user-interaction trigger |
Also look for chains. A meta refresh that lands on a URL with a JavaScript redirect that lands on a 301 is three hops of increasing fragility. See our guide to finding and fixing redirect chains.
A worked example: moving 120 documentation pages off GitHub Pages
This is a hypothetical scenario with illustrative numbers. A software company hosts 120 documentation pages on GitHub Pages and is restructuring the docs into a new URL scheme on the same domain.
- Option A: stay on GitHub Pages. Add
redirect_fromentries to each of the 120 new pages. Every old URL now returns a 200 with a client-side redirect page. Google should treat instant refreshes as permanent, but every hop depends on Google reprocessing the HTML. - Option B: put a CDN in front. Map the 120 old paths to new paths as 301 rules at the edge. Old URLs never reach GitHub Pages at all.
- Option C: move hosting to a platform with redirect files. Export the 120 mappings into a
_redirectsfile, one line each, with the most specific rules first.
If the team monitors the Page indexing report weekly, a reasonable success test is that the count of old URLs still listed as indexed falls steadily and new URLs pick up the impressions in the Performance report. Whichever option is chosen, the mapping spreadsheet (old URL, new URL, status code, tested date) is the asset that matters, because it lets you switch from option A to B later without re-deciding every mapping.
Migrating from client-side to server-side redirects without losing signals
When you finally get server access, or move to a better host, swap your fallback redirects for real ones in this order:
- Inventory every client-side redirect. Search the codebase and templates for
http-equiv="refresh",window.location,location.replaceand router-level redirect config. Crawl the site to catch any you missed. - Resolve to final destinations. If A refreshes to B and B redirects to C, the new rule is A to C. Do not recreate chains.
- Write server or edge rules as 301 or 308 for permanent moves.
- Deploy and test with curl before removing anything. The server rule will take precedence because it fires before HTML is served.
- Delete the stub pages and scripts so no one reintroduces them, and update internal links to point straight at final URLs.
- Update the XML sitemap to list only final URLs.
- Monitor for 4–8 weeks in the Page indexing and Crawl Stats reports.
If this is part of a domain or platform move, use our full website migration SEO guide, and if you are deleting rather than moving content, our guide to removing pages from Google explains which status codes to use instead.
Questions developers and marketers ask about HTML and JavaScript redirects
Does a meta refresh redirect pass PageRank like a 301?
Google says it interprets an instant (zero-second) meta refresh as a permanent redirect, the same category as a 301 or 308. Google does not publish a separate rule for link value, but in its model a permanent redirect signals that the target should become canonical. A server-side 301 remains the more reliable signal.
Is a five-second meta refresh treated as a 301?
No. Google interprets meta refresh redirects with a delay greater than zero as temporary redirects, so the source URL is more likely to stay the one shown in search results. If you want the target indexed, use a zero-second refresh at minimum.
Do Bing and other search engines follow JavaScript redirects?
Google documents its own behaviour; other engines and many AI crawlers render JavaScript less, or not at all. That is why Google ranks JavaScript redirects below meta refresh and server-side redirects: the less rendering a crawler does, the more likely it is to miss the redirect.
Can I combine a meta refresh, a JavaScript redirect and a canonical tag?
Yes, and on static hosts this is a sensible belt-and-braces setup: a zero-second meta refresh in the head, a canonical tag pointing to the target and a visible link. Make sure every signal points to the same final URL, because conflicting signals weaken all of them.
How long should I keep client-side redirect pages after moving to 301s?
Remove them once the server-side rules are live, because the server responds before the HTML is ever served. Keep the old URLs redirecting for at least a year, and longer if they still receive links or traffic.
Replacing your fallback redirects with real ones
Client-side redirects are a legitimate fallback, and Google has documented how it treats them. An instant meta refresh is read as permanent; a delayed one as temporary; a JavaScript redirect works only when rendering does. If you are stuck with them, make them instant, absolute, supported by a canonical tag and a visible link, and test them in URL Inspection. Then plan the move to server or edge redirects, because that is the only setup every crawler understands.
If you are planning a migration or untangling years of mixed redirects, our technical SEO specialists can map, implement and monitor the changes. Get a free quote and send us your redirect list.
Further reading on meta refresh redirect
- SEO for Developers: What Engineers Need to Know Before Shipping
- Large-Site SEO: Managing Crawling and Templates on 100,000+ Page Websites
- Python for SEO: Beginner Scripts That Save Hours
Sources for this meta refresh and JavaScript redirect guide
- Google Search Central: Redirects and Google Search
- Google Search Central: Understand JavaScript SEO basics
- W3C WAI: Technique F41, failure due to using meta refresh
- Netlify Docs: Redirects and rewrites
- GitHub Docs: Redirects on GitHub Pages (Enterprise Server 2.14)
- Search Console Help: URL Inspection tool
- Google Search Central: How to specify a canonical URL
- Google Search Central: Make your links crawlable




