Web Development

If Modified Since: HTTP Header Guide & Best Practices

Configure the If Modified Since header to reduce bandwidth and server load. Use conditional requests to return 304 status codes for cached content.

880
if modified since
Monthly Search Volume

If-Modified-Since is an HTTP request header that asks servers to return a resource only if it has been modified after a specific date and time. When a webpage hasn't changed, the server returns a 304 Not Modified status instead of the full content, cutting bandwidth usage and server load. For SEO practitioners, this means faster load times, reduced server costs, and more efficient crawl budget utilization by search engines.

What is If Modified Since?

The If-Modified-Since header transforms standard HTTP GET and HEAD requests into conditional requests based on modification timestamps. The client sends a date formatted in GMT, and the server compares this against the resource's actual modification time.

If the resource changed since the specified date, the server returns a 200 OK response with the full content body and an updated Last-Modified header. If it hasn't changed, the server responds with 304 Not Modified and no message body. This header has been supported consistently across browsers since July 2015 (MDN Web Docs).

Unlike If-Unmodified-Since, this header only works with GET and HEAD methods. When used alongside If-None-Match (which validates against ETags), If-Modified-Since is ignored unless the server doesn't support If-None-Match.

Why If Modified Since matters

  • Reduces bandwidth consumption. A 304 response contains no body, delivering significant data savings compared to a full 200 response, particularly for large HTML documents or media files.
  • Decreases server load. The server avoids the computational cost of generating and transmitting full resource representations when content remains unchanged, as the 304 response is consistently more lightweight than the 200 response (Dev.to).
  • Improves page speed. Browsers display cached content immediately after receiving a 304, eliminating download latency for unchanged resources.
  • Optimizes crawl budget. Search engine crawlers can check modification timestamps before downloading content, allowing them to process more pages within their allocated crawl time.
  • Enables efficient API polling. Applications can use HEAD requests with If-Modified-Since to check for updates without retrieving full resource representations, triggering downstream operations only when data actually changes.

How If Modified Since works

The mechanism requires coordination between the initial response and subsequent requests:

  1. Initial request. The browser requests a resource. The server responds with 200 OK, includes the Last-Modified header showing the resource's modification time in GMT, and delivers the full content body.
  2. Cache storage. The browser stores the resource and notes the Last-Modified date.
  3. Subsequent request. When revisiting the page, the browser sends If-Modified-Since containing the previously stored Last-Modified value.
  4. Server evaluation. The server compares the header date against the current file modification time. Because HTTP dates truncate milliseconds, servers must zero out milliseconds from file system timestamps (mtime) before comparison to avoid precision mismatches (Dev.to).
  5. Conditional response. If modified, the server returns 200 OK with new content. If unmodified, it returns 304 Not Modified with no body, and the browser displays the cached version.

Best practices

Set Last-Modified headers on all cacheable resources. Without an initial Last-Modified response header, browsers have no baseline date to send in If-Modified-Since on subsequent visits. Configure your server or application to emit this header for static files and dynamic content that tracks modification times.

Format dates in GMT with millisecond precision removed. HTTP specifications require GMT (Greenwich Mean Time) and define specific date formats. When comparing file system modification times (mtime) against header values, strip milliseconds from the mtime using setMilliseconds(0) or equivalent, since HTTP date formatting truncates milliseconds and direct comparisons may fail due to millisecond discrepancies (Dev.to).

Use Cache-Control to force revalidation. To ensure browsers send conditional requests rather than using heuristics, combine Last-Modified with Cache-Control: must-revalidate and Expires: -1. This marks resources as stale immediately while requiring revalidation on each request (Stack Overflow).

Prefer HEAD for update checks. When you only need to know if content changed without retrieving it (such as triggering synchronization jobs), use HEAD requests with If-Modified-Since instead of GET. This checks modification status with minimal overhead.

Avoid mixing with ETag unless intentional. If your response includes both ETag and Last-Modified, and the client sends both If-None-Match and If-Modified-Since, the server ignores the date-based header and uses the ETag validation instead. Use one or the other unless you specifically want ETag priority.

Common mistakes

Mistake: Expecting If-Modified-Since on the first request. Browsers only send this header on subsequent visits after receiving a Last-Modified header in a previous response. If your initial response lacks Last-Modified, the conditional request mechanism never activates. Fix: Verify your server configuration sends Last-Modified headers for static assets and applicable dynamic content.

