# Missing charset declaration

> A missing <meta charset> lets browsers guess your encoding, mangling emoji and accented text. Declare UTF-8 as the first tag in <head>.

_Category: Web essentials · Detector `web-essentials` · Check `charset` · Severity: warning_

With no explicit `<meta charset="utf-8">`, the browser falls back to a guessed encoding and can render “café” as “cafÃ©” or drop emoji entirely. Worse, if the tag appears late in a large `<head>`, the browser may have to restart parsing. It is invisible in dev on modern servers that send a `charset` header, then breaks on a static host that does not.

## Symptoms

- Accented characters and emoji render as garbled “mojibake”
- Content looks fine locally but breaks when served from a CDN or file://
- The browser restarts HTML parsing after discovering the `charset` late

## How VibeCheck detects it

The `web-essentials` detector flags this live in the browser and reports it to the widget's Problems list — and to your coding agent over MCP.

- **Issue string:** `Missing charset declaration`
- **Threshold:** No element matching <meta charset> in the document head

## Root causes

- A hand-written HTML shell omitted it
- The `charset` meta was placed after other tags or scripts instead of first
- Relying on the HTTP `Content-Type` `charset` header, which is absent on some hosts

## The fix

Declare UTF-8 as the very first element inside `<head>`, before any other tag or text, so the browser locks the encoding before parsing content. The short form `<meta charset="utf-8">` is the modern standard.

### Steps

1. Open your document head
2. Add `<meta charset="utf-8">` as the first child of `<head>`
3. Verify accented text and emoji render correctly on a static host

_Must be the first tag in <head>_

```html
<head>
  <meta charset="utf-8" />
  <!-- everything else follows -->
</head>
```

## Framework-specific fixes

### React

Vite/CRA React apps declare it in `index.html` as the first head tag.

_index.html_

```html
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
```

### Next.js

Next.js injects `<meta charSet="utf-8">` automatically for App Router pages — you normally do not add it. If VibeCheck still flags it, you have overridden the document with a custom `app/_document` that dropped it; restore the `charset` there.

_Auto-injected by Next — verify it is not stripped_

```html
<meta charSet="utf-8" />
```

### Vanilla JS

Add it as the first line of every page’s `<head>`, or in your server-side layout partial.

```html
<meta charset="utf-8" />
```

## FAQ

### Do I need the long <meta http-equiv="Content-Type"> form?

No. The short `<meta charset="utf-8">` has been valid HTML5 for over a decade and is preferred. Keep it as the first tag in `<head>`.

### It works locally — why does VibeCheck still flag it?

Your dev server may send a `charset` in the HTTP header, masking the missing tag. A static host or file:// open won’t, so declare it in the HTML to be safe everywhere.

## Related problems

- [Missing viewport meta tag](https://vibecheck.wcgw.fun/fix/missing-viewport-meta.md) — Web essentials
- [Missing lang attribute on <html>](https://vibecheck.wcgw.fun/fix/missing-lang-attribute.md) — Web essentials

---

Fix guide from VibeCheck — https://vibecheck.wcgw.fun/fix/missing-charset. Full site index for LLMs: https://vibecheck.wcgw.fun/llms.txt
