For the complete documentation index, see llms.txt. Markdown versions are available by appending .md to documentation URLs.

Document Load

SigNoz Cloud - This page applies to SigNoz Cloud editions.
Self-Host - This page applies to self-hosted SigNoz editions.

Overview

The OpenTelemetry document load instrumentation traces page loads in your web application. Each load arrives in SigNoz as one trace: a span for the document itself, one span per resource the page fetched, and the DNS lookup, connection, request, response, and DOM processing phases recorded as timed events on those spans.

Those spans answer questions a single page-load number cannot:

  • Which resource delayed rendering, and by how much
  • Whether a third-party script or external API caused a slow load
  • How page load time shifted after a release

This page covers the instrumentation setup and one trace-based alert on resource fetch time.

Prerequisites

  • A web application you can add a JavaScript file to
  • A SigNoz Cloud account or a self-hosted SigNoz deployment

Setup

Step 1: Install dependencies

npm install @opentelemetry/sdk-trace-web \
  @opentelemetry/exporter-trace-otlp-http \
  @opentelemetry/instrumentation \
  @opentelemetry/instrumentation-document-load \
  @opentelemetry/resources

Step 2: Create an instrumentation file

In the src directory of your web application, create otel-setup.js and paste the code below.

src/otel-setup.js
import { BatchSpanProcessor, WebTracerProvider } from '@opentelemetry/sdk-trace-web';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { DocumentLoadInstrumentation } from '@opentelemetry/instrumentation-document-load';
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { resourceFromAttributes } from '@opentelemetry/resources';
 
const exporter = new OTLPTraceExporter({
  // Self-hosted SigNoz: use your collector's OTLP HTTP endpoint instead.
  url: 'https://ingest.<region>.signoz.cloud:443/v1/traces',
  headers: {
    // Not needed for self-hosted SigNoz.
    'signoz-ingestion-key': '<your-ingestion-key>',
  },
});
 
const provider = new WebTracerProvider({
  resource: resourceFromAttributes({
    'service.name': '<service_name>',
  }),
  spanProcessors: [new BatchSpanProcessor(exporter)],
});
 
provider.register();
 
registerInstrumentations({
  instrumentations: [new DocumentLoadInstrumentation()],
});

Verify these values:

Step 3: Import the instrumentation file

Import otel-setup.js as the first import in your entry file, so the instrumentation loads before your application code runs.

src/index.js
import './otel-setup';

Step 4: Start the app

From the root folder of your web application, run:

npm start

Load a page in the browser. Your application shows up in the Services section of SigNoz.

Web application listed in the SigNoz Services section
SigNoz Services Interface

Step 5: Read the document load traces

Open the Traces section. Each page load appears as a trace rooted at a documentLoad span, with one documentFetch child for the HTML document and one resourceFetch child per resource the page pulled in.

Those three names are the only spans the instrumentation emits. Open a span to read its phase timings, which arrive as events such as domainLookupStart, connectStart, requestStart, responseStart, and domInteractive. Filters and alerts match on the span names, so query name = resourceFetch rather than a phase name.

Document load traces in the SigNoz Traces explorer
Trace Data on Document Load

Set up an alert on resource fetch time

resourceFetch spans cover the external scripts, images, style sheets, and fonts a page needs to render. Alerting on their duration tells you when to cache or optimize an asset, before users report a slow page.

Sample trace-based alert for resourceFetch spans
ResourceFetch Trace Alert Sample

Define the query

Use the Create an Alert button at the bottom of the Traces section, or start from the Alerts section. For the full options, see trace-based alerts.

On the Traces Based Alerts page, set the Traces filter to service.name = <service_name> and name = resourceFetch. Set Y-axis units to seconds, set Legend Format to Resource Fetch, then press Stage & Run Query.

Trace filter set to service.name and name equals resourceFetch
Set the Traces Field to filter ResourceFetch Data

Define the alert condition

