Correlation with Data
Correlate what a real user did in the browser with the exact backend work your services performed, and the log line(s) those services emitted using one continuous context. This page walks you through a RUM session → the backend trace → the attached logs, explaining what each panel means and how to read it confidently.
What you get
- A single request “thread” across browser, services, and logs (via
<trace_id>/<span_id>). - Visual timing (flame graph) to spot where time is actually spent.
- Request/response and headers to validate behaviour and caching.
- Log details to confirm status, payload sizes, and errors.
Prerequisites
- RUM SDK initialised with browser tracing enabled, so network events (XHR/Fetch) carry trace context.
- Backend services instrumented for tracing and configured to propagate W3C Trace Context (
traceparent/tracestate) through gateways/queues. - Logging is configured to enrich log events with
<trace_id>and<span_id>(so the Logs tab can stitch them automatically).
Short Answer: it’s close, but we can make the “what” and the “how” completely unmistakable by adding two small, explicit sections at the top. Below are drop-in blocks you can paste into your page. They keep your placeholders and reference your screenshots.
What is “correlation” in RUM?
Correlation means stitching a single user action in the browser (a RUM event such as an XHR/Fetch) to the exact backend trace that handled it and to the log entries those services emitted so that you can follow one request end-to-end.
Middleware achieves this by propagating and storing shared identifiers, primarily <trace_id> and <span_id>, across RUM, tracing, and logging. When these IDs match, you are looking at the same request across all three data types.
How Middleware stitches RUM → Traces → Logs
- Browser (RUM SDK)
- Auto-instruments XHR/Fetch and starts/joins a distributed trace.
- Attaches W3C Trace Context headers (
traceparent,tracestate) carrying<trace_id>/<span_id>on the network request. - Captures browser timings and attributes (e.g.,
resource.duration,http.url,browser.name) as well as the session ID (session.id). - Sends the RUM event with these fields to Middleware.
- Edge / Service (Tracing)
- Your tracing library extracts the incoming context from
traceparent. - It continues the same trace and creates server spans (e.g.,
app-api-v2span), preserving<trace_id>and generating child<span_id>values. - Spans are sent to the Middleware’s trace store.
- Your tracing library extracts the incoming context from
- Service Logging (Logs)
- Your logger is enriched to include
<trace_id>/<span_id>on every relevant log event (request logs, errors, DB warnings, etc.). - Logs are shipped to Middleware and indexed by these IDs.
- Your logger is enriched to include
- Index & Link
- Middleware indexes RUM events, traces, and logs on
<trace_id>(and also onsession.id/time). - From a RUM event, the UI can unambiguously fetch the trace and the logs that share the duplicate IDs.
- Middleware indexes RUM events, traces, and logs on
Start from the RUM Session (front end)
Open RUM → Sessions and select a session that interests you (e.g., a user reporting slowness). In the left pane, choose Events. Filter for Type: xhr and click the network event (e.g., GET /api/v1/account/init).
You’re selecting the exact browser request that the user’s page fired. From here, Middleware pivots you to the backend view for this very request.

What you see on the right:
- Flame Graph (top): stacked spans across services that handled this request.
- Services panel / Exec time % (right): Which service took the most time.
- Tabs (bottom): Trace Attributes, Events, Logs, Headers, Request, Response.
Why it matters:
- This is already filtered to the same request your browser made. No manual search across products; you’re looking at one stitched timeline.
Read the Trace (How to Interpret the Panels)
1. The Flame Graph
- Each bar is a span; its width is duration.
- Bars stack to show parent/child work (e.g., frontend gateway →
app-api-v2→ DB). - Zoom and hover to see where the latency sits. Long, wide bars are hot spots.
How to use it
- If the top bar is the HTTP handler and a child DB call dominates, you’ve found the bottleneck.
- If most of the time is spent before any server span, it’s likely due to network/TTFB/CDN issues.
2. Service Breakdown (Exec time %)
- A quick at-a-glance ranking of which service is responsible for most of the end-to-end time.
3. Trace Attributes (context you’ll rely on)
Open the Trace Attributes tab (it’s usually selected). You’ll see a merged view of browser and server attributes. Typical high-value fields:
| Attribute | Meaning | Example |
|---|---|---|
event.type | Browser event type | xhr |
ttp.method, http.url, http.status_code | Core request data | GET https://<host>/api/v1/account/init → 200 |
traceId, spanId | Correlation keys across RUM, trace, and logs | <trace_id>, <span_id> |
browser.trace | Browser tracing enabled | true |
resource.duration | Browser-observed total resource time | 369.3 ms |
resource.first_byte.duration | Time to first byte from server/CDN | 366.5 ms |
resource.download.duration | Time to read the response | 2.8 ms |
resource.size / resource.transfer_size | Uncompressed vs on-wire size | 14708 B / 5716 B |
http.response_content_length | Server-reported length | 5416 B |
project.name, mw.agent_id | Project/agent identity | <project_name>, <agent_id> |
browser.name/version, os | Client environment | Chrome 138, Linux |
cf-*, email, name | (Optional) geo/user fields | <city>, <country>, <email>, <user_name> |
Anchor the correlation on IDs: Write down <trace_id> and <span_id> from here; you’ll confirm them again in the Logs view. If they match, you’re unquestionably looking at the same request from browser → services → logs.
Jump to Logs (same request, same IDs)
Click the Logs tab in the same right-hand inspector. You’ll see log entries scoped to this trace/span, no extra filters needed.

Open a log row to inspect its structured fields.

Key fields you’ll read here:
| Field | Why it matters | Example |
|---|---|---|
service.name | Which service emitted the log | app-api-v2 |
method, path, response_status | Confirms HTTP behaviour | GET, /api/v1/account/init, 200 |
duration | Service-reported time | 24 ms |
traceId / spanId | Must match the Trace view | <trace_id> / <span_id> |
response-body-size | What the service sent | 0 B / 14 K |
ip, user_id | Origin context (if logged) | <ip>, <user_id> |
project.name, mw_agent, telemetry.sdk.language | Runtime & agent metadata | <project_name>, true, go |
Sanity check: If the traceId here doesn’t match the Trace Attributes, your gateway/worker likely started a new trace. Ensure trace context headers are forwarded end-to-end.
Validate Payloads and Headers
Use the Request, Response, and Headers tabs to confirm:
- Auth headers present/valid; cache headers as expected.
- Response status/text and content length match what the browser saw.
- Mismatch examples to look for:
- Server
durationis small butresource.first_byte.durationis large → network/CDN or queueing before your app. - Response length differs between server and browser fields → compression or proxy mutation (expected with HTTP/2 + gzip/brotli).
- Server
Field Glossary (front-end timings)
These fields are reported by the browser and help you understand “time outside your code”:
resource.connect.duration: TCP connect time.resource.ssl.duration: TLS handshake time.resource.first_byte.duration: Time until first byte (server + network + intermediaries).resource.download.duration: Time to read response from socket.resource.duration: Sum of the above (roughly connect → download).
Tip: Compare resource.first_byte.duration with the service log duration. If first_byte ≫ service duration, most latency happened before your application code returned (CDN, WAF, upstream, or network).
Troubleshooting Correlation
- No logs under the trace
- Ensure your logger attaches
<trace_id>/<span_id>and that log ingestion is enabled for the service. - Check sampling and log levels; the event might be filtered out.
- Ensure your logger attaches
- IDs don’t match between trace and logs
- A proxy/queue/async worker can start a new trace. Forward
traceparentheaders and bind server spans to incoming context.
- A proxy/queue/async worker can start a new trace. Forward
- The browser shows a long TTFB, but the service time is small
- Investigate CDN/WAF, upstreams, or network segments. Use headers (age, via, server-timing) to attribute the gap.
- No
browser.trace- Verify RUM init options; ensure CSP/ad-blockers aren’t disabling XHR/fetch instrumentation.
Need assistance or want to learn more about Middleware? Contact our support team at [email protected] or join our Slack channel.