Web request performance monitoring

  • Latest Dynatrace
  • Explanation
  • Published Dec 17, 2025

The OneAgent for iOS provides comprehensive web request monitoring capabilities:

  • Automatic instrumentation—automatically captures all web requests made via URLSession.
  • W3C Trace Context—activates distributed tracing by propagating trace context headers.
  • Manual reporting—report web requests from custom networking implementations.
  • Event enrichment—add custom properties to web request events.

Automatic web request instrumentation

The OneAgent for iOS automatically instruments web requests made using Apple's URLSession API and stores them as events in Grail.

Each event consists of well-defined key-value fields as specified in the Semantic Dictionary for user events.

This data can be queried directly in Grail using DQL.

Additionally, the timing values from the mobile side are measured.

What is captured automatically

For each web request, the SDK captures:

  • Request URL
  • HTTP method (GET, POST, PUT, DELETE, etc.)
  • Response status code
  • Request and response size (bytes sent/received)
  • Request duration
  • Errors (if the request fails)

The data captured will be structured and reported according to the fields specified in request.*.

Supported APIs

Automatic instrumentation works with:

  • URLSession.dataTask(with:completionHandler:)
  • URLSession.downloadTask(with:completionHandler:)
  • URLSession.uploadTask(with:from:completionHandler:)
  • Async/await variants (URLSession.data(from:), etc.)
  • NSURLRequest, NSURLConnection, NSURLProtocol
  • WKWebView requests
  • NSData convenience methods

Limitations

Automatic instrumentation has the following limitations:

  • Non-HTTP(S) protocols are not supported.
  • The requests of a third-party framework may not be instrumented.

Disable automatic instrumentation

To disable automatic web request instrumentation, set the DTXInstrumentWebRequestTiming configuration key to false in your app's Info.plist file:

<key>DTXInstrumentWebRequestTiming</key>
<false/>

You may want to disable automatic instrumentation when:

  • You need full control over which requests are reported
  • You're using a custom networking implementation exclusively

Which type of instrumentation to use

Request typeInstrumentation typeDTXInstrumentWebRequestTiming
HTTP(S)Option A: Autotrue
Option B: Manualfalse

You cannot combine automatic and manual instrumentation for the same HTTP(S) request.

W3C Trace Context (distributed tracing)

The SDK supports W3C Trace Context (external) for distributed tracing, allowing you to correlate mobile requests with backend services instrumented by Dynatrace.

For background and examples, see the Dynatrace Knowledge Base on W3C Trace Context.

How it works

When automatic web request instrumentation is enabled, OneAgent may propagate W3C trace context on outgoing requests by setting the following headers:

  • traceparent—Identifies the request as part of a distributed trace.
  • tracestate—Carries vendor-specific context. Dynatrace adds Dynatrace-specific information here.

OneAgent sets these headers automatically as part of its web request instrumentation.

W3C Trace Context headers (traceparent / tracestate) are used for distributed tracing correlation across services.

Behavior with existing trace headers

OneAgent automatically handles trace context headers on your requests. In most cases, you don't need to manage this yourself—OneAgent does the right thing based on what headers are already present.

When your request has no trace headers, OneAgent generates them for you:

Swift

// Your original request
var request = URLRequest(url: URL(string: "https://api.example.com/data")!)
request.httpMethod = "GET"
// After OneAgent instrumentation, headers are automatically added:
// traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
// tracestate: dt=...dynatrace-specific-data...
URLSession.shared.dataTask(with: request) { data, response, error in
// Handle response
}.resume()

Objective-C

// Your original request
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://api.example.com/data"]];
request.HTTPMethod = @"GET";
// After OneAgent instrumentation, headers are automatically added:
// traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
// tracestate: dt=...dynatrace-specific-data...
[[NSURLSession.sharedSession dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// Handle response
}] resume];

If the combined tracestate grows too large, OneAgent may trim entries to stay within W3C limits. Dynatrace data is preserved whenever possible.

Manually propagating trace context headers

If you use a custom networking stack and need to add W3C trace context headers yourself, use the public API Dynatrace.generateTraceContext(traceparent:tracestate:) (Swift) / generateTraceContext:tracestate: (Objective-C).

