# Content-Type Header: Values, Examples, charset

> Content-Type tells the receiver what the body is: application/json, text/html; charset=utf-8, multipart/form-data. Common values, examples and 415 fixes.

Source: https://howhttpworks.com/headers/content-type
Last reviewed: 2026-10-05

> **TL;DR:** `Content-Type` names the media type of the body. Send `application/json` with JSON, let your HTTP client set the `multipart/form-data` boundary, and add `charset=utf-8` to `text/*` types; wrong or missing values cause 415 errors and blocked scripts.

## Syntax

```http
Content-Type: text/html; charset=utf-8
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryx3ZQ
```

A media type is `type/subtype`, optionally followed by `; parameter=value`. Types are case-insensitive. `charset` is meaningful for `text/*` types; `boundary` is required for `multipart/*`.

## Common values

| Content-Type | Used for |
| --- | --- |
| `text/html; charset=utf-8` | Web pages |
| `text/plain; charset=utf-8` | Plain text |
| `text/css`, `text/javascript` | Stylesheets and scripts (RFC 9239 makes `text/javascript` the one to use) |
| `application/json` | JSON APIs |
| `application/problem+json` | RFC 9457 error bodies |
| `application/x-www-form-urlencoded` | Default HTML form posts |
| `multipart/form-data` | File uploads |
| `application/octet-stream` | Unknown binary; browsers download |
| `application/pdf`, `application/zip` | Documents and archives |
| `image/png`, `image/webp`, `image/svg+xml`, `video/mp4` | Media |

## Requests

```http
POST /api/users HTTP/1.1
Content-Type: application/json

{"name":"Alice"}
```

With `fetch` and `FormData`, do not set the header yourself. The browser adds the boundary:

```javascript
// Right: browser sets multipart/form-data; boundary=...
fetch('/upload', { method: 'POST', body: formData })

// Wrong: the boundary is missing and the server cannot split the parts
fetch('/upload', { method: 'POST', body: formData, headers: { 'Content-Type': 'multipart/form-data' } })
```

With curl, `-d` defaults to `application/x-www-form-urlencoded`, which is why JSON posts fail until you add `-H 'Content-Type: application/json'`:

```bash
curl -i https://api.example.com/users -d '{"name":"Alice"}'
# HTTP/1.1 415 Unsupported Media Type  (or 400 with an empty body)
curl -i https://api.example.com/users -H 'Content-Type: application/json' -d '{"name":"Alice"}'
```

One CORS note: `Content-Type: application/json` is not a safelisted value for cross-origin requests, so it triggers a preflight. Only `application/x-www-form-urlencoded`, `multipart/form-data` and `text/plain` are exempt. See [CORS preflight](https://howhttpworks.com/debug/cors-preflight).

## Errors people search for

**`Refused to execute script from 'https://example.com/app.js' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled.`** The path returned your SPA fallback or a 404 page. Check the actual response with `curl -sI`, fix the asset path or `try_files`/rewrite rule, and keep `X-Content-Type-Options: nosniff` on.

**`Refused to apply style from '...' because its MIME type ('text/html') is not a supported stylesheet MIME type`.** Same cause for CSS.

**`Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "application/octet-stream"`.** Serve `.js` and `.mjs` as `text/javascript`. In nginx check `include mime.types;` is present; in S3 or GCS set the object metadata `Content-Type`.

**`415 Unsupported Media Type`.** The server did not accept the request body type. See [415](https://howhttpworks.com/status-codes/415).

**Mojibake such as `Ã©`.** A `text/html` response without `charset` is guessed by the browser. Send `charset=utf-8` and also `<meta charset="utf-8">` in the first 1024 bytes.

**Download instead of render.** `application/octet-stream` or a missing type with `Content-Disposition: attachment`. See [Content-Disposition](https://howhttpworks.com/headers/content-disposition).

## Sniffing

If the type is missing or generic, browsers may guess from the content (MIME sniffing), a vector for XSS through uploaded files served as HTML. `X-Content-Type-Options: nosniff` disables sniffing for scripts and styles and is worth setting everywhere; see [X-Content-Type-Options](https://howhttpworks.com/headers/x-content-type-options). Serve user uploads from a separate domain with the correct type, or with `Content-Disposition: attachment`.

## Server configuration

nginx maps extensions in `mime.types` and falls back to `default_type`:

```nginx
include /etc/nginx/mime.types;
default_type application/octet-stream;
types { text/javascript mjs; }
```

Apache: `AddType text/javascript .mjs`. Verify with:

```bash
curl -sI https://example.com/app.mjs | grep -i content-type
```

## Related

- [Content-Encoding](https://howhttpworks.com/headers/content-encoding), [Content-Length](https://howhttpworks.com/headers/content-length), [Accept](https://howhttpworks.com/headers/accept), [Content-Disposition](https://howhttpworks.com/headers/content-disposition)
- [415 Unsupported Media Type](https://howhttpworks.com/status-codes/415)
