Give every request a trace ID at the edge: one identifier the request carries through every log line, outgoing call and queued job, and onto the error page the customer sees. In software, that identifier is what a trace ID means. In the W3C standard, it is 32 lowercase hex characters, sent in a header named traceparent.

What is a trace ID: one name for one request’s journey

A trace ID is the one identifier a request gets when it enters a system, carried through every handler, query, outgoing call and queued job done on its behalf. In the W3C Trace Context standard it is 16 bytes written as 32 lowercase hex characters. It names a piece of work, never a person.

Whether a log viewer prints it as trace_id, traceId or TraceID, what is meant is that same name for one request. A trace is the whole journey, and the trace ID is what you search for to pull it back together. The structured event shape in error logging best practices with structured events carries it as a trace_id field next to request_id, and that article draws the line between logs, error tracking, traces and uptime.

The standard’s own rules are short. The value is a 16-byte array, and all zeros is an invalid value. It is not a user id, a session id, a secret or proof of anything: the specification says tracing vendors must not use the traceparent and tracestate fields for any personally identifiable or otherwise sensitive information, and that the only purpose of those fields is to enable trace correlation.

Three ids get mixed up, and they differ in what they name and where they live:

idwhat it identifieswho creates ithow long it liveswhere you see it
Trace IDThe whole path of one request, every span includedThe first service that receives the request without a valid traceparentThe whole trace: every span in it shares the same valueA trace_id log field, a tracing tool’s trace view, the second field of traceparent
Span IDOne unit of work inside the trace, such as one queryThe service doing that work, one per spanOne span, from its start timestamp to its end timestampA span’s detail in a tracing tool, the parent-id field of traceparent
Correlation or request IDThe request, with no span structure around itWhatever first handles the request: a proxy, the host or your codeAs long as you keep passing itA request_id log field, an X-Request-Id or X-Correlation-Id header

The trace ID and span ID rows come from the W3C specification and OpenTelemetry’s definitions; the correlation ID row is my own account of how teams use the older convention. You meet one of these in a log line, in an error tracker’s or APM tool’s trace view, in a traceparent request header, or in a header a cloud load balancer adds. The fastest place to look needs no terminal: open your browser’s network tab, click any request to your app, and read the response headers for an id.

This page belongs to the wider set of controls in logging and monitoring before customers depend on the app.

Other things called a trace ID

Several other things share the name, and none of them is this page’s subject. TraceID is a platform that helps manufacturers trace high-value products, and Trace iD is a home for soccer memories and highlights, with its own Basic and Pro tiers. A payout trace ID is created by banking partners to track a missing or delayed payout, and Stripe’s docs tell you to give it to your bank when an expected payout has not arrived after 10 business days, so it is looked up with the bank, not in software logs. Apps that claim to trace a phone or a person are another thing again. No account, payment or subscription question for any of them is answered here.

A trace ID turns the questions you ask during an incident from guesses into searches:

the question during an incidentwithout an idwith an id
A customer says checkout failed this afternoonFilter the logs by a time window and guess which lines were theirsSearch one id and read that request’s lines in order
Which of these dozens of error lines belong together?Match them by timestamp, route and hopeGroup them by the id they share
Did our call to the other service cause the error there?Compare two log streams by clockSearch the same id in the other service’s logs
Was the slow part our database or their API?Rerun the request and watchRead the spans of that one trace and compare their durations

The table is my picture of a normal support day. When a customer’s report arrives as a sentence instead of an id, the work of turning it into one identifiable request is set out in when a customer finds the bug before you do, and it is not repeated here.

Many apps are not at the search stage yet. In June and July 2026 I audited 21 third-party apps, and 17 of them had no error tracking or alerting; when a user hits an error, nothing records it. The 21 were my own choice, so the count says nothing about AI-built apps in general.

My working order is errors first, then the id, because an id on lines nobody keeps finds nothing. The id pays for itself at the first support ticket only if the customer can quote it, which is why it belongs on the error page as well as in the logs. For most small apps the cost is a middleware and a logger setting, not a new vendor.

How it works: spans, the traceparent header and the X- headers

