# ETag Header — Syntax, Values & Examples

> An identifier for a specific version of a resource, used to revalidate cached copies and to prevent lost updates.

An ETag (entity tag) is an opaque string the server attaches to a response — often a hash of the content. Clients send it back in `If-None-Match` to ask 'has this changed?' (a 304 means no), or in `If-Match` to say 'only apply my update if this is still the version I saw'.

- Type: Response header
- Category: Caching
- Defined in: [RFC 9110 §8.8.3 — ETag](https://www.rfc-editor.org/rfc/rfc9110.html#section-8.8.3)

## Syntax

```http
ETag: "<value>"   or   ETag: W/"<value>"
```

## Values

| Value | Meaning |
|---|---|
| `"<value>"` | strong ETag: byte-for-byte identical content |
| `W/"<value>"` | weak ETag: equivalent content, not necessarily identical bytes |

## Examples

```http
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
```

a strong ETag built from a content hash

```http
ETag: W/"0815"
```

a weak ETag

## Good to know

- The quotes are part of the value.
- When several servers serve the same files, build ETags from the content, not from inode numbers or timestamps — otherwise each server reports a different ETag and revalidation keeps missing.
- Compression middleware often turns strong ETags weak, because compressing changes the bytes.

## Who sets ETag

Most servers generate ETags for you: Express adds weak ETags to `res.send()` responses, Next.js to pages (the `generateEtags` option), and nginx to static files (`etag on;` by default). Check one with `curl -sI https://example.com/ | grep -i etag`, then send it back with `-H 'If-None-Match: "…"'` to see the 304.

## Check it

Fetch only the response headers and filter for ETag. In the browser, it's under Response Headers in DevTools → Network.

```sh
curl -sI https://example.com/ | grep -i '^etag:'
```

## FAQ

### Is an ETag required for a 304?

A validator is — ETag or Last-Modified. ETag is more precise, since Last-Modified only has one-second resolution.

### Can ETags be used for tracking?

They can: a unique ETag per visitor behaves like a cookie. That's one reason browsers now partition their caches by site.

## Status codes it appears with

- [304 Not Modified](https://www.devkult.com/http/304.md)
- [412 Precondition Failed](https://www.devkult.com/http/412.md)

## Related headers

- [If-None-Match](https://www.devkult.com/headers/if-none-match.md): Makes a request conditional: send the resource only if its current ETag isn't one of those listed.
- [Cache-Control](https://www.devkult.com/headers/cache-control.md): Directives that tell browsers and CDNs whether, where and for how long a response may be cached.
- [Last-Modified](https://www.devkult.com/headers/last-modified.md): The date and time the server believes the resource last changed.

## Further reading

- [HTTP caching explained](https://www.devkult.com/blog/http-caching-explained.md)

Open the interactive page: https://www.devkult.com/headers/etag