# application/x-www-form-urlencoded: Format and Examples

> The default encoding for HTML form posts: fields joined as key=value pairs with &, in the same format as a URL query string.

- MIME type: `application/x-www-form-urlencoded`
- Used for: Request body
- Parameters: None — non-ASCII characters are always UTF-8 percent-encoded
- Specification: [WHATWG URL Standard](https://url.spec.whatwg.org/#application/x-www-form-urlencoded)

## Example

```http
POST /comment HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded

name=Ada&comment=c%C3%A0t+%26+dog&notify=on
```

## Send it

### HTML form (the default enctype)

```
<form action="/comment" method="post">
  <input name="name">
  <textarea name="comment"></textarea>
  <input type="checkbox" name="notify">
  <button>Send</button>
</form>
```

### fetch with URLSearchParams

```
// URLSearchParams encodes the body and sets the Content-Type for you.
const body = new URLSearchParams({ name: "Ada", comment: "càt & dog" });
await fetch("/comment", { method: "POST", body });
```

### curl

```
curl -d name=Ada --data-urlencode "comment=càt & dog" https://example.com/comment
```

## Receive it

### Express

```
app.use(express.urlencoded({ extended: false }));

app.post("/comment", (req, res) => {
  // req.body.name, req.body.comment
});
```

### Web standard Request

```
const form = await req.formData(); // parses urlencoded and multipart bodies
const name = form.get("name");
```

### Python (Flask)

```
name = request.form["name"]
tags = request.form.getlist("tag")
```

### PHP

```
$name = $_POST['name'];
```

## Good to know

- Spaces become `+` in form bodies but `%20` with `encodeURIComponent()`. A decoder that doesn't treat `+` as a space — plain `decodeURIComponent()` — turns "càt & dog" into "càt+&+dog".
- An unchecked checkbox isn't sent at all; a checked one without a `value` sends `on`.
- Parsers disagree on repeated keys (`tag=a&tag=b`): Node returns an array, PHP keeps the last value unless the name ends in `[]`, and Flask's `request.form["tag"]` returns the first (use `getlist`).
- Every non-ASCII byte becomes three characters, so it's a poor fit for binary data. Use [multipart/form-data](https://www.devkult.com/mime/multipart-form-data.md) for files.

## FAQ

### Is application/x-www-form-urlencoded the same as a query string?

Same format, different place. A GET form puts the encoded fields in the URL's query string; a POST form sends them as the request body with this Content-Type. One detail differs from `encodeURIComponent()`: the form encoding writes spaces as `+`.

### Do I need a charset parameter?

No. The WHATWG spec defines the type without parameters, and the bytes are always UTF-8 percent-encoded. Browsers' fetch adds `;charset=UTF-8` anyway, and servers ignore it.

### How do I send x-www-form-urlencoded with fetch?

Pass a `URLSearchParams` object as the body. fetch encodes it and sets the Content-Type. Sending a JSON string with this header gives the server one garbled field instead.

## Related types

- [multipart/form-data](https://www.devkult.com/mime/multipart-form-data.md)

Open the interactive page: https://www.devkult.com/mime/x-www-form-urlencoded