A missing or late charset declaration forces browsers to guess your page's character encoding, causing garbled text, broken layouts, and potential security vulnerabilities.
Character encoding tells the browser how to interpret the bytes in your HTML document as text. Without an explicit declaration, browsers must guess—and they often guess wrong. The result: special characters, emojis, and non-ASCII text render as garbage like ’ instead of '.
Worse, charset sniffing opens a security hole. Attackers can craft payloads that browsers misinterpret as different encodings, bypassing XSS filters. This is why Lighthouse requires the charset declaration to appear within the first 1024 bytes of HTML.
The browser checks three places for charset, in order:
Content-Type header with charset parameter<meta charset="UTF-8"> in the first 1024 bytesIf none of these exist or appear too late, you fail this audit.
View page source and look for a charset declaration in the <head>:
<!-- Good: meta charset in first 1024 bytes -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
The <meta charset> must appear before any content that contains characters—ideally as the first element after <head>.
In DevTools Network tab:
Content-TypeContent-Type: text/html; charset=UTF-8Or via command line:
curl -I https://your-site.com | grep -i content-type
If you have a long <head> before the charset, verify it's within 1024 bytes:
curl -s https://your-site.com | head -c 1024 | grep -i charset
Place the charset declaration as the first element in <head>:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Page Title</title>
<!-- other head elements -->
</head>
UTF-8 is the correct choice for modern web pages—it supports all languages and characters while being backwards-compatible with ASCII.
Configure your server to send the charset in the Content-Type header. This is processed before the HTML is parsed and provides an additional layer of reliability.
Nginx:
http {
charset utf-8;
charset_types text/html text/css application/javascript;
}
Apache (.htaccess):
AddDefaultCharset UTF-8
Express/Node.js:
app.use((req, res, next) => {
res.setHeader('Content-Type', 'text/html; charset=UTF-8')
next()
})
Cloudflare Workers / Edge Functions:
return new Response(html, {
headers: {
'Content-Type': 'text/html; charset=UTF-8',
},
})
If you have lots of content before your charset (long inline scripts, many meta tags), restructure your <head>:
<!-- Bad: charset buried after 1200 bytes of inline scripts -->
<head>
<script>/* 800 bytes of tracking code */</script>
<script>/* 600 bytes more */</script>
<meta charset="UTF-8">
</head>
<!-- Good: charset first -->
<head>
<meta charset="UTF-8">
<script>/* tracking code */</script>
<script>/* more scripts */</script>
</head>
<meta charset="UTF-8"> appears within the first few lines of <head>Content-Type: text/html; charset=UTF-8 header<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> works but is verbose. Use <meta charset="UTF-8"> for HTML5.<head>.UTF-8, utf-8, and utf8 all work, UTF-8 is the canonical form. Avoid exotic variations like utf_8.<head> elements.Different templates may have different <head> structures. Scan your entire site to ensure all pages declare charset correctly.