Content-Language Meta or HTTP Header Missing or Invalid
Issue No: 110
Category: Html Head Tags
Issue type: Warning
Priority: Important
Description
The Content-Language signal — declared either as an HTTP response header (Content-Language: en) or as an HTML meta equivalent (<meta http-equiv="content-language" content="en">) — informs clients of the natural language of the document. When missing on multilingual sites, it weakens language targeting signals. When it conflicts with <html lang="xx">, it creates contradictory declarations that can confuse search engine language classification.
How do we capture it
-
Read the HTTP
Content-Languageresponse header from the crawl response.- Record the raw header value.
- Parse the language tag(s) — the header may contain a comma-separated list for multi-language documents.
-
Search for
<meta http-equiv="content-language">in the page<head>:- Extract the
contentattribute value. - Record
meta_presentandmeta_value.
- Extract the
-
Determine the effective value:
- HTTP response headers override HTML meta equivalents. If both are present,
effective_value = http_header_value. - If only the meta is present,
effective_value = meta_value. - If neither is present,
effective_value = NULL.
- HTTP response headers override HTML meta equivalents. If both are present,
-
Validate the effective value against BCP 47:
- The language tag must be a valid IETF BCP 47 tag (e.g.
en,en-US,fr). - Language-only tags (no region) are preferred in headers; flag region-qualified tags as informational.
- Flag invalid tags that are not in the IANA Language Subtag Registry.
- The language tag must be a valid IETF BCP 47 tag (e.g.
-
Compare to the
<html lang>attribute (cross-reference with issue-105 data):- Retrieve the
lang_attributevalue stored from the page's lang attribute check. - Extract the primary language subtag from each (ignore region differences).
- If the primary language subtags differ, set
has_conflict_with_html_lang = true.
- Retrieve the
-
Detect language mismatch against detected language:
- If page language detection data is available (from issue-105), compare
effective_valueagainstdetected_language. - If they differ with detection confidence ≥ 0.85, set
is_language_mismatch = true.
- If page language detection data is available (from issue-105), compare
-
Flag deprecated
http-equivusage:- The
<meta http-equiv="content-language">form is deprecated in HTML5. - If
meta_present = true, always setmeta_is_deprecated = trueand flag as a suggestion to use<html lang>and the HTTP header instead.
- The
What to store
| Field | Type | Comment |
|---|---|---|
site_id | integer | FK → sites(id) |
page_id | integer | FK → pages(id) |
meta_present | boolean | Whether <meta http-equiv="content-language"> exists in <head> |
meta_value | text | The content value of the meta tag; NULL if absent |
http_header_value | text | The raw Content-Language HTTP response header value; NULL if absent |
effective_value | text | The resolved language value (HTTP header takes precedence over meta) |
is_valid_bcp47 | boolean | Whether the effective value is a valid BCP 47 language tag |
html_lang_attribute | text | Value of <html lang> for cross-reference (from issue-105) |
has_conflict_with_html_lang | boolean | Whether effective value primary language differs from html lang primary language |
detected_language | text | Detected language code from page text content |
detection_confidence | numeric | Confidence of language detection (0.0–1.0) |
is_language_mismatch | boolean | Whether effective value differs from detected language (confidence ≥ 0.85) |
meta_is_deprecated | boolean | Whether <meta http-equiv="content-language"> is used (always deprecated in HTML5) |
checked_at | timestamp | When this check was last performed |
Condition for trigger
The following rules evaluate stored fields and produce diagnostics in the audit report.
-
Trigger Rule 1: Missing Content-Language on Multilingual Site
- Target Field:
effective_value - Evaluation Logic:
effective_value IS NULL AND site_is_multilingual = true - Severity: WARNING
- Diagnostic Message: "No
Content-Languageheader or meta equivalent was found on this page of a multilingual site. Declare the document language via the HTTPContent-Languageresponse header to complement the<html lang>attribute."
- Target Field:
-
Trigger Rule 2: Invalid BCP 47 Language Tag
- Target Field:
is_valid_bcp47 - Evaluation Logic:
effective_value IS NOT NULL AND is_valid_bcp47 = false - Severity: WARNING
- Diagnostic Message: "The
Content-Languagevalue[effective_value]is not a valid BCP 47 language tag. Use a registered IANA primary language subtag (e.g.en,fr,de)."
- Target Field:
-
Trigger Rule 3: Conflicts with
<html lang>Attribute- Target Field:
has_conflict_with_html_lang - Evaluation Logic:
has_conflict_with_html_lang = true - Severity: WARNING
- Diagnostic Message: "The
Content-Languagevalue ([effective_value]) conflicts with the<html lang>attribute ([html_lang_attribute]). Align both to the same primary language code to avoid contradictory language signals."
- Target Field:
-
Trigger Rule 4: Language Mismatch (Detected vs Declared)
- Target Field:
is_language_mismatch - Evaluation Logic:
is_language_mismatch = true AND detection_confidence >= 0.85 - Severity: CRITICAL
- Diagnostic Message: "The declared
Content-Language([effective_value]) does not match the detected page language ([detected_language], confidence[detection_confidence]). Update the declaration to match the actual content language."
- Target Field:
-
Trigger Rule 5: Deprecated
http-equivMeta Tag in Use- Target Field:
meta_is_deprecated - Evaluation Logic:
meta_is_deprecated = true - Severity: SUGGESTION
- Diagnostic Message: "The
<meta http-equiv=\"content-language\">tag is deprecated in HTML5. Serve theContent-Languagevalue as an HTTP response header instead, and use<html lang=\"[language]\">for the in-document language declaration."
- Target Field:
Sources
- W3C — Content-Language: https://www.w3.org/International/questions/qa-http-and-language
- MDN — Content-Language HTTP Header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Language
- Google — International SEO Basics: https://developers.google.com/search/docs/specialty/international
- HTML Living Standard —
meta http-equiv: https://html.spec.whatwg.org/multipage/semantics.html#pragma-directives - IETF BCP 47: https://www.rfc-editor.org/rfc/rfc5646
- W3C I18n — Choosing language tags: https://www.w3.org/International/questions/qa-choosing-language-tags
Long description
Content-Language is an HTTP-level language declaration that tells clients the intended natural language audience for a response. It is distinct from, but related to, three other language signals:
| Signal | Location | Authority | SEO Scope |
|---|---|---|---|
HTTP Content-Language header | Response header | High (server-level) | Per-request |
<html lang="xx"> | In-document attribute | High (definitive for HTML) | Per-page |
<meta http-equiv="content-language"> | In <head> HTML | Deprecated in HTML5 | Per-page |
hreflang annotations | <link> tags or sitemaps | High (explicit alternate mapping) | Cross-page |
Current best practice (HTML5 era)
The W3C and Google both recommend:
- Use
<html lang="xx">as the primary in-document language declaration. - Use the HTTP
Content-Languageresponse header for server-level language declaration. - Do NOT use
<meta http-equiv="content-language">— it is deprecated in HTML5 and has no effect in modern browsers. It is a legacy technique from HTML 4.01. - Use hreflang annotations for explicit language/region alternate mapping across pages.
The <meta http-equiv="content-language"> form is flagged as deprecated not because it causes active harm, but because it creates a maintenance burden (a third place to keep language declarations in sync) with no modern benefit.
When Content-Language matters
For single-language sites, Content-Language is largely redundant if <html lang> is correct. Its value increases for:
- Multilingual sites where different URLs serve different languages — the HTTP header provides a server-level hint that does not depend on the HTML parser reading the
<html>element. - APIs and non-HTML resources (PDFs, JSON responses) where there is no
<html lang>attribute — the HTTP header is the only language declaration available. - CDN and proxy scenarios where language-based content negotiation (
Accept-Language→Content-Language) is in use.
Conflict scenarios
If Content-Language: fr is set at the server level (e.g. as a global Apache AddDefaultCharset equivalent for language) but the page serves English content with <html lang="en">, search engines and quality tools receive contradictory signals. Google resolves this by favouring the <html lang> attribute, but the conflict still flags as a quality issue in audits.
Common failure patterns:
- Server sends a global
Content-Language: enfor all pages on a multilingual site, even when individual pages are in French, Spanish, or German. <meta http-equiv="content-language">was added years ago and never removed after migration to HTML5.Content-Languageheader matches the server's default locale, not the page's actual content language.- No
Content-Languagesignal at all on a multilingual site that relies solely on hreflang.
How to Fix
-
Add
Content-Languageas an HTTP response header via the web server:- Apache:
Header always set Content-Language "en"in.htaccessor virtual host config. - Nginx:
add_header Content-Language "en";in the server block. - For multilingual sites, dynamically set the header value per language variant.
- Apache:
-
Remove deprecated
<meta http-equiv="content-language">from all page templates.- Replace with the correct
<html lang="xx">attribute (see Issue 105).
- Replace with the correct
-
Align HTTP header and
<html lang>attribute:- Both should declare the same primary language tag.
- The HTTP header may omit the region (
ennoten-US) since it is a hint, not a precise locale.
-
For multilingual CMS setups, ensure the language routing layer (per-language subdomain, subdirectory, or URL parameter) sets the
Content-Languageheader dynamically based on the active language. -
Verify with
curl -I https://example.com/pageand check for theContent-Language:response header in the output.
Additional technical notes
Content-Language in non-HTML contexts
The HTTP Content-Language header is not limited to HTML documents. It is equally relevant for:
- PDF documents served via HTTP — the only language declaration available since PDFs do not have
<html lang>. - JSON API responses where the content is localised text.
- RSS/Atom feeds — search engines and feed readers use
Content-Languageto classify feed content. - Downloadable office documents (Word, Excel) when served with
Content-Disposition: attachment.
For these non-HTML resource types, the HTTP header is the only available language signal, and its absence prevents correct language-based classification.
Accept-Language and content negotiation
Some servers implement HTTP content negotiation using Accept-Language (the browser's preferred language header) to select the appropriate content variant. When this is in use, the server should set the Content-Language response header to confirm which language variant was selected. This tells intermediate caches (CDNs, proxies) that the response content varies by language and they must not serve the same cached response to users requesting different languages.
The Vary: Accept-Language response header should accompany this pattern so caches key responses by language.
Interaction with the Canonical URL
For multilingual sites using hreflang, each language variant should have:
- Its own canonical URL (
<link rel="canonical">pointing to itself, not the default language). - A correct
<html lang>attribute. - A consistent
Content-LanguageHTTP header matching thelangattribute. - hreflang annotations pointing to the other language variants.
If the Content-Language header for the French version says fr but the <html lang> says en, Google may classify the French URL as an English page and exclude it from French-language search results entirely.
Validation checklist
Before marking this issue resolved, confirm all of the following:
-
curl -I {url}output includes aContent-Language:response header. - The header value is a valid BCP 47 language tag (e.g.
en,fr,de). - The
Content-Languageheader primary language matches the<html lang>primary language. - No
<meta http-equiv="content-language">tag remains in the page<head>. - For multilingual sites, the header value changes dynamically per language variant.