# What Is a MIME Type? — The Header That Decides Render vs Download

Canonical: https://commareports.com/glossary/mime-type
Published: 2026-09-11

> A MIME type tells the browser what a response contains. Why text/html renders and application/octet-stream downloads, how Content-Disposition overrides it, and where reports go wrong.

# MIME type

**A MIME type — formally a media type — is the label in a response's
`Content-Type` header telling the client what the body contains.** The
browser reads it to decide whether to render the response, play it, or
save it to disk.

```
Content-Type: text/html; charset=utf-8    → renders
Content-Type: application/octet-stream    → downloads
Content-Type: text/plain                  → shows the markup as text
```

Over HTTP the header is authoritative and the file extension is
irrelevant. `report.html` served as `application/octet-stream` is a
download, every time.

## The two headers that decide

| Header                | Says                 | Values that matter                                    |
| --------------------- | -------------------- | ----------------------------------------------------- |
| `Content-Type`        | What the bytes are   | `text/html`, `application/octet-stream`, `text/plain` |
| `Content-Disposition` | What to do with them | `inline`, `attachment; filename="…"`                  |

`Content-Disposition: attachment` wins over a correct `Content-Type`. If
a page downloads despite `text/html`, that header is why.

## Where reports get this wrong

- **S3 and compatible object stores.** An upload with no declared type
  is stored as `application/octet-stream` or `binary/octet-stream`, so
  the report downloads. Fixed at upload time with
  `--content-type text/html`, not afterwards on the link
  ([the full fix](/fix/s3-html-downloads-instead-of-opening)).
- **CI artifact endpoints.** Many serve every artifact as a download by
  policy, regardless of type — which is why a GitHub Actions "report
  link" is a zip
  ([why](/fix/github-actions-artifact-html-not-viewable)).
- **Chat and ticket attachments.** HTML is served as a download
  deliberately, because rendering user-supplied HTML in the app's own
  origin would be an XSS vector
  ([why Slack won't preview](/fix/slack-wont-preview-html-file)).

That last one is not a misconfiguration. Serving arbitrary HTML inline
from an origin that holds sessions is genuinely dangerous — which is why
services that do render report HTML do it inside a
[sandboxed iframe](/glossary/iframe-sandbox) on a separate origin.

## Charset matters too

`text/html` without `charset=utf-8` leaves the browser guessing, and the
guess is wrong for any report containing non-ASCII test names, author
names or currency symbols. The `<meta charset>` in the document helps,
but the header wins where both are present.

## Try it

Comma is free — unlimited reports, unlimited commenters, unlimited
revision history. Reports are served with the headers that make them
render.

**[Publish a report that opens →](https://commareports.com/)**

### Related

- [S3 downloads instead of rendering](/fix/s3-html-downloads-instead-of-opening) · [Slack won't preview HTML](/fix/slack-wont-preview-html-file)
- [iframe sandbox](/glossary/iframe-sandbox) · [Presigned URL](/glossary/presigned-url)
- [Open an HTML file online](/open-html-file-online) · [Glossary](/glossary)