The four parts below go from the model, to the wire format, to the headers you will find in the wild, to the decision for a single app.

Trace ID vs span ID

A trace ID names the whole request, and a span ID names a single timed operation inside it, such as a database query. Every span records the trace ID and its own span ID, and a child span also records its parent’s, which is how a tracing tool draws the request as a tree.

In one line each: the trace ID is the name of the request’s whole path, and a span ID is the name of one unit of work in it, the HTTP handler, one SQL query or one outgoing call. Zipkin’s B3 headers write the pair as single words, X-B3-TraceId and X-B3-SpanId, for the same two ids. OpenTelemetry’s traces concepts describe the root span as the one that marks the beginning and end of the entire operation: it has a trace ID but no parent. The sizes come from the W3C standard: the trace ID is 16 bytes, written as 32 hex characters, and the parent-id field is 8 bytes, written as 16 hex characters, which the standard notes some tracing systems call the span-id.

One checkout request, drawn as a trace with four spans:

  • Trace 4bf92f3577b34da6a3ce929d0e0e4736: one checkout request
    • Span A, the POST /checkout handler: the root span, with no parent
      • Span B, read the cart: parent A
      • Span C, call the payment API: parent A
      • Span D, write the order: parent A

All four spans carry the same trace ID; each has its own span ID and points at its parent. What spans add over a bare id is where the time went: span C’s duration tells you whether the payment API was the slow part. What they cost is instrumentation and somewhere to send the spans, which is the adoption question for OpenTelemetry distributed tracing.

The traceparent header: four fields, read left to right

The traceparent header is the W3C standard for passing trace identity between services. It has 4 hyphen-separated fields: a version, the 32-character trace ID, the 16-character id of the request as the caller knows it, and flags whose sampled bit carries the caller’s recording decision. A companion header, tracestate, carries vendor data.

Of all the trace headers in use, traceparent is the one that the W3C Trace Context recommendation defines, and it and tracestate are both listed as permanent in IANA’s HTTP field name registry. The specification’s own example of a traceparent header, for a request the caller sampled:

traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
fieldlengthmeaning
version2 hex characters (1 byte)00 in the current recommendation; ff is invalid
trace-id32 hex characters (16 bytes)The whole trace; all zeros is invalid
parent-id16 hex characters (8 bytes)The id of this request as known by the caller; all zeros is invalid
trace-flags2 hex characters (8 bits)Only the sampled flag is used in the current recommendation: 01 sampled, 00 not sampled

Trace Context Level 2 adds a random trace ID flag in the second least significant bit of trace-flags, but on 2026-10-03 it was still a Candidate Recommendation Draft dated 28 March 2024, so the table above is the current recommendation. The tracestate header carries vendor-specific trace information as name and value pairs, and storing anything in it is optional, so you can leave it alone until a vendor asks for it.

A few rules decide whether a receiver accepts the header. The hex must be lowercase. If the trace-id or the parent-id is invalid, vendors must ignore the traceparent, and when the version cannot be parsed the implementation should restart the trace, which means a new traceparent with fresh ids. The specification also calls the flags “recommendations given by the caller rather than strict rules”, and trust and abuse is the first of its three reasons. Its security section warns that a public API which naively continues any trace with the sampled flag set could let an attacker overwhelm the app with tracing overhead or forge trace-id collisions.

So whether to adopt a trace ID sent by a browser or an outside caller, or start a fresh one at your edge, is a decision to make on purpose. My default is to start fresh at a public edge and adopt the incoming one only from services you run. If you later add OpenTelemetry, OpenTelemetry’s context propagation page says its default propagator uses the headers specified by the W3C TraceContext specification, so it reads and writes this same header.

Generate the id in the W3C format from the start, and nothing has to change when tracing arrives. Node’s built-in crypto module is enough; no library, no vendor:

import { randomBytes } from 'node:crypto';

const traceId = randomBytes(16).toString('hex'); // 32 lowercase hex characters
const parentId = randomBytes(8).toString('hex'); // 16 lowercase hex characters
const traceparent = `00-${traceId}-${parentId}-00`; // flags 00: not sampled

