Skip to main content

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

  1. Read the HTTP Content-Language response 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.
  2. Search for <meta http-equiv="content-language"> in the page <head>:

    • Extract the content attribute value.
    • Record meta_present and meta_value.
  3. 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.
  4. 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.
  5. Compare to the <html lang> attribute (cross-reference with issue-105 data):

    • Retrieve the lang_attribute value 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.
  6. Detect language mismatch against detected language:

    • If page language detection data is available (from issue-105), compare effective_value against detected_language.
    • If they differ with detection confidence ≥ 0.85, set is_language_mismatch = true.
  7. Flag deprecated http-equiv usage:

    • The <meta http-equiv="content-language"> form is deprecated in HTML5.
    • If meta_present = true, always set meta_is_deprecated = true and flag as a suggestion to use <html lang> and the HTTP header instead.

What to store

FieldTypeComment
site_idintegerFK → sites(id)
page_idintegerFK → pages(id)
meta_presentbooleanWhether <meta http-equiv="content-language"> exists in <head>
meta_valuetextThe content value of the meta tag; NULL if absent
http_header_valuetextThe raw Content-Language HTTP response header value; NULL if absent
effective_valuetextThe resolved language value (HTTP header takes precedence over meta)
is_valid_bcp47booleanWhether the effective value is a valid BCP 47 language tag
html_lang_attributetextValue of <html lang> for cross-reference (from issue-105)
has_conflict_with_html_langbooleanWhether effective value primary language differs from html lang primary language
detected_languagetextDetected language code from page text content
detection_confidencenumericConfidence of language detection (0.0–1.0)
is_language_mismatchbooleanWhether effective value differs from detected language (confidence ≥ 0.85)
meta_is_deprecatedbooleanWhether <meta http-equiv="content-language"> is used (always deprecated in HTML5)
checked_attimestampWhen 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-Language header or meta equivalent was found on this page of a multilingual site. Declare the document language via the HTTP Content-Language response header to complement the <html lang> attribute."
  • 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-Language value [effective_value] is not a valid BCP 47 language tag. Use a registered IANA primary language subtag (e.g. en, fr, de)."
  • 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-Language value ([effective_value]) conflicts with the <html lang> attribute ([html_lang_attribute]). Align both to the same primary language code to avoid contradictory language signals."
  • 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."
  • Trigger Rule 5: Deprecated http-equiv Meta 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 the Content-Language value as an HTTP response header instead, and use <html lang=\"[language]\"> for the in-document language declaration."

Sources

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:

SignalLocationAuthoritySEO Scope
HTTP Content-Language headerResponse headerHigh (server-level)Per-request
<html lang="xx">In-document attributeHigh (definitive for HTML)Per-page
<meta http-equiv="content-language">In <head> HTMLDeprecated in HTML5Per-page
hreflang annotations<link> tags or sitemapsHigh (explicit alternate mapping)Cross-page

Current best practice (HTML5 era)

The W3C and Google both recommend:

  1. Use <html lang="xx"> as the primary in-document language declaration.
  2. Use the HTTP Content-Language response header for server-level language declaration.
  3. 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.
  4. 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-LanguageContent-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: en for 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-Language header matches the server's default locale, not the page's actual content language.
  • No Content-Language signal at all on a multilingual site that relies solely on hreflang.

How to Fix

  1. Add Content-Language as an HTTP response header via the web server:

    • Apache: Header always set Content-Language "en" in .htaccess or virtual host config.
    • Nginx: add_header Content-Language "en"; in the server block.
    • For multilingual sites, dynamically set the header value per language variant.
  2. Remove deprecated <meta http-equiv="content-language"> from all page templates.

    • Replace with the correct <html lang="xx"> attribute (see Issue 105).
  3. Align HTTP header and <html lang> attribute:

    • Both should declare the same primary language tag.
    • The HTTP header may omit the region (en not en-US) since it is a hint, not a precise locale.
  4. For multilingual CMS setups, ensure the language routing layer (per-language subdomain, subdirectory, or URL parameter) sets the Content-Language header dynamically based on the active language.

  5. Verify with curl -I https://example.com/page and check for the Content-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-Language to 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:

  1. Its own canonical URL (<link rel="canonical"> pointing to itself, not the default language).
  2. A correct <html lang> attribute.
  3. A consistent Content-Language HTTP header matching the lang attribute.
  4. 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 a Content-Language: response header.
  • The header value is a valid BCP 47 language tag (e.g. en, fr, de).
  • The Content-Language header 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.