Skip to content

Comments

chore(flags): prefer remote config over flags config parameter#421

Open
dmarticus wants to merge 9 commits intomainfrom
chore/prefer-remote-config
Open

chore(flags): prefer remote config over flags config parameter#421
dmarticus wants to merge 9 commits intomainfrom
chore/prefer-remote-config

Conversation

@dmarticus
Copy link
Contributor

@dmarticus dmarticus commented Feb 16, 2026

Summary

  • Remove config=true parameter from the flags endpoint URL (/flags/?v=2 instead of /flags/?v=2&config=true)
  • Add timezone field to all flags requests
  • Deprecate the remoteConfig config option and make it a no-op (remote config is now always loaded)

Remote config (/array/{apiKey}/config) is now the sole source for configuration data, so the flags endpoint only needs to return feature flags. This aligns the Android SDK with the direction being taken in posthog-js.

Based on PostHog/posthog-js#2895

Changes

File Change
PostHogApi.kt Remove config=true from flags URL
PostHogFlagsRequest.kt Add timezone field (uses TimeZone.getDefault().id)
PostHogConfig.kt (posthog) Deprecate remoteConfig option
PostHogConfig.kt (posthog-server) Deprecate remoteConfig option
PostHog.kt Always load remote config (ignore deprecated option)
Tests Update expected URLs and add @Suppress("DEPRECATION")

Notes

This follows the same pattern as posthog-js:

  • Remote config is loaded once at init
  • reloadFeatureFlags() only reloads feature flags, not the full remote config
  • Session replay config changes don't take effect until the next app restart

This is an acceptable tradeoff for simplicity and reduced API calls.

Test plan

  • CI passes
  • Feature flags still load correctly via remote config flow

@dmarticus dmarticus requested a review from a team as a code owner February 16, 2026 17:11
@github-actions
Copy link
Contributor

github-actions bot commented Feb 16, 2026

posthog-android Compliance Report

Date: 2026-02-18 12:06:50 UTC
Duration: 147040ms

⚠️ Some Tests Failed

17/29 tests passed, 12 failed


Capture Tests

⚠️ 17/29 tests passed, 12 failed

View Details
Test Status Duration
Format Validation.Event Has Required Fields 2322ms
Format Validation.Event Has Uuid 2023ms
Format Validation.Event Has Lib Properties 2021ms
Format Validation.Distinct Id Is String 2021ms
Format Validation.Token Is Present 2019ms
Format Validation.Custom Properties Preserved 2022ms
Format Validation.Event Has Timestamp 2020ms
Retry Behavior.Retries On 503 7025ms
Retry Behavior.Does Not Retry On 400 4022ms
Retry Behavior.Does Not Retry On 401 4023ms
Retry Behavior.Respects Retry After Header 7023ms
Retry Behavior.Implements Backoff 17022ms
Retry Behavior.Retries On 500 7025ms
Retry Behavior.Retries On 502 7019ms
Retry Behavior.Retries On 504 7024ms
Retry Behavior.Max Retries Respected 17033ms
Deduplication.Generates Unique Uuids 2036ms
Deduplication.Preserves Uuid On Retry 7018ms
Deduplication.Preserves Uuid And Timestamp On Retry 12026ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry 7026ms
Deduplication.No Duplicate Events In Batch 2031ms
Deduplication.Different Events Have Different Uuids 2021ms
Compression.Sends Gzip When Enabled 2016ms
Batch Format.Uses Proper Batch Structure 2016ms
Batch Format.Flush With No Events Sends Nothing 2013ms
Batch Format.Multiple Events Batched Together 2028ms
Error Handling.Does Not Retry On 403 4019ms
Error Handling.Does Not Retry On 413 4020ms
Error Handling.Retries On 408 7025ms

Failures

retry_behavior.retries_on_503

Expected at least 3 requests, got 1

retry_behavior.respects_retry_after_header

Expected at least 2 requests, got 1

retry_behavior.implements_backoff

Expected at least 3 requests, got 1

retry_behavior.retries_on_500

Expected at least 2 requests, got 1

retry_behavior.retries_on_502