crypto.randomBytes returns cryptographically strong pseudorandom bytes, and a Buffer’s hex encoding writes each byte as two hexadecimal characters, in lowercase. The flags stay 00 because the standard says the sampled flag should be set to 0 as the default option when a component starts the trace itself.

X-Trace-Id, X-Request-Id and the vendor headers

X-Trace-Id is a name some services give a request’s id, not a header the W3C Trace Context standard defines, so its format is whatever the sending service chose. X-Request-Id works the same way. The two headers the standard does define, traceparent and tracestate, are in IANA’s HTTP field registry; X-Trace-Id and X-Request-Id are not.

The headers you are most likely to meet, and what each one is:

headerwho sets itstandard or conventionwhat to do with it
X-Trace-IdTypically a service that returns its trace ID to the callerConvention; not in IANA’s registryLog it under your own field name if a caller sends it
traceparentA tracer or your own middleware, by the W3C rulesW3C standard; permanent in IANA’s registryAdopt or restart it on purpose; send it on calls you make
X-Request-IdA proxy, a platform or your own middlewareConvention; not in IANA’s registry; often a UUIDLog it beside your own id
X-Correlation-IdThe same kinds of sender as X-Request-IdConvention; not in IANA’s registryLog it beside your own id
X-Amzn-Trace-IdAn AWS Application Load Balancer adds or updates it before sending the request onAWS’s own format, Root=1- then an 8-hex-digit time and a 24-hex-digit id; not in IANA’s registryKeep it; an app can add its own fields, which the load balancer preserves
X-Cloud-Trace-ContextSome Google Cloud services, for backwards compatibilityGoogle’s legacy header, which predates the W3C specification; not in IANA’s registryPrefer traceparent, as Google’s docs recommend
b3 and X-B3-TraceIdTracers that use Zipkin’s B3 propagationB3’s single-header and multiple-header forms; not in IANA’s registryRead them only if a service you call uses them
x-vercel-idVercel, on responsesVercel’s own header: the regions the request hit and the region the function ran in; not in IANA’s registryKeep it beside your id; it is not your trace ID

The sources are IANA’s HTTP field name registry, AWS’s request tracing for Application Load Balancers, Google Cloud’s trace context page, Zipkin’s B3 propagation spec and Vercel’s response headers docs. The X- prefix itself is old practice: RFC 6648, from 2012, deprecates the “X-” convention for newly defined parameters in application protocols, and the standard header carries no prefix.

For your own app, log whichever id you use under one field name, request_id or trace_id, the same names as the event shape linked in the first section. Keep a platform’s own id beside yours rather than replacing it. Print yours on the error page as a short reference the customer can paste into a support message. The steps for reading, passing and returning the header belong with the correlation ID steps, which the next section points to. I’d consider an id safe to show, because it is random and grants nothing, which is what the standard’s privacy rule asks of it.

Is trace ID the same as correlation ID? What a single app needs

A trace ID and a correlation ID do the same job, and in an app with a single service they can be the same value. The difference is the standard around a trace ID: spans, parents and sampling. Start with one id on every log line, generated in the W3C format.

This agrees with the error-logging best practices article, which says a single-service app can begin with request_id and add trace context when background jobs, functions, queues or external calls make one interaction difficult to follow.

For a small SaaS, day one means one id per request, on every log line, passed on outgoing calls and into background jobs. I audited a voice-AI SDK whose token server logged with no request id, timestamp or structure, so a live issue could not be traced, and the five steps that prevent it are the core of how to do logging with correlation IDs. What it taught me: an id that exists nowhere in the logs cannot be quoted by a customer or searched by anyone, which is why it is the day-one item.

If the id is generated in the W3C format, as in the snippet above, nothing changes when tracing arrives. A logger’s child logger is the easy way to stamp it on every line; the wiring is part of pino logging in a Node app. Add spans when there is a second service or a slow path nobody can explain. The id is only useful if the lines it sits on are the right ones, so settle which logs severity levels stay on in production at the same time.

How to check your own app

A trace ID is proven with 5 checks after the basic one: the id has the W3C format, an outside traceparent is handled as decided, the error page reference matches the tracker event, two simultaneous requests never share an id, and an outgoing call carries the same trace ID once spans are on.

