Redirect Chain & Loop Analysis
Issue No: 104
Category: HTML Head Tags
Issue type: Issue
Priority: Critical
Description
The crawler checks whether the page includes a <meta name="viewport" content="width=device-width, initial-scale=1"> tag inside the <head> element. This tag is required for correct mobile rendering and is a prerequisite for Google's mobile-friendliness evaluation under mobile-first indexing.
How do we capture it
-
Fetch the raw HTML response by sending an HTTP GET request to the target page URL and reading the full response body as raw text.
-
Isolate the
<head>section by locating content between the opening<head>and closing</head>tags in the raw HTML. Only inspect tags found within this range; a viewport tag placed outside<head>is treated as absent since browsers ignore it in that position. -
Search for a viewport meta tag within the
<head>content using a case-insensitive pattern match:- Match any
<meta>element where thenameattribute equalsviewport(case-insensitive, with or without quotes). - Example pattern:
<meta[^>]+name=["']?viewport["']?[^>]*>— also apply name-last ordering since some pages placecontentbeforename.
- Match any
-
Record tag presence:
- Set
has_viewport_meta = trueif at least one matching<meta name="viewport">element is found inside<head>. - Set
has_viewport_meta = falseif no matching element is found.
- Set
-
Extract the content attribute value from the first matched tag:
- Locate the
content="..."attribute within the matched tag string. - Strip surrounding quotes and store the raw value as
viewport_content. - If no tag is found, store
null.
- Locate the
-
Check for
width=device-width:- Perform a case-insensitive substring search of
viewport_contentforwidth=device-width. - Set
has_width_device_width = trueif found, otherwisefalse.
- Perform a case-insensitive substring search of
-
Check for
initial-scale=1:- Perform a case-insensitive substring search of
viewport_contentforinitial-scale=1. - Allow for optional whitespace around the
=sign. - Set
has_initial_scale_1 = trueif found, otherwisefalse.
- Perform a case-insensitive substring search of
-
Count all viewport meta tags inside
<head>:- Count every occurrence of
<meta name="viewport">within the isolated<head>content. - If the count is greater than 1, set
has_multiple_viewport_tags = true.
- Count every occurrence of
What to store
| Field | Type | Comment |
|---|---|---|
site_id | integer | FK → sites(id) |
page_url | text | The URL of the page inspected |
has_viewport_meta | boolean | Whether a <meta name="viewport"> tag was found inside <head> in the raw HTML |
viewport_content | text | The raw value of the content attribute from the first viewport meta tag; null if the tag is absent |
has_width_device_width | boolean | Whether the viewport content value contains width=device-width |
has_initial_scale_1 | boolean | Whether the viewport content value contains initial-scale=1 |
has_multiple_viewport_tags | boolean | Whether more than one <meta name="viewport"> tag is present inside <head> |
detected_at | timestamp | When this data was last captured during a crawl |
Condition for trigger
The following rules evaluate stored fields and produce diagnostics in the audit report.
-
Trigger Rule 1: Viewport Meta Tag Missing
- Target Field:
has_viewport_meta - Evaluation Logic:
has_viewport_meta = false - Severity: CRITICAL
- Diagnostic Message: "The page at
[page_url]is missing a<meta name='viewport'>tag inside<head>. Without this tag, mobile browsers render the page at a fixed desktop-equivalent width and scale it down, producing an unreadable zoomed-out layout. Google also uses this tag as a mobile-friendliness signal under mobile-first indexing. Add<meta name='viewport' content='width=device-width, initial-scale=1'>inside the<head>element."
- Target Field:
-
Trigger Rule 2: Viewport Tag Missing width=device-width
- Target Field:
has_width_device_width - Evaluation Logic:
has_viewport_meta = true AND has_width_device_width = false - Severity: CRITICAL
- Diagnostic Message: "The viewport meta tag on
[page_url]does not includewidth=device-width. The current content value is[viewport_content]. Without this directive the browser does not match the layout width to the device screen width. Update the viewport tag so that its content attribute includeswidth=device-width."
- Target Field:
-
Trigger Rule 3: Viewport Tag Missing initial-scale=1
- Target Field:
has_initial_scale_1 - Evaluation Logic:
has_viewport_meta = true AND has_initial_scale_1 = false - Severity: WARNING
- Diagnostic Message: "The viewport meta tag on
[page_url]does not includeinitial-scale=1. The current content value is[viewport_content]. Without this directive some browsers apply a non-standard zoom level on initial page load. Update the viewport tag to includeinitial-scale=1."
- Target Field:
-
Trigger Rule 4: Multiple Viewport Tags Detected
- Target Field:
has_multiple_viewport_tags - Evaluation Logic:
has_multiple_viewport_tags = true - Severity: WARNING
- Diagnostic Message: "More than one
<meta name='viewport'>tag was found in the<head>of[page_url]. Browsers typically apply only the last tag encountered, which may not be the intended configuration. Consolidate all viewport directives into a single tag with the correct content value."
- Target Field:
Sources
- Google — Mobile-First Indexing: https://developers.google.com/search/docs/crawling-indexing/mobile/mobile-sites-mobile-first-indexing
- Google — Mobile Usability Report: https://support.google.com/webmasters/answer/9063469
- MDN — Viewport meta tag: https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag
- W3C — CSS Device Adaptation (viewport meta): https://www.w3.org/TR/css-device-adapt-1/
- WHATWG — HTML Living Standard (meta element): https://html.spec.whatwg.org/multipage/semantics.html#standard-metadata-names
- Google Search Central — Mobile-Friendly Test: https://search.google.com/test/mobile-friendly
Long description
The viewport meta tag is an HTML directive placed inside the <head> element that instructs the browser how to scale and display the page on different screen sizes. Its canonical form is:
<meta name="viewport" content="width=device-width, initial-scale=1">
Before this tag was introduced, mobile browsers rendered pages at a fixed desktop-equivalent width (typically 980 px) and then scaled the entire layout down to fit the physical screen. This produced a zoomed-out, unreadable page that required pinch-to-zoom to interact with. The viewport meta tag addresses this by instructing the browser to match the layout width to the device screen width (width=device-width) and to start at a 1:1 zoom level (initial-scale=1).
Why it matters for SEO
Google completed the transition to mobile-first indexing for all sites in 2023. Googlebot now primarily crawls and evaluates the mobile version of a page. The presence of width=device-width in the viewport meta tag is one of the explicit signals evaluated by Google's mobile-friendliness pipeline. Pages that fail this check are flagged in Google Search Console under the Mobile Usability report and may receive lower scores for mobile-specific ranking factors. A missing or misconfigured viewport tag can prevent a page from being classified as mobile-friendly regardless of how the page visually renders.
Crawler capture notes
The XeoPix crawler inspects raw HTTP response bytes only. The <meta name="viewport"> tag must be present as static HTML in the server response to be detected. If the tag is injected by JavaScript after the page loads, the crawler will not detect it and will record has_viewport_meta = false. Sites using server-side rendering (SSR) return the tag in the initial HTML response and are correctly handled. Client-side-only rendering frameworks that inject the viewport tag via JavaScript after load cannot be verified by this crawler; the constraint applies equally to all JavaScript-injected head tags.
Common failures the crawler checks:
- The viewport meta tag is entirely absent from the page
<head>. - The viewport tag uses a fixed pixel width such as
width=1024instead ofwidth=device-width, causing the layout to ignore the device screen width. - The
initial-scaledirective is missing, causing some browsers to apply a non-standard zoom factor on initial load. - The viewport tag is present on the desktop template but absent from a separate mobile-specific template served at the same URL.
- Multiple conflicting
<meta name="viewport">tags exist inside<head>; browsers typically apply the last one encountered, which may differ from the intended configuration. - The viewport tag is placed outside
<head>(e.g. inside<body>), which causes browsers to ignore it.
How to Fix
-
Add the viewport meta tag if missing: place
<meta name="viewport" content="width=device-width, initial-scale=1">inside the<head>element of every page, as close to the top of<head>as practical, before any stylesheets or scripts that depend on viewport dimensions. -
Correct an invalid content value: if the tag is present but does not include
width=device-width, update thecontentattribute to include it. Remove any fixed-pixel width declarations such aswidth=980orwidth=1024. -
Add
initial-scale=1if absent: ifinitial-scaleis missing or set to a value other than 1, update the tag to includeinitial-scale=1alongsidewidth=device-width. -
Remove duplicate viewport tags: if more than one
<meta name="viewport">is present, consolidate them into a single tag with the correct and completecontentvalue. Ensure no template partials or layout fragments emit their own independent viewport tags. -
Confirm the tag is in the server response: verify using a raw HTTP request (e.g.
curl -s {url} | grep -i viewport) that the tag appears in the initial HTML before any JavaScript execution. If it is absent from the raw response but visible in a browser, the tag is being injected by JavaScript and must be moved to the server-rendered HTML.
Validation checklist
Before marking this issue resolved, confirm all of the following:
- A single
<meta name="viewport">tag is present inside<head>in the raw HTML response. - The
contentattribute value includeswidth=device-width. - The
contentattribute value includesinitial-scale=1. - No duplicate
<meta name="viewport">tags exist in<head>. - The tag is confirmed present in the raw HTTP response, not only after JavaScript execution.
- Google Search Console Mobile Usability report shows no "Viewport not configured" errors for the page.