Describe the bug
DdRumResourceTracking captures resources by proxying XMLHttpRequest (XHRProxy), relying on React Native's whatwg-fetch polyfill being XHR-backed so that fetch traffic is captured too.
Since Expo SDK 56, Expo's WinterCG runtime installs expo/fetch as global.fetch at startup (expo/src/winter/runtime.native.ts — install('fetch', () => require('./fetch').fetch), gated only by the EXPO_PUBLIC_USE_RN_FETCH escape hatch). expo/fetch is a native implementation: OkHttp on Android (expo/modules/fetch/ExpoFetchModule.kt, using OkHttpClientProvider.createClient — no Datadog interceptor), URLSession on iOS.
The result is platform-asymmetric and easy to miss:
- Android: every request made through
fetch (e.g. all Apollo/GraphQL traffic) produces no RUM resource events at all. Only libraries that still use XHR directly (e.g. axios) remain visible. No errors, no logs — the events just stop.
- iOS: resources still appear, but only because the native iOS SDK swizzles
URLSession, which happens to cover expo/fetch. They are captured at the native layer rather than through the RN SDK's resource-tracking path (so RN-level features tied to the JS interception, like the resourceEventMapper and first-party-host header injection from JS, no longer apply to them).
Consequences beyond missing timings: @view.network_settled_time on Android is computed from an empty resource set, and Datadog trace-context headers are no longer injected into first-party fetch requests on Android, breaking RUM↔APM correlation.
In our production app the Android resources-per-view rate dropped ~98% (from ~2–3 to ~0.03) the exact release we upgraded Expo 55 → 56, with iOS flat across the same boundary. The surviving Android resources map exactly to our axios (XHR) call sites.
Reproduction steps
- Create an Expo SDK 56+ app (bare or CNG) with
@datadog/mobile-react-native, RUM enabled with trackResources: true / RumConfiguration(..., trackXHRResources: true).
- Make any request with
fetch("https://example.com") (or any fetch-based client such as Apollo).
- On Android: no
resource event is emitted. Adding SdkVerbosity.DEBUG shows startResource is never called.
- Confirm the cause:
global.fetch is expo/fetch (its module source is expo/src/winter/fetch/fetch.ts, not whatwg-fetch), so XMLHttpRequest is never touched by the request.
- Rebuild with the env var
EXPO_PUBLIC_USE_RN_FETCH=1 set at bundle time — global.fetch stays RN's XHR-backed polyfill and resource events return. This is our current workaround.
SDK logs
With SdkVerbosity.DEBUG: user actions and long tasks log normally; no Starting RUM Resource lines are ever emitted for fetch traffic on Android.
Expected behavior
Either resource tracking captures expo/fetch traffic (e.g. by wrapping global.fetch/expo/fetch in addition to proxying XHR, or by documenting a supported OkHttp interception path for Expo's client on Android), or the limitation is called out loudly in the docs — the current failure mode is fully silent and, because iOS keeps working via URLSession swizzling, it's easy to attribute the Android gap to anything but the SDK.
Given that Expo has made expo/fetch the default and the escape hatch is explicitly temporary, XHR-only interception effectively means "no fetch resource tracking on current Expo" going forward.
Affected SDK versions
3.4.0–3.5.4 (all current versions; the trigger is the Expo SDK 56+ runtime, not an SDK change)
Latest working SDK version
Any version, when running on Expo SDK ≤ 55 (or with EXPO_PUBLIC_USE_RN_FETCH=1 on 56+)
Did you confirm if the latest SDK version fixes the bug?
Yes (3.5.4 still tracks resources exclusively via the XHR proxy)
Integration Methods
Yarn
React Native Version
0.85.3 (Expo SDK 57; also reproduced on Expo SDK 56 / RN 0.85)
Platform
Android (fully missing), iOS (captured only via native URLSession swizzling, bypassing RN-level resource tracking)
Describe the bug
DdRumResourceTrackingcaptures resources by proxyingXMLHttpRequest(XHRProxy), relying on React Native'swhatwg-fetchpolyfill being XHR-backed so thatfetchtraffic is captured too.Since Expo SDK 56, Expo's WinterCG runtime installs
expo/fetchasglobal.fetchat startup (expo/src/winter/runtime.native.ts—install('fetch', () => require('./fetch').fetch), gated only by theEXPO_PUBLIC_USE_RN_FETCHescape hatch).expo/fetchis a native implementation: OkHttp on Android (expo/modules/fetch/ExpoFetchModule.kt, usingOkHttpClientProvider.createClient— no Datadog interceptor),URLSessionon iOS.The result is platform-asymmetric and easy to miss:
fetch(e.g. all Apollo/GraphQL traffic) produces no RUM resource events at all. Only libraries that still use XHR directly (e.g. axios) remain visible. No errors, no logs — the events just stop.URLSession, which happens to coverexpo/fetch. They are captured at the native layer rather than through the RN SDK's resource-tracking path (so RN-level features tied to the JS interception, like theresourceEventMapperand first-party-host header injection from JS, no longer apply to them).Consequences beyond missing timings:
@view.network_settled_timeon Android is computed from an empty resource set, and Datadog trace-context headers are no longer injected into first-partyfetchrequests on Android, breaking RUM↔APM correlation.In our production app the Android resources-per-view rate dropped ~98% (from ~2–3 to ~0.03) the exact release we upgraded Expo 55 → 56, with iOS flat across the same boundary. The surviving Android resources map exactly to our axios (XHR) call sites.
Reproduction steps
@datadog/mobile-react-native, RUM enabled withtrackResources: true/RumConfiguration(..., trackXHRResources: true).fetch("https://example.com")(or anyfetch-based client such as Apollo).resourceevent is emitted. AddingSdkVerbosity.DEBUGshowsstartResourceis never called.global.fetchisexpo/fetch(its module source isexpo/src/winter/fetch/fetch.ts, notwhatwg-fetch), soXMLHttpRequestis never touched by the request.EXPO_PUBLIC_USE_RN_FETCH=1set at bundle time —global.fetchstays RN's XHR-backed polyfill and resource events return. This is our current workaround.SDK logs
With
SdkVerbosity.DEBUG: user actions and long tasks log normally; noStarting RUM Resourcelines are ever emitted forfetchtraffic on Android.Expected behavior
Either resource tracking captures
expo/fetchtraffic (e.g. by wrappingglobal.fetch/expo/fetchin addition to proxying XHR, or by documenting a supported OkHttp interception path for Expo's client on Android), or the limitation is called out loudly in the docs — the current failure mode is fully silent and, because iOS keeps working viaURLSessionswizzling, it's easy to attribute the Android gap to anything but the SDK.Given that Expo has made
expo/fetchthe default and the escape hatch is explicitly temporary, XHR-only interception effectively means "no fetch resource tracking on current Expo" going forward.Affected SDK versions
3.4.0–3.5.4 (all current versions; the trigger is the Expo SDK 56+ runtime, not an SDK change)
Latest working SDK version
Any version, when running on Expo SDK ≤ 55 (or with
EXPO_PUBLIC_USE_RN_FETCH=1on 56+)Did you confirm if the latest SDK version fixes the bug?
Yes (3.5.4 still tracks resources exclusively via the XHR proxy)
Integration Methods
Yarn
React Native Version
0.85.3 (Expo SDK 57; also reproduced on Expo SDK 56 / RN 0.85)
Platform
Android (fully missing), iOS (captured only via native URLSession swizzling, bypassing RN-level resource tracking)