Firebase Remote Config Integration in Mobile Applications
App is released, but a week later marketing asks to change button color, banner text, or free delivery threshold. Without Remote Config — this is a hotfix, review, release, waiting for moderation. With it — a change in Firebase Console that goes to production in minutes.
How Remote Config Works Under the Hood
Remote Config is a Key-Value store with server side in Firebase Console and client SDK on iOS/Android/Flutter. On app startup, it requests fresh values, Firebase returns a JSON package, SDK caches it locally. If network is unavailable — last cached values or built-in defaults are used.
Key point: fetch() and activate() are two separate actions. fetch downloads config to staging cache, activate applies it at runtime. This split is intentional — to not break current user session by applying new config mid-work.
// iOS, Swift
let remoteConfig = RemoteConfig.remoteConfig()
let settings = RemoteConfigSettings()
settings.minimumFetchInterval = 3600 // in production — 1 hour, in debug can be 0
remoteConfig.configSettings = settings
// Defaults are mandatory, otherwise values are nil until first fetch
remoteConfig.setDefaults(fromPlist: "RemoteConfigDefaults")
remoteConfig.fetchAndActivate { status, error in
if status == .successFetchedFromRemote || status == .successUsingPreFetchedData {
let buttonColor = remoteConfig["promo_button_color"].stringValue ?? "#FF5722"
DispatchQueue.main.async { self.applyConfig(buttonColor) }
}
}
On Android via Kotlin:
val remoteConfig = Firebase.remoteConfig
remoteConfig.setConfigSettingsAsync(remoteConfigSettings {
minimumFetchIntervalInSeconds = 3600
})
remoteConfig.setDefaultsAsync(R.xml.remote_config_defaults)
remoteConfig.fetchAndActivate().addOnCompleteListener { task ->
if (task.isSuccessful) {
val threshold = remoteConfig.getLong("free_delivery_threshold")
updateCartUI(threshold)
}
}
Where It Breaks in Practice
Cache and minimumFetchInterval. In production, Firebase strictly limits request frequency: 5 fetch requests per hour per device. Exceeding returns ThrottledException. Teams often hit this in QA: tester updates value in console, but app continues showing old data. Solution — in debug builds set minimumFetchIntervalInSeconds = 0, in production leave 3600.
Defaults not set. If before first successful fetch (e.g., no internet) you access a key without default — you get nil or empty string. App doesn't crash, but behavior is unpredictable. Defaults must cover all keys the app uses.
Race condition on startup. fetchAndActivate is asynchronous. If UI renders before fetch completes, user sees default values. For critical parameters (e.g., paywall display flag), load config on splash screen and block transition with 2–3 second timeout.
Conditional Values and Segmentation
Real Remote Config power — conditions. You can set different values for:
- specific app versions (
app_version < 2.5.0) - platform (iOS vs Android)
- user country
- arbitrary
user_propertyset via Firebase Analytics
For example, show new onboarding only to iOS 16+ users in Russia — without separate release.
What's Included in Work
- Firebase SDK connection (via SPM on iOS, Gradle on Android,
firebase_remote_configon Flutter) -
RemoteConfigSettingsconfiguration with correct intervals for debug/release - Defaults file covering all keys
- Helper class with typed value access (no string keys in code)
- Integration with app initialization point (AppDelegate / Application)
Timeline
Basic integration with typed helper: 1 day. Cost estimated individually after requirement analysis.