The basic check, one known id found on the lines of the API, a background job and a webhook you send, belongs with the correlation ID steps and comes first. Run the five below against a production build or a preview deployment, because the error page your customers see is the production one, and keep the evidence each one names, with the date.

  1. 01 Format. If you generate W3C-format ids, the trace ID in your response header or log line is 32 lowercase hex characters and not all zeros. Skip this check if your request ids are UUIDs. Evidence: the header value.
  2. 02 An outside traceparent. Send one well-formed header you made up and confirm the app does what you decided: it adopts the trace ID, so the same 32 characters appear on your log line, or it starts its own. Then send a malformed one and confirm the request still succeeds with a fresh trace ID. Evidence: the two log lines.
  3. 03 The error page reference. Force a server error with a thrown exception on a test route, rather than asking for a missing page, and confirm the reference printed on the error page equals the id on that error's tracker event and on its log line. This passes only if the app attaches the id to the tracker event, which is the point of the check. Evidence: a screenshot of the test page and the event.
  4. 04 Two requests at once. Send two requests at the same moment and confirm each response's id finds only its own lines. This fails when the id sits in a module-level variable instead of request context. Evidence: the two searches.
  5. 05 An outgoing call, only once spans are switched on. On a call to a second service you own, the traceparent it receives carries the same trace-id and a parent-id that is not the incoming one. Evidence: the receiving service's log line.

Check 2 rests on the standard: a header with an invalid trace-id or parent-id is ignored and a new traceparent is created; that the request itself must still succeed is my inference. Check 4 is what Node’s AsyncLocalStorage docs describe: stores that stay coherent through asynchronous operations, stable since Node 16.4.0, and their own example is a logger that assigns IDs to incoming HTTP requests. The failure mode, one shared variable overwritten by the second request, is my example. Check 5 follows OpenTelemetry’s description of propagation: the called service creates a new span in the same trace and sets the caller’s span as its parent.

If your host adds its own id, such as x-vercel-id, that is a different value from yours; search your app’s own log lines for your id, not the host’s request log.

In the sprint, deliverable 8.1 is verified this way: we trace a test request across services and check log content for sensitive fields.

Where the sprint fits

No deliverable is named after trace IDs. Under deliverable 8.1, Structured, sanitized logs, we add structured request logs with correlation IDs and appropriate user references, and exclude passwords, tokens and unnecessary personal data. Errors reach a tracker under deliverable 6.3, where we install error tracking such as Sentry with protected source maps, environment labels and alerts. Hosting, paid tools and API usage remain in your accounts. Both deliverables are listed, with how each is verified, in the published scope.

Common questions about tracing a request

How to find a trace ID?

Look in three places, in order: the response headers of the request in your browser’s network tab, the trace_id or request_id field of the matching log line, and the event detail in your error tracker. If none of the three shows one, the app does not create a trace ID yet, and the snippet in the traceparent section is a place to start. A correlation ID is found the same way, usually in an X-Request-Id or X-Correlation-Id response header or a request_id log field.

What is an X request ID?

An X request ID is a per-request identifier sent in the X-Request-Id header, set by a proxy, a platform or the app’s own middleware, and often a UUID. It is a convention, not part of the W3C Trace Context standard and not in IANA’s HTTP field name registry, and RFC 6648 deprecated the X- naming style for new parameters in 2012.

What is the difference between a root span and a trace?

The trace is the whole tree of spans for one request, and the root span is the top of that tree, the one span with no parent. In OpenTelemetry’s terms the root span marks the beginning and end of the entire operation, and every other span in the trace shares its trace ID.

What is trace context propagation?

Trace context propagation is passing the trace ID and the caller’s span ID from one service to the next, over HTTP in the traceparent header, so both services record their spans in the same trace. The receiving service sets the caller’s span as the parent of its own.

How can I trace an HTTP request?

Give the request an id at the edge, log it on every line, return it in a response header, and read it back by searching for that id. Spans and a tracing backend are for later, when you need timing per step; OpenTelemetry’s traces concepts page describes that model.