Mistake: Including milliseconds in date comparisons. File system timestamps include milliseconds, but HTTP date headers do not. This causes comparison logic to fail when the mtime is milliseconds newer than the header date, even for unchanged files. Fix: Strip milliseconds from server-side timestamps before comparing against the header value.

Mistake: Using If-Modified-Since with POST or PUT requests. This header only functions with GET and HEAD methods. Using it with state-changing methods produces unpredictable behavior or is ignored entirely. Fix: Restrict usage to safe, idempotent retrieval operations.

Mistake: Assuming 304 responses require no server processing. While 304 responses lack message bodies, the server still processes the request, accesses the resource to verify modification times, and generates response headers. Fix: Implement additional caching layers or ETags for further optimization if server load remains high.

Mistake: Inconsistent time zone handling. Using local time zones instead of GMT breaks the comparison logic since HTTP mandates GMT. Fix: Always format Last-Modified and parse If-Modified-Since using GMT/UTC time functions.

Examples

Basic conditional request:

GET /article.html HTTP/1.1
Host: www.example.com
If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT

If the file changed since October 21, 2015, the server responds:

HTTP/1.1 200 OK
Last-Modified: Wed, 01 Jun 2022 08:00:00 GMT
Content-Type: text/html

[Full HTML content]

If unchanged:

HTTP/1.1 304 Not Modified
Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT

Cache refresh scenario: A user visits your homepage. Your server responds with Last-Modified: Thu, 15 Nov 2023 19:18:46 GMT and the full HTML. The browser caches the page. Two hours later, the user refreshes. The browser sends If-Modified-Since: Thu, 15 Nov 2023 19:18:46 GMT. If you updated the homepage five minutes ago, the server returns 200 OK with the new content and updated timestamp. If not, the user sees the cached version instantly via a 304 response.

API polling for inventory updates: An inventory management system needs to check if warehouse stock data changed without downloading entire datasets. It sends:

HEAD /api/inventory/WH001 HTTP/1.1
If-Modified-Since: 2023-11-15T19:18:46Z

The server returns 304 Not Modified if no changes occurred, or 200 OK with new Last-Modified if stock levels updated, triggering a full data fetch only when necessary.

FAQ

What is If-Modified-Since used for? It allows browsers and clients to receive full content only when resources have actually changed since their last visit. This saves bandwidth by returning empty 304 responses for unchanged content and speeds up page loads by using cached copies when possible.

How does If-Modified-Since differ from ETag? If-Modified-Since uses date-based validation, while ETag uses content-based fingerprints (typically hashes). When both headers are present in a request, servers prioritize If-None-Match (the ETag validator) over If-Modified-Since. ETags detect changes even if the modification date hasn't updated, while date-based validation is simpler but less precise.

When should I use If-Modified-Since versus ETag? Use If-Modified-Since when you track reliable modification timestamps and want simple cache validation. Use ETag when content might change without timestamp updates, when serving dynamically generated content where byte-for-byte equality matters, or when you need strong validation guarantees.

Why isn't the browser sending If-Modified-Since? Browsers send this header only after receiving a Last-Modified header in a previous response. If your server doesn't emit Last-Modified, or if the cache was cleared, the browser has no date value to send. Additionally, if you use Cache-Control: no-store, browsers won't cache the resource and thus won't send conditional headers.

Can I use If-Modified-Since for APIs? Yes, particularly for HEAD requests that check if data changed without retrieving it. This works well for polling scenarios where you want to trigger operations only when resources update. Ensure your API returns proper Last-Modified headers for GET requests to enable this workflow.

What happens if the time zones don't match? HTTP specifications require all dates in If-Modified-Since and Last-Modified headers to use GMT (Greenwich Mean Time). If your server uses local time, comparisons fail. Always format these headers using GMT and handle conversions if your application stores times in local time zones.

Does a 304 response mean the server did no work? No. The server still processes the request, checks the resource's modification time, and generates response headers. It simply avoids generating and transmitting the message body. For high-traffic sites, you still benefit from reduced bandwidth, though CPU usage remains higher than with aggressive static caching.

Start Your SEO Research in Seconds

5 free searches/day • No credit card needed • Access all features