"Data MIME" is how most developers casually refer to the MIME types used to identify data payloads β JSON, binary blobs, protocol buffers, form data, streams, and the application-specific formats that apps use to round-trip their state across copy boundaries, fetch calls, and file uploads. Unlike image or video MIME types, which describe the bytes themselves, data MIME types describe how to interpret the bytes as structured information.
This article covers the data MIME types you will meet in three places: HTTP request and response bodies, FormData uploads, and the clipboard. It explains what each type means, when to use it, the common mistakes, and how to inspect real-world payloads.
The canonical data MIME types
Five types cover ninety percent of the data you will send or receive in a web app:
application/jsonβ structured data, human-readable, the default for REST and most SPAsapplication/octet-streamβ "raw bytes, figure it out yourself"application/x-www-form-urlencodedβ HTML form data, URL-encoded key/value pairsmultipart/form-dataβ HTML form with file uploads or mixed contenttext/plainβ unstructured string data
Each has different encoding rules, different size implications, and different debugger behaviour. Mixing them up is the most common source of "why is my backend receiving a stringified JSON blob?" bugs.
application/json
The workhorse. A Content-Type: application/json request means the body is a UTF-8 encoded JSON document. Every modern HTTP client serialises JavaScript objects automatically when you set this header. Every modern server parses it.
Common mistakes:
- Sending JSON with no
Content-Typeheader. The body is valid JSON but the server treats it as a blob and callsJSON.parseon[object Object]or worse. Set the header. - Sending JSON with
application/x-www-form-urlencoded. Body gets URL-encoded into{"name":"Alice"}, server tries to parse it as a form, fails silently. - BOM at the start. Some tools prefix the JSON with a byte-order mark.
JSON.parsethrowsSyntaxErroron the\uFEFF. - Non-UTF-8 encoding. JSON is always UTF-8 by spec. If your server emits windows-1252, clients will accept bytes that are not valid UTF-8 and produce mojibake.
application/octet-stream
The generic "I don't know what this is, or I don't want the browser to guess" content type. Servers use it to force a download; browsers use it as a fallback when sniffing fails. If you see it in a clipboard paste or a file upload, it almost always means the source stripped or lost the real MIME type.
When to send it from your own code:
- Uploading a blob of bytes that has no meaningful internet media type (sensor data, custom binary protocol)
- Forcing a download of any file β browsers will not render
application/octet-streaminline
When not to send it:
- Uploading images, PDFs, or other well-known formats β use their real MIME types so caching, thumbnailing, and client-side validation work
application/x-www-form-urlencoded
The default <form> encoding when no enctype is set. The body looks like a query string: name=Alice&age=42&tags=one&tags=two. Compact, widely supported, and the right choice for simple key/value submissions.
Caveats:
- Values are URL-encoded, so Unicode strings get percent-encoded. Expect a 3Γ size inflation for non-ASCII text.
- Nested objects and arrays require convention (brackets, dot-paths, repeated keys). Every framework picks a different one; document yours.
- Not suitable for files. Use
multipart/form-datainstead.
multipart/form-data
Designed for forms with file uploads. The body is a sequence of "parts", each with its own Content-Type and Content-Disposition header. Parts are separated by a boundary string that must not appear in any part's content (browsers generate random boundaries to avoid collisions).
Content-Type: multipart/form-data; boundary=---XXXX
---XXXX
Content-Disposition: form-data; name="avatar"; filename="me.png"
Content-Type: image/png
<raw PNG bytes>
---XXXX
Content-Disposition: form-data; name="username"
alice
---XXXX-- From JavaScript, construct it with FormData:
const fd = new FormData()
fd.append('avatar', fileInput.files[0])
fd.append('username', 'alice')
await fetch('/upload', { method: 'POST', body: fd }) Do not set Content-Type yourself when sending FormData β the browser must set it so the boundary is correct.
text/plain and text/* subtypes
Use text/plain for any UTF-8 string payload that does not need parsing. Other text/* types worth knowing:
text/csvβ comma-separated values, parseable by spreadsheet toolstext/tab-separated-valuesβ TSV, what Excel produces when you copytext/htmlβ HTML content (common on the clipboard, rare as a data payload)text/xmlβ XML (preferapplication/xmlfor new code)text/event-streamβ Server-Sent Events, streaming text frames
Streaming and chunked data
text/event-streamβ SSE. Each "event" is a set offield: valuelines followed by a blank line. Used for real-time one-way updates from server to browser.application/ndjsonβ newline-delimited JSON. Each line is a complete JSON document. Simple to parse with a line reader, friendly to generator functions.application/jsonl/application/x-jsonlinesβ same thing under other names.application/grpcβ gRPC over HTTP/2. Binary-framed protobuf.
Custom application/* MIME types
When you need to identify a format that no registered MIME type describes, you have three conventions:
application/vnd.<vendor>.<format>β vendor-tree. Registered with IANA. Use this if you want the type to be globally recognised.application/x-<format>β unregistered "experimental" prefix. Common but discouraged by modern RFCs; still works everywhere.application/prs.<producer>.<format>β personal tree. Rare.
Example custom types you will see in the wild:
application/vnd.api+jsonβ JSON:API spec payloadsapplication/ld+jsonβ JSON-LD, used for structured dataapplication/x-vnd.google-docs-document-slice-clip+wrappedβ Google Docs clipboard formatapplication/vnd.figmaβ Figma copy/paste formatapplication/x-protobufβ Protocol Buffers
If you are inventing one for your own app, prefer the vendor tree and pick a real reverse-DNS identifier. application/vnd.myapp.v1+json is well-structured: the +json suffix tells generic tools they can still parse the payload as JSON. For the full clipboard angle, see Writing Custom application/* MIME Types to the Clipboard.
Data MIME types on the clipboard
The clipboard is the least-discussed place where data MIME types matter. A copy from any app can place structured data alongside plain text, and a sufficiently clever paste handler can consume it directly:
document.addEventListener('paste', async (e) => {
// Check for structured JSON first
const json = e.clipboardData.getData('application/json')
if (json) {
try {
const data = JSON.parse(json)
return handleStructuredPaste(data)
} catch {}
}
// Fall back to plain text
const text = e.clipboardData.getData('text/plain')
handleTextPaste(text)
})To see which data MIME types a specific source actually writes, paste into Clipboard Inspector. Google Docs, Notion, Figma, and Office all publish richer types than you would guess from the surface UI.
Choosing a data MIME type: a decision tree
- Is it JavaScript-object-shaped? β
application/json - Is it a structured form, no files? β
application/x-www-form-urlencoded - Does it include files? β
multipart/form-data - Is it raw bytes with no standard format? β
application/octet-stream - Is it a stream of records? β
application/ndjsonortext/event-stream - Is it a known format with a registered MIME? β Use the registered type. Look it up at iana.org/assignments/media-types before inventing one.
- Is it your own format? β
application/vnd.yourapp.format+jsonif JSON-compatible, otherwiseapplication/vnd.yourapp.format.
Debugging data MIME type issues
- Server receives
[object Object]: client sent an object where the HTTP library expected a string. Serialise withJSON.stringifyand setContent-Type: application/json. - Browser downloads instead of rendering: server returned
application/octet-streamorattachmentContent-Disposition. Change the MIME type on the server. - CORS error only on JSON:
application/jsontriggers a preflight. Your server's CORS config must allow the Content-Type header and OPTIONS method. - FormData arrives empty: you set
Content-Typemanually and broke the boundary. Remove the header and let the browser set it.
Related: Clipboard MIME Types Explained, Writing Custom application/* MIME Types, File Types & MIME Types Reference.