Custom Status Codes
Relevant source files
The following files were used as context for generating this wiki page:The Rendertron service provides a mechanism for developers to control the HTTP status code returned to the client (e.g., a search engine bot). This is crucial for accurately signaling the state of a rendered page, such as "Not Found" (404) or "Bad Request" (400), which is important for SEO and correct bot behavior.
This functionality is achieved through two primary methods: forwarding the status code from the origin server's response and allowing the rendered page's HTML to override the status code via a special <meta> tag. The system has a clear set of precedence rules to determine the final status code.
Sources: README.md:92-95, src/renderer.ts:133-149
Status Code Determination Logic
The final status code returned by a /render request is determined by a sequence of checks performed within the Renderer.serialize method. It prioritizes the origin server's response status and then looks for an override in the page's content.
Sources: src/renderer.ts:101-158
Forwarding Server Status Codes
By default, Rendertron captures and preserves the HTTP status code from the initial response of the requested URL. For example, if a request to /render/http://example.com/not-found results in the example.com server returning a 404, Rendertron will also return a 404 status to the original client.
This behavior is validated by tests ensuring that server status codes are correctly forwarded.
Sources: src/test/app-test.ts:110-113, src/renderer.ts:133-134
Overriding with a Meta Tag
If the origin server responds with a 200 OK or 304 Not Modified status, the status code can be explicitly overridden by including a <meta> tag in the <head> of the HTML document.
The format for this tag is:
<meta name="render:status_code" content="<STATUS_CODE>" />
For example, to return a 400 Bad Request status, the following tag would be included:
<meta name="render:status_code" content="400">
This feature is tested by rendering a page containing this meta tag and asserting that the Rendertron service returns the specified status.
Sources: README.md:92-95, test-resources/http-meta-status-code.html:16, src/test/app-test.ts:115-120
Precedence and Processing Flow
The logic for determining the final status code follows a specific order of operations. The following diagram illustrates this flow.
This diagram shows the decision flow for setting the final HTTP status code.
Sources: src/renderer.ts:133-149
The rules can be summarized as follows:
| Initial Status | render:status_code Meta Tag | Final Status | Description |
|---|---|---|---|
304 | Not present | 200 | A 304 Not Modified is treated as a 200 OK for rendering purposes. |
200 | <meta ... content="400"> | 400 | The meta tag overrides the 200 OK status. |
200 | Not present | 200 | The original 200 OK status is preserved. |
404 | <meta ... content="200"> | 404 | The meta tag is ignored when the original status is not 200 or 304. |
200 | Multiple meta tags present | Status from the first tag | If multiple render:status_code meta tags exist, the content from the first one found in the DOM is used. |
The handling of multiple meta tags is confirmed by a test where a page contains tags for both 401 and 402, and the service correctly returns 401.
Sources: src/renderer.ts:133-149, src/test/app-test.ts:122-126, test-resources/http-meta-status-code-multiple.html:16-17
Implementation Details
The core logic resides in the Renderer.serialize method. After Puppeteer navigates to the page, the status code from the response object is retrieved. The code then attempts to find the meta tag and updates the status code variable accordingly.
// src/renderer.ts:133-149
// Set status to the initial server's response code. Check for a <meta
// name="render:status_code" content="4xx" /> tag which overrides the status
// code.
let statusCode = response.status();
const newStatusCode =
await page
.$eval(
'meta[name="render:status_code"]',
(element) => parseInt(element.getAttribute('content') || ''))
.catch(() => undefined);
// On a repeat visit to the same origin, browser cache is enabled, so we may
// encounter a 304 Not Modified. Instead we'll treat this as a 200 OK.
if (statusCode === 304) {
statusCode = 200;
}
// Original status codes which aren't 200 always return with that status
// code, regardless of meta tags.
if (statusCode === 200 && newStatusCode) {
statusCode = newStatusCode;
}
The page.$eval function uses a CSS selector (meta[name="render:status_code"]) which is equivalent to document.querySelector, meaning it will only find the first matching element in the DOM.
Sources: src/renderer.ts:133-149
Interaction with Caching
The status code of a rendered response affects whether it is cached. If the datastoreCache option is enabled, only responses with a 200 OK status are cached. Any response that results in a different status code (e.g., a 400 from a meta tag or a forwarded 404) will not be stored in the cache.
This is demonstrated in tests where a request that returns a 400 status is not cached, and a subsequent identical request is processed again instead of being served from the cache.
Sources: src/test/datastore-cache-test.ts:114-121, src/rendertron.ts:46-49
Summary
The custom status code feature is a vital part of Rendertron, providing developers with the necessary control to reflect the true status of dynamically rendered content. By either forwarding the origin server's status or allowing an override via a meta tag, Rendertron ensures that clients like search engine crawlers receive accurate signals, which is essential for proper indexing and site health monitoring. The clear precedence rules and interaction with the caching layer make it a robust and predictable system.