This API generates a new trace context (when traceparent is nil) or enriches an existing valid traceparent with a Dynatrace tracestate. It returns nil if the trace context can't be created (for example, when the provided traceparent is invalid or capture/tagging is not allowed).

import Dynatrace
var request = URLRequest(url: URL(string: "https://api.example.com/data")!)
// Read existing headers (if any)
let existingTraceparent = request.value(forHTTPHeaderField: "traceparent")
let existingTracestate = request.value(forHTTPHeaderField: "tracestate")
// Generate/enrich trace context
if let ctx = Dynatrace.generateTraceContext(existingTraceparent, tracestate: existingTracestate) {
request.setValue(ctx.traceparent, forHTTPHeaderField: "traceparent")
request.setValue(ctx.tracestate, forHTTPHeaderField: "tracestate")
} else {
// No changes should be applied when context can't be created (for example, invalid traceparent)
}

Report web requests manually

For networking libraries not covered by automatic instrumentation, you can manually report web requests using DTXHttpRequestEventData.

Basic usage

import Dynatrace
// Create the request data with the URL and HTTP method
let requestData = DTXHttpRequestEventData(url: "https://api.example.com/data", method: "GET")
.withDuration(250) // Duration in milliseconds
.withStatusCode(200) // HTTP status code
.withBytesSent(128) // Bytes sent
.withBytesReceived(4096) // Bytes received
// Send the web request event
Dynatrace.sendHttpRequestEvent(requestData)

Report errors

When a request fails, include the error information:

let requestData = DTXHttpRequestEventData(url: "https://api.example.com/data", method: "POST")
.withDuration(1500)
.withError(error as NSError)
Dynatrace.sendHttpRequestEvent(requestData)

Include trace context

To correlate manually reported requests with distributed traces, include the traceparent header:

// Report the event with the traceparent
let requestData = DTXHttpRequestEventData(url: url, method: "GET")
.withDuration(duration)
.withStatusCode(statusCode)
.withTraceparentHeader(traceparent)
Dynatrace.sendHttpRequestEvent(requestData)

Add custom properties

Add custom event properties to capture additional context:

let requestData = DTXHttpRequestEventData(url: url, method: "POST")
.withDuration(300)
.withStatusCode(201)
.addEventProperty("event_properties.api_version", value: "v2")
.addEventProperty("event_properties.endpoint", value: "users")
Dynatrace.sendHttpRequestEvent(requestData)

Custom property keys must be prefixed with event_properties.—properties without this prefix will be dropped.

Event enrichment (modifiers)

Event modifiers allow you to enrich web request events with additional data before they are sent. This is useful for adding context from the request/response that isn't captured automatically.

Add a web request modifier

let subscriber = Dynatrace.addHttpEventModifier { event, context in
// Access request details from the context
if let request = context?.request {
// Add custom headers or request info as properties
if let customHeader = request.value(forHTTPHeaderField: "X-Custom-Header") {
event.fields["event_properties.custom_header"] = customHeader
}
}
// Access response details
if let httpResponse = context?.response as? HTTPURLResponse {
if let serverTiming = httpResponse.value(forHTTPHeaderField: "Server-Timing") {
event.fields["event_properties.server_timing"] = serverTiming
}
}
// Return the modified event (or nil to drop it)
return event
}

Available context properties

The DTXHttpRequestEventContext provides access to:

PropertyTypeDescription
requestURLRequestThe original request
responseURLResponse?The server response (if available)
responseBodyData?The response body data (if captured)
errorNSError?The error (if the request failed)

Remove a modifier

When you no longer need the modifier, remove it using the subscriber reference:

Dynatrace.removeEventModifier(subscriber)

Filter requests

Return nil from the modifier to prevent the event from being sent:

let subscriber = Dynatrace.addHttpEventModifier { event, context in
// Don't report requests to analytics endpoints
if let url = context?.request.url?.absoluteString,
url.contains("analytics.example.com") {
return nil
}
return event
}
Related tags
Digital Experience