Skip to content

fix(replay): stop session replay when over the mobile recordings quota - #825

Merged
arnohillen merged 1 commit into
mainfrom
posthog/stop-replay-on-mobile-quota
Sep 29, 2026
Merged

arnohillen merged 1 commit into
mainfrom
posthog/stop-replay-on-mobile-quota

Conversation

@arnohillen

@arnohillen arnohillen commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

💡 Motivation and Context

Session replay now stops when the project is over its mobile session replay quota.

  • The PostHog server now reports a separate mobile session replay quota as quotaLimited: ["mobile_recordings"] in remote config. Server change: PostHog/posthog#103077.
  • The server keeps sessionRecording enabled in that case, because web recording is still allowed.
  • Before this change, the SDK kept recording, and capture dropped the data server side.

Changes:

  • When /config has quotaLimited with mobile_recordings, the SDK handles sessionRecording as false. Replay turns off, the cached recording config is removed, and the SDK logs a message.
  • When a later /config does not report it, replay behaves normally again.
  • Older servers never send the value, so their behavior does not change.
  • quotaLimited moves from PostHogFlagsResponse to its base class PostHogRemoteConfigResponse, so /config responses parse it too. /flags responses still expose it through inheritance. Declaring it on both classes is not possible, because Gson rejects two fields with the same JSON name in one class hierarchy. Both classes are @PostHogInternal. The posthog.api diff shows the constructor and componentN changes on PostHogFlagsResponse.

💚 How did you test it?

  • New test in PostHogRemoteConfigTest: a /config with a normal sessionRecording object and quotaLimited: ["mobile_recordings"] leaves replay inactive and evicts the cache. A second /config without it makes replay active again.
  • The new test fails without the change in PostHogRemoteConfig.kt (assertFalse(sut.isSessionReplayFlagActive())).
  • ./gradlew :posthog:test --tests 'com.posthog.internal.PostHogRemoteConfigTest': 111 tests pass.
  • PostHogFeatureFlagsTest, PostHogFeatureFlagsV1Test and PostHogApiTest in posthog pass. They cover quotaLimited: ["feature_flags"] on /flags.
  • FeatureFlagErrorTrackingTest and PostHogEvaluateFlagsTest in posthog-server pass.
  • spotlessCheck passes. apiDump regenerated posthog/api/posthog.api.

📝 Checklist

  • I reviewed the submitted code.
  • I added tests to verify the changes.
  • I updated the docs if needed.
  • No breaking change or entry added to the changelog.

If releasing new changes

  • Ran pnpm changeset to generate a changeset file

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

  • Written with PostHog Desktop (model: Claude Opus 5.5).
  • The check sits where /config session recording is processed, and reuses the existing sessionRecording: false path. The flags re-arm path and cold start read the cached recording config, so they stay off with no extra checks.
  • No sdk-specs capability covers quotaLimited, so no spec divergence applies.

Created with PostHog Desktop

The server reports the mobile session replay quota as
`quotaLimited: ["mobile_recordings"]` in remote config and keeps
`sessionRecording` set, because web shares that field. Treat the value
the same as `sessionRecording: false`. `quotaLimited` moves to
`PostHogRemoteConfigResponse` so `/config` responses parse it.

Generated-By: PostHog Desktop
Task-Id: f115d189-5362-410f-9778-f87e6f59f5d6
@greptile-apps

greptile-apps Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Retrigger

[Medium risk] Session replay disables when mobile recordings quota is exceeded.

The PR appears safe to merge; no actionable regression was identified.

Reviews (1) · Last reviewed commit: "fix(replay): stop session replay when ov..."

@arnohillen
arnohillen requested review from a team, TueHaulund, fasyy612 and ksvat and removed request for a team September 29, 2026 22:11
@github-actions

Copy link
Copy Markdown
Contributor

posthog-android Compliance Report

Date: 2026-09-29 22:12:14 UTC
Duration: 118329ms

✅ All Tests Passed!

46/46 tests passed


Capture Tests

✅ 29/29 tests passed

View Details
Test Status Duration
Format Validation.Event Has Required Fields ✅ 334ms
Format Validation.Event Has Uuid ✅ 29ms
Format Validation.Event Has Lib Properties ✅ 28ms
Format Validation.Distinct Id Is String ✅ 27ms
Format Validation.Token Is Present ✅ 23ms
Format Validation.Custom Properties Preserved ✅ 26ms
Format Validation.Event Has Timestamp ✅ 26ms
Retry Behavior.Retries On 503 ✅ 7025ms
Retry Behavior.Does Not Retry On 400 ✅ 4025ms
Retry Behavior.Does Not Retry On 401 ✅ 4024ms
Retry Behavior.Respects Retry After Header ✅ 7029ms
Retry Behavior.Implements Backoff ✅ 17034ms
Retry Behavior.Retries On 500 ✅ 7014ms
Retry Behavior.Retries On 502 ✅ 7015ms
Retry Behavior.Retries On 504 ✅ 7016ms
Retry Behavior.Max Retries Respected ✅ 17036ms
Deduplication.Generates Unique Uuids ✅ 38ms
Deduplication.Preserves Uuid On Retry ✅ 7013ms
Deduplication.Preserves Uuid And Timestamp On Retry ✅ 12025ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ✅ 7021ms
Deduplication.No Duplicate Events In Batch ✅ 40ms
Deduplication.Different Events Have Different Uuids ✅ 27ms
Compression.Sends Gzip When Enabled ✅ 21ms
Batch Format.Uses Proper Batch Structure ✅ 19ms
Batch Format.Flush With No Events Sends Nothing ✅ 13ms
Batch Format.Multiple Events Batched Together ✅ 37ms
Error Handling.Does Not Retry On 403 ✅ 4025ms
Error Handling.Does Not Retry On 413 ✅ 4022ms
Error Handling.Retries On 408 ✅ 5030ms

Feature_Flags Tests

✅ 17/17 tests passed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id ✅ 36ms
Request Payload.Flags Request Uses V2 Query Param ✅ 23ms
Request Payload.Flags Request Hits Flags Path Not Decide ✅ 24ms
Request Payload.Flags Request Omits Authorization Header ✅ 23ms
Request Payload.Token In Flags Body Matches Init ✅ 22ms
Request Payload.Groups Round Trip ✅ 26ms
Request Payload.Groups Default To Empty Object ✅ 25ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False ✅ 25ms
Request Payload.Disable Geoip Omitted Defaults To False ✅ 31ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key ✅ 22ms
Request Lifecycle.No Flags Request On Init Alone ✅ 8ms
Request Lifecycle.No Flags Request On Normal Capture ✅ 21ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests ✅ 34ms
Request Lifecycle.Mock Response Value Is Returned To Caller ✅ 23ms
Retry Behavior.Retries Flags On 502 ✅ 329ms
Retry Behavior.Retries Flags On 504 ✅ 323ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event ✅ 20ms

@arnohillen
arnohillen marked this pull request as ready for review September 29, 2026 22:25
@arnohillen
arnohillen merged commit 572b972 into main Sep 29, 2026
18 checks passed
@arnohillen
arnohillen deleted the posthog/stop-replay-on-mobile-quota branch September 29, 2026 23:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants