Migrating from Firebase is a one-click config import, the API your code already calls, and a diff that is mostly a class name. The only change on your bill is that there is no bill.
val config = Firebase.remoteConfig config.setDefaultsAsync(defaults) config.fetchAndActivate() .addOnCompleteListener { /* initialization complete */ } val paywall = config.getBoolean("paywall_enabled") val message = config.getString("welcome_message")
val config = AppSpikeRemoteConfig config.setDefaults(defaults) scope.launch { config.fetchAndActivate() } // initialization complete val paywall = config.getBoolean("paywall_enabled") val message = config.getString("welcome_message")
let config = RemoteConfig.remoteConfig() config.setDefaults(["paywall_enabled": false as NSObject]) config.fetchAndActivate { status, error in /* initialization complete */ } let paywall = config["paywall_enabled"].boolValue let message = config["welcome_message"].stringValue
let config = AppSpike.remoteConfig() config.setDefaults(["paywall_enabled": false]) try await config.fetchAndActivate() // initialization complete let paywall = config["paywall_enabled"].boolValue let message = config["welcome_message"].stringValue
NSObject casts), completion handlers become async/await, and a @RemoteConfigProperty wrapper is available for SwiftUI.final config = FirebaseRemoteConfig.instance; await config.setDefaults({'paywall_enabled': false}); await config.fetchAndActivate(); final paywall = config.getBool('paywall_enabled'); final message = config.getString('welcome_message');
final config = AppSpikeRemoteConfig.instance; await config.setDefaults({'paywall_enabled': false}); await config.fetchAndActivate(); final paywall = config.getBool('paywall_enabled'); final message = config.getString('welcome_message');
firebase_remote_config method-for-method. The class name changes, and firebase_core is removed from your dependencies.import remoteConfig from '@react-native-firebase/remote-config'; await remoteConfig().setDefaults({ paywall_enabled: false }); await remoteConfig().fetchAndActivate(); const paywall = remoteConfig().getBoolean('paywall_enabled'); const message = remoteConfig().getString('welcome_message');
import { remoteConfig } from '@appspike/react-native-remote-config'; await remoteConfig().setDefaults({ paywall_enabled: false }); await remoteConfig().fetchAndActivate(); const paywall = remoteConfig().getBoolean('paywall_enabled'); const message = remoteConfig().getString('welcome_message');
var config = FirebaseRemoteConfig.DefaultInstance; await config.SetDefaultsAsync(defaults); await config.FetchAndActivateAsync(); var paywall = config.GetValue("paywall_enabled").BooleanValue; var message = config.GetValue("welcome_message").StringValue;
var config = AppSpikeRemoteConfig.DefaultInstance; await config.SetDefaultsAsync(defaults); await config.FetchAndActivateAsync(); var paywall = config.GetValue("paywall_enabled").BooleanValue; var message = config.GetValue("welcome_message").StringValue;
import { initializeApp } from 'firebase/app'; import { fetchAndActivate, getBoolean, getRemoteConfig } from 'firebase/remote-config'; const rc = getRemoteConfig(initializeApp(firebaseConfig)); await fetchAndActivate(rc); const paywall = getBoolean(rc, 'paywall_enabled');
import { initializeApp } from '@appspike/web/app'; import { fetchAndActivate, getBoolean, getRemoteConfig } from '@appspike/web/remote-config'; const rc = getRemoteConfig(initializeApp({ apiKey })); await fetchAndActivate(rc); const paywall = getBoolean(rc, 'paywall_enabled');
AppSpike is built by Pyde Technologies, app developers first. Our own apps, PokeRaid and PokeTrade, two of the most popular apps in their category, run on the same SDK we ship to you. Remote Config exists because when Firebase's usage-based pricing was announced, our own projected config bill came to about $25,000 a year. We built this to make that bill $0, then opened it to everyone.
AppSpike's business is built on its ad revenue optimization platform. Remote Config is free because it makes the platform more useful. There is no per-fetch billing waiting for you at scale, and no premium tier that hides features you will need later.
You don't need to use AppSpike ads to use Remote Config. Initialize the SDK in config-only mode and your existing ad stack stays untouched.
Unlimited fetches. Unlimited parameters (up to the 3,000-parameter engineering limit). All targeting conditions. Version history and rollback. Firebase config import. Every platform we ship.
Some Remote Config users try our ad optimization later. That is the whole business model. If you never do, the config service still costs us close to nothing to run. Your config is served as static, CDN-cached JSON, and evaluation happens on your users' devices, not our servers.
If you are under 100K fetches a day, Firebase costs you nothing today. The bill starts when your app grows. As of September 2026, Firebase bills $0.06 per 10K fetches beyond the daily free tier.
| Config Fetches / Day | Firebase / Year | AppSpike / Year |
|---|---|---|
| 100K | $0 (inside the free tier) | $0 |
| 500K | ~$876 | $0 |
| 2M | ~$4,161 | $0 |
| 10M | ~$21,681 | $0 |
A full 365-day year at Firebase's published overage rate. Your fetch volume depends on how often each device fetches. Foreground refreshes, shorter intervals, and realtime reconnects push the Firebase figure up, never down.
A config bill that grows with your user count means you pay more for being successful. AppSpike serves your config as immutable, CDN-cached files that are evaluated on the device. That costs almost nothing, so we don't meter it.
You can export your Firebase config, but no other tool can import it. AppSpike imports your Firebase config in one click, and your AppSpike config is plain JSON you can export and take with you at any time. Leaving should stay easy forever, not only joining.
Firebase uploads your custom signals (subscription tier, player level, whatever you target on) to Google with every fetch. AppSpike evaluates conditions on the device, so signals never leave the phone. Same targeting, no transmission.
You can only trust config infrastructure if you know how it behaves during failures. Here are the exact answers.
Your app keeps running on the last activated config, which is persisted on the device. Keys that were never fetched resolve to the in-app defaults you set with setDefaults. A failed fetch never degrades a running app. It's the same offline model Firebase uses.
Every publish is an immutable version. The dashboard diffs any two versions and rolls back in one click. The rollback itself is just a new publish, fully audited with author and timestamp.
The Firebase and AppSpike SDKs coexist in one app with different artifacts and different storage. Run both during the rollout, control which one is read with a flag, and move traffic 5% → 50% → 100% before removing Firebase. The migration guide documents this pattern end to end.
Your config is plain JSON. Parameters, conditions, and version history are yours to export at any time. We want the product to keep you, not the cost of leaving.
Each SDK mirrors the Firebase SDK of its own platform: Firebase Android naming on Android and KMP, a native Swift API on iOS, the firebase_remote_config Dart surface on Flutter, the @react-native-firebase shape on React Native, the Firebase Unity API in C#, and the modular firebase/remote-config functions on the web. Call sites translate one-to-one.
Country, language, platform, app version and build, percentage rollouts with stable bucketing, custom signals, time windows, install cohorts, and per-device targeting. First matching condition wins, the same mental model as Firebase.
Upload your exported Firebase config. Parameters, conditions, groups, tag colors, and ordering carry over. Anything unconvertible is flagged in a warning report instead of silently dropped. Nothing publishes until you review the diff.
iOS gets subscripts, a @RemoteConfigProperty wrapper, and Codable decoding via Swift Package Manager. React Native is pure TypeScript with no native modules, so it runs in Expo Go. Flutter is pure Dart with no firebase_core. The web package has zero runtime dependencies. No google-services files anywhere.
The SDK is KMP at its core. Add one dependency to commonMain and read config from shared code across Android, iOS, and wasmJs. No other config provider ships this natively.
Draft → diff → publish. Every version is immutable with author and timestamp. Select any two to diff, and roll back in one click. Nothing reaches devices until you publish.
Including the things Firebase does that we don't do yet. You would find out anyway, so it is better to learn it here than in production.
| Capability | Firebase Remote Config | AppSpike Remote Config |
|---|---|---|
| Price at scale | 100K fetches/day free, then $0.06 per 10K | Free, no fetch metering |
| Client API | Platform-specific SDKs | Same as Firebase |
| Config import | ✗ No import path from other providers | ✓ One-click import from Firebase |
| Condition evaluation | On Google's servers | On the device, where you can inspect it |
| Custom signals | Uploaded with every fetch | Never leave the device |
| Percentage rollouts | ✓ | ✓ Stable SHA-256 bucketing |
| Version history & rollback | ✓ | ✓ |
| Real-time config updates | ✓ Real-time Remote Config | ✓ Via data push notifications |
| A/B testing integration | ✓ Firebase A/B Testing | ✓ With percentage conditions |
| Analytics audience targeting | ✓ Google Analytics audiences | ✗ Use custom signals instead |
| Platforms | Android, iOS, Web, Flutter, Unity | Android, iOS, Web, Kotlin Multiplatform, Flutter, React Native, Unity |
| Kotlin Multiplatform | ✗ | ✓ Native |
If your rollout depends on Google Analytics audiences today, Firebase is still the right tool for that piece. The two SDKs work together in one app, so you can migrate everything else first. Comparing more than the two of us? See our roundup of every free Firebase Remote Config alternative, our own included.
Everything you need to integrate AppSpike Remote Config, from installation to production.
Remote Config reuses your AppSpike app API key and device identity, so there are no new credentials. Call AppSpike.initialize with your API key at app startup before fetching, as with the rest of the SDK.
repositories { maven("https://maven.pkg.github.com/pydetech/appspike-sdk-kmp-dist") } dependencies { implementation("dev.appspike:remote-config:1.2.1") }
// Add the AppSpike package dependency .package(url: "https://github.com/pydetech/appspike-sdk-ios-dist", from: "1.0.0") // Add both products to your target .product(name: "AppSpikeSDKCore", package: "appspike-sdk-ios-dist"), .product(name: "AppSpikeRemoteConfig", package: "appspike-sdk-ios-dist")
Distributed via Swift Package Manager. Add AppSpikeSDKCore and AppSpikeRemoteConfig as products.
// commonMain dependencies implementation("dev.appspike:remote-config:1.2.1")
KMP apps add the artifact to the shared source set. Targets Android, iOS, and wasmJs.
dependencies: appspike_remote_config: git: url: https://github.com/pydetech/appspike-sdk-flutter-dist.git ref: 0.1.0
Pure Dart, no Firebase core and no google-services files. The API mirrors firebase_remote_config method-for-method, with AppSpikeRemoteConfig.instance as the entry point.
npm install github:pydetech/appspike-sdk-react-native-dist#0.1.0 npm install @react-native-async-storage/async-storage
Installs as @appspike/react-native-remote-config. Pure TypeScript with no native modules, so it works with any React Native version, Expo (including Expo Go), and Hermes out of the box. The API mirrors @react-native-firebase/remote-config.
{
"dependencies": {
"dev.appspike.sdk-core": "https://github.com/pydetech/appspike-sdk-unity-dist.git?path=dev.appspike.sdk-core#0.1.0",
"dev.appspike.remote-config": "https://github.com/pydetech/appspike-sdk-unity-dist.git?path=dev.appspike.remote-config#0.1.0",
"com.unity.nuget.newtonsoft-json": "3.2.1"
}
}
Requires Unity 2021.3+. List dev.appspike.sdk-core first, since Unity's package manager can't resolve git-to-git dependencies. The API matches Firebase Remote Config for Unity: DefaultInstance, FetchAndActivateAsync(), GetValue().
npm install github:pydetech/appspike-sdk-web-dist#0.1.0
Installs as @appspike/web with zero runtime dependencies, ESM and CommonJS builds, and TypeScript declarations. The modular API mirrors firebase/remote-config, including fetchAndActivate, getValue, and setCustomSignals.
The lifecycle mirrors Firebase exactly: set in-app defaults, optionally configure fetch settings, then fetch and activate.
// 1. Set in-app defaults (persisted across cold starts) AppSpikeRemoteConfig.setDefaults( mapOf( "welcome_message" to "Hello", "paywall_enabled" to false, "max_retries" to 3L, ) ) // 2. Fetch and activate scope.launch { try { AppSpikeRemoteConfig.fetchAndActivate() // initialization complete } catch (e: RemoteConfigThrottledException) { // Within minimum fetch interval, cached config stands } catch (e: RemoteConfigFetchException) { // Network failure, previously activated config stays } } // 3. Read values, same names as Firebase val msg = AppSpikeRemoteConfig.getString("welcome_message") val enabled = AppSpikeRemoteConfig.getBoolean("paywall_enabled") val retries = AppSpikeRemoteConfig.getLong("max_retries")
let config = AppSpike.remoteConfig() // 1. Set in-app defaults config.setDefaults([ "welcome_message": "Hello", "paywall_enabled": false, "max_retries": 3, ]) // 2. Fetch and activate do { try await config.fetchAndActivate() // initialization complete } catch is RemoteConfigThrottledError { // Within minimum fetch interval, cached config stands } catch { // Network failure, previously activated config stays } // 3. Read values with the native Swift subscript API let msg = config["welcome_message"].stringValue let enabled = config["paywall_enabled"].boolValue let retries = config["max_retries"].numberValue
// Shared code, same API on Android, iOS, and wasmJs // 1. Set in-app defaults (persisted across cold starts) AppSpikeRemoteConfig.setDefaults( mapOf( "welcome_message" to "Hello", "paywall_enabled" to false, "max_retries" to 3L, ) ) // 2. Fetch and activate from any coroutine scope scope.launch { try { AppSpikeRemoteConfig.fetchAndActivate() // initialization complete } catch (e: RemoteConfigThrottledException) { // Within minimum fetch interval, cached config stands } catch (e: RemoteConfigFetchException) { // Network failure, previously activated config stays } } // 3. Read values from common code, same names as Firebase val msg = AppSpikeRemoteConfig.getString("welcome_message") val enabled = AppSpikeRemoteConfig.getBoolean("paywall_enabled") val retries = AppSpikeRemoteConfig.getLong("max_retries")
final remoteConfig = AppSpikeRemoteConfig.instance; // 1. Set in-app defaults (persisted, used before the first fetch) await remoteConfig.setDefaults(const { 'welcome_message': 'Hello', 'paywall_enabled': false, 'max_retries': 3, }); // 2. Fetch and activate await remoteConfig.fetchAndActivate(); // initialization complete // 3. Read values, same names as firebase_remote_config final message = remoteConfig.getString('welcome_message'); final paywall = remoteConfig.getBool('paywall_enabled'); final retries = remoteConfig.getInt('max_retries');
// 1. Set in-app defaults await remoteConfig().setDefaults({ welcome_message: 'Hello', paywall_enabled: false, max_retries: 3, }); // 2. Fetch and activate await remoteConfig().fetchAndActivate(); // initialization complete // 3. Read values, same names as @react-native-firebase const message = remoteConfig().getString('welcome_message'); const paywall = remoteConfig().getBoolean('paywall_enabled'); const retries = remoteConfig().getNumber('max_retries');
var remoteConfig = AppSpikeRemoteConfig.DefaultInstance; // 1. Set in-app defaults await remoteConfig.SetDefaultsAsync(new Dictionary<string, object> { { "welcome_message", "Hello" }, { "paywall_enabled", false }, { "max_retries", 3L }, }); // 2. Fetch and activate await remoteConfig.FetchAndActivateAsync(); // 3. Read values, same names as Firebase for Unity var message = remoteConfig.GetValue("welcome_message").StringValue; var paywall = remoteConfig.GetBoolean("paywall_enabled"); var retries = remoteConfig.GetLong("max_retries");
const app = initializeApp({ apiKey: 'YOUR_API_KEY' }); const remoteConfig = getRemoteConfig(app); // 1. Set in-app defaults remoteConfig.defaultConfig = { welcome_message: 'Hello', paywall_enabled: false, max_retries: 3, }; // 2. Fetch and activate await fetchAndActivate(remoteConfig); // 3. Read values, same modular API as firebase/remote-config const message = getString(remoteConfig, 'welcome_message'); const paywall = getBoolean(remoteConfig, 'paywall_enabled'); const retries = getNumber(remoteConfig, 'max_retries');
Your app now reads config from AppSpike. Values resolve in this order: remote → in-app default → type zero-value (empty string, false, 0). Accessors never block the calling thread. They read from an in-memory cache and are safe on the main thread.
Every accessor and lifecycle method, all targeting conditions, percentage rollout mechanics, and config limits.
Steps 1 and 2 don't touch your app. Import your Firebase config, look around the dashboard, and decide with your actual config in front of you.
Either path gives you the same JSON file with your parameters, conditions, and groups.
From the Firebase console: open Remote Config, click the ⋮ menu at the top of the Parameters page, and choose Download current config file.
Or from the terminal:
firebase remoteconfig:get -o template.json
Go to Remote Config → Import in the AppSpike console and upload your template.json. The importer runs a dry-run first, asks you to map Firebase app IDs to AppSpike apps, and shows a diff before applying. Anything it can't convert is flagged in a warning report, never silently dropped. Nothing reaches devices until you publish.
The mapping is nearly 1:1 on every platform. Pick yours:
| Firebase (Kotlin) | AppSpike (Kotlin) |
|---|---|
Firebase.remoteConfig | AppSpikeRemoteConfig (singleton object) |
setDefaultsAsync(map) | setDefaults(map) |
setConfigSettingsAsync(settings) | setConfigSettings(settings) |
fetchAndActivate() → Task<Boolean> | suspend fetchAndActivate(): Boolean |
getString / getBoolean / getLong / getDouble / getValue / getAll | Identical names |
setCustomSignals(signals) | Identical, same builder pattern |
addOnConfigUpdateListener | Identical, updates arrive via data push notifications |
FirebaseRemoteConfigFetchThrottledException | RemoteConfigThrottledException |
The one mechanical change: Firebase's Task-returning …Async methods become suspend functions, so replace .addOnCompleteListener { } chains with a coroutine.
The SDK is Kotlin Multiplatform at its core, so a KMP app migrates once, in shared code. Add the dependency to commonMain and move your config reads behind a shared interface. The API is the same Firebase-style surface as on Android, callable from Android, iOS, and wasmJs targets.
// commonMain dependencies implementation("dev.appspike:remote-config:1.2.1") // shared code, same API as Android val paywall = AppSpikeRemoteConfig.getBoolean("paywall_enabled")
If today each platform calls Firebase separately, this is the moment to consolidate: port the Android call sites with the mapping in the Android tab, then delete the duplicated iOS config code entirely.
| Firebase (Swift) | AppSpike (Swift) |
|---|---|
RemoteConfig.remoteConfig() | AppSpike.remoteConfig() |
config["key"].stringValue | Identical subscripts |
setDefaults([String: NSObject]) | setDefaults([String: Any]), no NSObject casts |
fetchAndActivate(completionHandler:) | try await fetchAndActivate() |
addOnConfigUpdateListener | AsyncSequence of config updates, delivered via data push notifications |
| NSError with status codes | Typed errors: RemoteConfigThrottledError, RemoteConfigFetchError |
SwiftUI apps can also bind values directly with the @RemoteConfigProperty wrapper, and JSON parameters decode straight to Codable types through the subscript API.
| firebase_remote_config | appspike_remote_config |
|---|---|
FirebaseRemoteConfig.instance | AppSpikeRemoteConfig.instance |
Firebase.initializeApp(options: ...) | AppSpike.instance.initialize(apiKey: ..., modules: [remoteConfig]) |
setDefaults / setConfigSettings / setCustomSignals | Identical |
fetch / activate / fetchAndActivate | Identical |
getString / getBool / getInt / getDouble / getValue / getAll | Identical |
onConfigUpdated stream | Identical, fires on activate |
FirebaseException with codes | RemoteConfigThrottledException / RemoteConfigFetchException |
The value API is identical, so most migrations only touch imports and initialization. Drop firebase_core entirely, since there are no google-services files.
| @react-native-firebase/remote-config | @appspike/react-native-remote-config |
|---|---|
import remoteConfig from '@react-native-firebase/remote-config' | import { AppSpike, appSpikeRemoteConfig, remoteConfig } from '@appspike/react-native-remote-config' |
| Auto-init from google-services files | AppSpike.initialize({ apiKey, modules: [appSpikeRemoteConfig] }) |
getString / getBoolean / getNumber / getValue / getAll | Identical call sites |
setDefaults / setConfigSettings / fetch / activate / fetchAndActivate | Identical |
setDefaultsFromResource(name) | Not supported, pass the object to setDefaults |
onConfigUpdated((event, error) => ...) | onConfigUpdated((event) => ...), no error argument |
Pure TypeScript with no native modules, so there are no pods to reinstall and it runs in Expo Go. getKeysByPrefix is included as an extension beyond the Firebase RN surface.
| Firebase Remote Config (Unity) | AppSpike (Unity) |
|---|---|
FirebaseRemoteConfig.DefaultInstance | AppSpikeRemoteConfig.DefaultInstance |
Firebase.RemoteConfig namespace | AppSpike.RemoteConfig |
google-services.json + CheckAndFixDependenciesAsync() | AppSpikeSdk.InitializeAsync(apiKey, modules) |
SetDefaultsAsync / FetchAsync / ActivateAsync / FetchAndActivateAsync | Identical |
GetValue(key).StringValue, ConfigSettings, Info | Identical |
OnConfigUpdateListener event | Identical, fires on activate |
FirebaseException | RemoteConfigFetchException / RemoteConfigThrottledException |
One helpful difference: ConfigValue accessors never throw. An unconvertible value reads as the zero value instead of raising FormatException, and typed getters fall through to your in-app default.
| firebase/remote-config | @appspike/web/remote-config |
|---|---|
import { initializeApp } from 'firebase/app' | import { initializeApp } from '@appspike/web/app' |
| Firebase config object | { apiKey: 'YOUR_APPSPIKE_API_KEY' } |
getRemoteConfig / fetchConfig / activate / fetchAndActivate / ensureInitialized | Identical function names |
getValue / getAll / getString / getBoolean / getNumber | Identical |
rc.settings / rc.defaultConfig / rc.lastFetchStatus | Identical |
setCustomSignals(rc, signals) | Identical function names |
Same modular API shape, so your defaultConfig, settings, and getter calls stay unchanged. AppSpike's web SDK also adds getKeysByPrefix and config update listeners, which Firebase's web SDK doesn't have.
The SDK README also ships a copy-paste AI migration prompt. Point your coding agent at it and it converts your call sites for you.
Publish your AppSpike config, run the app, and observe that the parameters arrive with the values you expect. Then roll out at your own pace: the two SDKs work together in one app, so you can move traffic gradually with a flag.
We built Remote Config for ourselves first: Firebase's usage-based pricing put our own apps' config bill at roughly $25,000 a year, and replacing it cost us less than that. AppSpike's business is built on ad revenue optimization, and Remote Config is free because it brings developers into the platform, and because it genuinely costs very little to run. Your config is published as an immutable, CDN-cached JSON file, and all condition evaluation happens on your users' devices, so we don't run compute per fetch.
There's no plan to meter it later. If that ever changed, your config is plain JSON you can export and take elsewhere, which is exactly the lock-in situation we built this to avoid.
Nothing visible to your users. The last activated config is persisted on each device and keeps serving, and keys never fetched resolve to your in-app defaults. A total outage means devices serve slightly stale config until we're back, the same failure model as Firebase.
If you ever want to leave permanently, export your config as JSON and re-create it elsewhere. Your config data is never locked in.
Structurally safer than server-side evaluation. Conditions are evaluated on the device, so custom signals like subscription tier or player level are never transmitted to us or anyone else. Firebase uploads signals with every fetch. We can't see yours at all.
The trade-off to know: because the device evaluates conditions, your full config (including conditional values for segments a user isn't in) is delivered to the device. Don't put secrets in Remote Config, the same rule Firebase documents for its client-delivered config.
Real-time updates: yes. Publishing a new version triggers a data push notification that wakes the SDK to fetch and activate, and your update listener fires as the new values land. No polling loop, no FCM workaround.
A/B testing: yes, with percentage conditions. Clauses that share a seed split the same population, so ranges like 0 to 50 and 50 to 100 build clean experiment arms, and a device keeps its group across fetches. Measure the results in the analytics tool you already use. A managed experiment dashboard with built-in statistics is on our roadmap.
The config side takes minutes and no code: one export command, one upload, then a review of the warning report. On the code side, Android and KMP keep Firebase naming, so reads are untouched and async calls change shape (Tasks become coroutines). On iOS you map Firebase calls onto a native Swift API where subscript reads stay subscript reads. The Flutter, React Native, Unity, and Web SDKs mirror their Firebase counterparts method-for-method, so those migrations are mostly imports and initialization. The SDK README includes an AI migration prompt that automates the call-site conversion.
The one real surprise: percentage rollout groups are re-randomized because our bucketing hash differs from Firebase's. Finish in-flight gradual rollouts before cutting over.
Android, iOS (native Swift API via Swift Package Manager), Kotlin Multiplatform (Android, iOS, wasmJs from shared code), Flutter, React Native, Unity, and Web. Whatever you ship on, the config API keeps the same shape.
No. Initialize the SDK in config-only mode and the ad side stays inactive and your existing mediation and ad stack are untouched. Remote Config needs the SDK session for fetching, nothing more.
Export from Firebase, upload to the console, and look around. No SDK, no code changes, no card. If it is not for you, you only spent five minutes.