Expected at least 2 requests, got 1

retry_behavior.retries_on_504

Expected at least 2 requests, got 1

retry_behavior.max_retries_respected

Expected 4 requests, got 1

deduplication.preserves_uuid_on_retry

Need at least 2 requests to check retry

deduplication.preserves_uuid_and_timestamp_on_retry

Expected at least 3 requests, got 1

deduplication.preserves_uuid_and_timestamp_on_batch_retry

Expected at least 2 requests, got 1

compression.sends_gzip_when_enabled

Header 'Content-Encoding' with value 'gzip' not found in requests

error_handling.does_not_retry_on_413

Expected 1 requests, got 2

@dmarticus dmarticus marked this pull request as draft February 17, 2026 03:52
@dmarticus dmarticus force-pushed the chore/prefer-remote-config branch from 435edda to 6a2bc5f Compare February 17, 2026 05:31
Remove `config=true` parameter from the flags endpoint URL. Remote config
(`/array/{apiKey}/config`) is now the sole source for configuration data,
so the flags endpoint only needs to return feature flags.

Also adds `timezone` field to all flags requests, aligning with posthog-js.

Based on PostHog/posthog-js#2895

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@dmarticus dmarticus force-pushed the chore/prefer-remote-config branch from 6a2bc5f to c05b926 Compare February 17, 2026 05:33
@marandaneto
Copy link
Member

so we have this

/**
* Preload PostHog remote config automatically
* Defaults to true
*/
public var remoteConfig: Boolean = true,
which was added when remote config was still not considered GA
what we can do is to deprecate this and make it a noop, removing it would break builds

the only problem i see is that if session replay has changed its flags conditions, eg session recording was enabled and now it is disabled, we wont know unless we call remote config again for every reloadfeatureflags() call.

are we ok with keeping session replay running even if it should not or are we ok calling remote config again for every reloadfeatureflags() call?

dmarticus and others added 3 commits February 17, 2026 12:00
- Resolve merge conflict with #415 in CHANGELOG
- Deprecate `remoteConfig` config option (now always enabled)
- Simplify PostHog.kt to always load remote config
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@dmarticus
Copy link
Contributor Author

so we have this

/**
* Preload PostHog remote config automatically
* Defaults to true
*/
public var remoteConfig: Boolean = true,

which was added when remote config was still not considered GA
what we can do is to deprecate this and make it a noop, removing it would break builds
the only problem i see is that if session replay has changed its flags conditions, eg session recording was enabled and now it is disabled, we wont know unless we call remote config again for every reloadfeatureflags() call.

are we ok with keeping session replay running even if it should not or are we ok calling remote config again for every reloadfeatureflags() call?

This follows the same pattern as posthog-js, where:

  1. Remote config is loaded once at init
  2. reloadFeatureFlags() only reloads feature flags, not the full remote config
  3. Session replay config changes don't take effect until the next session (page reload/app restart)

We're accepting the same tradeoff here: session replay config staleness until app restart. I think this is a reasonable tradeoff because:

  • Session replay config changes are relatively rare (not something that changes frequently for a given user)
  • It simplifies the SDK logic
  • It reduces API calls to /flags
  • It matches the behavior users already experience with posthog-js

If we wanted session replay config to be more responsive, we could add periodic remote config refresh (e.g., every 5 minutes), but that adds complexity and battery/network overhead for a rare scenario. We can always add that later if it becomes a real need.

TL;DR – let's do it this way for now. But open to pushback!

@dmarticus dmarticus marked this pull request as ready for review February 17, 2026 20:17
The remoteConfig option is deprecated but still functional. Making it a
complete no-op would require significant test updates. For now, the
option works as before but shows a deprecation warning.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
init {
this["api_key"] = apiKey
this["distinct_id"] = distinctId
this["timezone"] = TimeZone.getDefault().id
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whats the expectation here? this would return eg Europe/Vienna

@marandaneto marandaneto requested a review from a team February 18, 2026 11:58
@marandaneto
Copy link
Member

@ioannisj can you review this since i've done many changes to account for the behaviour changes

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