Skip to content

[Bug] Mobile remote config can return sessionRecording=false due to a cache that doesn't vary by User-Agent #74510

Open

Description

@jmlopezz

Bug Description

The public endpoint /array/<project_token>/config decides whether to deliver the mobile Session Replay configuration using the User-Agent, but the cacheable response doesn't include User-Agent in Vary.

As a result, a non-mobile request can store sessionRecording: false in the shared bucket. A native SDK that immediately queries the same URL receives that value as a cache HIT, even if the project has mobile Replay enabled.

This was reproduced on PostHog Cloud US on 2026-07-29. No tokens or project identifiers are included.

How to reproduce

Use a Project API Key from a project with Session Replay enabled and allowed for mobile SDKs. The random query string avoids affecting the canonical bucket consumed by real users:

BASE="https://us-assets.i.posthog.com/array/<project_token>/config"
PROBE="<random-value>"

# 1. Client not recognized as mobile
curl -sS -D headers-non-mobile.txt \
  "$BASE?cache_probe=$PROBE" \
  -o body-non-mobile.json

# 2. Same exact URL, now with a React Native User-Agent
curl -sS -D headers-mobile-hit.txt \
  -H "User-Agent: posthog-react-native/4.61.1" \
  "$BASE?cache_probe=$PROBE" \
  -o body-mobile-hit.json

# 3. New bucket requested first by the mobile client
curl -sS -D headers-mobile-miss.txt \
  -H "User-Agent: posthog-react-native/4.61.1" \
  "$BASE?cache_probe=<another-random-value>" \
  -o body-mobile-miss.json

Observed result:

  1. The non-mobile request returns sessionRecording: false.
  2. The mobile request to the same URL returns CF-Cache-Status: HIT and also sessionRecording: false.
  3. The mobile request to a new bucket returns the full Replay configuration.
  4. The response uses Cache-Control: public, max-age=300.
  5. Vary includes signals like Origin/Referer and CORS headers, but not User-Agent.

Expected result

Two requests that can receive different responses based on their authorization/classification signal should not share the same cache entry. The cache should vary by the relevant signal, or the decision to enable Replay should not depend on a header excluded from the cache key.

Impact

Native iOS/Android/React Native SDKs query remote config without an Origin and are identified as mobile via User-Agent. A bucket previously populated by another client can disable Session Replay for the duration of the TTL, even when:

  • session_recording_opt_in is enabled;
  • the project has valid mobile triggers;
  • the SDK and native plugin are correctly installed.

The same remote response also participates in native capture activation, which makes the behavior hard to diagnose from the app.

Additional context

The backend logic recognizes mobile SDKs by User-Agent in:

https://github.com/PostHog/posthog/blob/50b83035a2b04531a8443542cf8cdf84e46c0424/rust/feature-flags/src/handler/session_recording.rs

A local mitigation based on removing domain/origin restrictions would widen the capture scope and doesn't seem like a safe alternative. The fix should preserve the current restrictions.

Debug info

- [x] PostHog Cloud US
- [x] Reproduced with posthog-react-native/4.61.1
- [x] Endpoint: /array/<project_token>/config
- [x] Project token and identifiers deliberately omitted

Activity

  1. changed the title [-][Bug] Remote config móvil puede devolver sessionRecording=false por una caché que no varía por User-Agent[/-] [+][Bug] Mobile remote config can return sessionRecording=false due to a cache that doesn't vary by User-Agent[/+] on Jul 31, 2026
  2. removed their assignment
    on Aug 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions