--- title: "NGINX Server-Timing (Help Center / Settings / Server-timing)" ai_context: "Use this article for questions about NGINX Server-Timing, reverse proxy timing, upstream connection latency, origin response delay and NGINX cache status in RUMvision. It covers exposing `Server-Timing` from NGINX, recommended fields such as `upstream_connect_time`, `upstream_header_time` and `upstream_cache_status`, converting NGINX timing variables from seconds to milliseconds with njs, configuring `js_import`, `js_set` and `add_header`, and applying the setup to HTML document requests. Relevant for questions about `$upstream_connect_time`, `$upstream_header_time`, NGINX HIT/MISS/BYPASS/EXPIRED/STALE cache states, backend or origin TTFB investigation, TLS connection time, DevTools validation, `PerformanceServerTiming`, avoiding `$upstream_response_time`, staging validation and preserving existing origin `Server-Timing` headers." canonical: "https://www.rumvision.com/help-center/settings/server-timing/nginx/" --- Breadcrumbs: [Home](https://www.rumvision.com/?format=md) > [Help Center](https://www.rumvision.com/help-center/?format=md) > [Settings](https://www.rumvision.com/help-center/settings/?format=md) > [Server-timing](https://www.rumvision.com/help-center/settings/server-timing/?format=md) > NGINX # NGINX Server-Timing RUMvision can collect NGINX timing data when your website exposes it through the `Server-Timing` response header. This helps you understand whether slow server response times are caused by NGINX proxying, upstream connection time, or waiting for your application server. NGINX does not expose standard Server-Timing metrics by default. If your site is not exposing these headers yet, you can add them in your NGINX configuration. ## Add Server-Timing via NGINX ### Recommended fields Below are the recommended fields to expose. Once these fields are exposed and NGINX is selected in your [tech stack settings](https://www.rumvision.com/help-center/monitoring/settings/domain-settings/?format=md#tech-stack) and enabled the NGINX checkbox, we will automatically collect them. Value Type/source Meaning `upstream_connect_time` **Metric** [`$upstream_connect_time`](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#var_upstream_connect_time) Time spent establishing a connection with the upstream server, including TLS handshake when applicable. `upstream_header_time` **Metric** [`$upstream_header_time`](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#var_upstream_header_time) Time between connecting to the upstream server and receiving the first byte of the upstream response header. `upstream_cache_status` **Filter** [`$upstream_cache_status`](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#var_upstream_cache_status) Shows NGINX cache behavior, such as `HIT`, `MISS`, `BYPASS`, `EXPIRED`, or `STALE`. ### Where to implement Implement this in the NGINX configuration that handles your HTML document requests. ``` /etc/nginx/nginx.conf /etc/nginx/conf.d/*.conf ``` The example below uses NGINX njs to convert NGINX timing variables from seconds to milliseconds, because `Server-Timing` expects durations in milliseconds. ### Rule to implement Apply this to all HTML document requests. These are the main page requests RUMvision uses to understand document TTFB and backend-related delays. This usually means the main document request of your pages, not images, scripts, stylesheets, or API calls. If needed, you can also expose these timings on other request types, but HTML document requests are the recommended starting point. Create this njs file: ``` // /etc/nginx/timings.js function toMs(value) { if (!value || value === '-') { return '0'; } const firstValue = String(value).split(/[,:]/)[0]; const seconds = Number(firstValue); if (!Number.isFinite(seconds)) { return '0'; } return String(Math.round(seconds * 1000)); } function upstreamConnect(r) { return toMs(r.variables.upstream_connect_time); } function upstreamHeader(r) { return toMs(r.variables.upstream_header_time); } export default { upstreamConnect, upstreamHeader }; ``` Then update your NGINX configuration: ``` load_module modules/ngx_http_js_module.so; http { js_import timings from /etc/nginx/timings.js; js_set $rumvision_upstream_connect timings.upstreamConnect; js_set $rumvision_upstream_header timings.upstreamHeader; server { location / { proxy_pass http://backend; add_header Server-Timing 'nginxConnect;dur=$rumvision_upstream_connect, nginxOrigin;dur=$rumvision_upstream_header, nginxCache;desc="$upstream_cache_status"' always; } } } ``` If you do not use NGINX caching, you can remove the `nginxCache` part from the header value. ## Testing the outcome Next step is testing the outcome. You could either wait for data to arrive in your RUMvision dashboard, or proactively test the outcome using the DevTools of your preferred browser. ### Expected outcome After deploying the configuration, your HTML document should return a `Server-Timing` header similar to this: ``` Server-Timing: nginxConnect;dur=12, nginxOrigin;dur=248, nginxCache;desc="MISS" ``` For a cached response, upstream values may be `0` and cache status may be `HIT`. ``` Server-Timing: nginxConnect;dur=0, nginxOrigin;dur=0, nginxCache;desc="HIT" ``` ### Check the response headers To verify the setup: 1. Open your website in Chrome or Edge. 2. Open DevTools. 3. Go to the Network tab. 4. Reload the page. 5. Click the main HTML document request. 6. Check the Response Headers section. 7. Look for `server-timing`. ### Test in DevTools Console As the browser exposes `Server-Timing` values through the `PerformanceServerTiming` interface, you can also test it in the browser console by running the following JavaScript: ``` const navEntries = window.performance.getEntriesByType('navigation'); console.table( navEntries[0].serverTiming ); ``` ## Important In general, be sure to: - Always test on staging environment before deploying these steps to a production environment. - Avoid exposing sensitive internal details. `Server-Timing` data is visible in the browser, so only expose metrics that are safe to share with visitors and third-party scripts. ### NGINX notes NGINX timing variables such as `$upstream_connect_time` and `$upstream_header_time` are measured in seconds with millisecond resolution. The example above converts them to milliseconds before exposing them as `Server-Timing` durations. Do not use `$upstream_response_time` for this response header. That value is only known after the full upstream response body has been received, which can be too late for a normal response header. If your origin already sends a `Server-Timing` header, make sure your NGINX configuration does not remove useful existing metrics.