Send a notification when A is above the threshold at least once during the last 5 mins, with Alert Threshold set to 10 seconds.

Alert condition set to above threshold at least once in the last 5 minutes
Set the Alert Condition

Set the alert configuration

Set Severity to critical and Alert Name to ResourceFetch. Toggle on Alert all the configured channels, or pick one channel from the dropdown. Save the rule and test the notification.

Alert configuration with severity critical and notification channels selected
Set the Alert Configuration

The rule now shows up in the alert list and reports OK until a resource fetch crosses 10 seconds.

ResourceFetch alert rule in OK state in the SigNoz alert list
ResourceFetch Alert Rule is OK

Troubleshooting

Open your browser's developer console and check the POST request to /v1/traces on the Network tab. Its status tells you which case below applies.

Console shows a CORS error and the request never reaches the collector (self-hosted)

  • Likely cause: the collector's OTLP HTTP receiver does not allow your frontend's origin, so the browser blocks the request at the preflight stage
  • Fix: add your frontend URL under cors.allowed_origins on the otlp receiver's http protocol and restart the collector, as shown in CORS in OTLP HTTP Receiver
  • Verify: curl -i -X OPTIONS -H "Origin: <your-frontend-url>" -H "Access-Control-Request-Method: POST" <your-collector-otlp-http-url>/v1/traces returns an Access-Control-Allow-Origin header. A 405 method not allowed response means CORS is still off.

Console reports the request was blocked as mixed content (self-hosted)

  • Likely cause: an HTTPS page cannot fetch a plain http:// collector endpoint. This surfaces after deploying, since http://localhost is exempt and works locally.
  • Fix: expose the collector over HTTPS, or proxy /v1/traces from your app's own origin
  • Verify: the exporter url starts with https://, or is a same-origin path, and the POST reaches the Network tab with a status instead of failing outright

The request returns 401 or 403 (SigNoz Cloud)

  • Likely cause: wrong ingestion key, or a key issued for a different region than the one in the exporter URL
  • Fix: copy the key again from your ingestion settings and set <region> to that same workspace's region
  • Verify: the POST to https://ingest.<region>.signoz.cloud:443/v1/traces returns 200

TypeError: provider.addSpanProcessor is not a function

  • Likely cause: the instrumentation file was written for OpenTelemetry JS SDK 1.x, where processors were added after construction
  • Fix: pass processors through the constructor instead: new WebTracerProvider({ spanProcessors: [new BatchSpanProcessor(exporter)] })
  • Verify: the page loads without console errors and a POST to /v1/traces appears on the Network tab

Resource is not a constructor, or Resource is missing from @opentelemetry/resources

  • Likely cause: SDK 2.x removed the Resource class
  • Fix: build the resource with resourceFromAttributes({ 'service.name': '<service_name>' })
  • Verify: spans in SigNoz carry your service.name instead of unknown_service

The POST returns 200 but nothing appears in SigNoz for a few seconds

  • Expected: BatchSpanProcessor batches spans and exports every 5 seconds by default. In the browser it also flushes when the visitor hides the tab or navigates away.
  • Fix: wait one batch interval, then refresh the Traces explorer. Widen the time range if you are looking at a narrow window.

A third-party asset has a resourceFetch span, but no breakdown inside it

  • Likely cause: the browser withholds phase-level timing for cross-origin resources, so the span keeps its total duration while the request and response timings collapse to zero
  • Fix: have the asset's host send a Timing-Allow-Origin header naming your frontend origin
  • Verify: performance.getEntriesByName('<asset-url>')[0] reports non-zero requestStart and responseStart in the browser console

Next steps

Get Help

If you need help with the steps in this topic, please reach out to us on SigNoz Community Slack. If you are a SigNoz Cloud user, please use in product chat support located at the bottom right corner of your SigNoz instance or contact us at cloud-support@signoz.io.

Is this page helpful

Last updatedJuly 31, 2026

Edit on GitHub