MMashDiv

Configuration reference — every key in app_config.json

Every key the app reads from assets/config/app_config.json — type, default, whether it is required, what it does, when a change takes effect, and the server setting it has to agree with. Also the keys older configs carry that the app ignores.

9 min readUpdated 26 September 2026mobile, configuration, app-config, reference, keys, baseurl, stripe, google

Every key the app reads from assets/config/app_config.json. How the file is loaded, what happens when it is missing or broken, and what must never go in it are on App configuration.

Four rules apply to every key:

  • Every change needs a new build. The file is packed into the app when it is built. A published app keeps the values it was built with until its users install an update.
  • Write JSON types. Text in quotes, switches as bare true/false, numbers as bare whole numbers. A value of the wrong type stops the app on its Configuration Error screen.
  • For the name, identifier and colour keys, "" counts as not set: an empty colour gives the default colour, an empty appName gives BiCrypto. For the other keys an empty string is a value, not a default.
  • Unknown keys are ignored, and keys starting with _ are notes.

All keys at a glance

Key Type When absent Required
baseUrl text — Yes
wsBaseUrl text — Yes
appName text BiCrypto No
androidApplicationId text com.bicrypto.mobile No
iosBundleId text The Xcode project's id No
iosTeamId text Nothing written; the Team chosen in Xcode No
primaryColor text #0ECE7A No
buyColor text #0ECE7A No
sellColor text #FF5A5F No
accentColor text #1890FF No
googleServerClientId text "" Only for Google sign-in
googleAuthEnabled switch Shown only if googleServerClientId is set No
stripePublishableKey text "" Only for Stripe card deposits
defaultTradingPair text BTC/USDT No
defaultExchangeProvider text bin No
appVersion text 5.0.0 No
settingsCacheDuration whole number 3600 No
_clientCredentialNotice text — No (a note)

Your server

baseUrl

baseUrltype: stringdefault: none
The address of your platform. Every request the app makes goes to this host.
  • Required. Missing, blank or not text stops the app on the Configuration Error screen: … does not set "baseUrl".
  • What to write. The address your customers open in a browser, such as https://exchange.example.com. No /api on the end; the app adds the paths itself. Spaces around it and one trailing / are removed for you.
  • What it is used for. Every API request (/api/...), and the images: coin logos (/img/crypto/...) and every image the server gives as a relative path, such as uploaded avatars (/uploads/...), are loaded from this host too.
  • Release builds accept only an https:// address and stop on the Configuration Error screen otherwise, naming the key and the value: … sets "baseUrl" to "http://…", which is not a https:// address, and this is a release build. The build itself still succeeds, so check first with dart run tool/apply_app_config.dart --check --release. Debug and profile builds also accept http://, for testing against a server on your own computer (on the Android emulator, http://10.0.2.2:4000 reaches your computer).
  • Takes effect at the next build.
  • Must agree with your server's public address: the host that answers /api, /img/crypto and /uploads. Check it with the market list request in Install.

wsBaseUrl

wsBaseUrltype: stringdefault: none
The address the app opens its live connections on: prices, order books, open orders, deposits, notifications and support chat.
  • Required, with the same rule and error as baseUrl.
  • What to write. The same host with wss://, such as wss://exchange.example.com. The app adds the paths, all under /api/... (for example /api/exchange/ticker for prices).
  • Release builds accept only wss://, and stop on the Configuration Error screen naming wsBaseUrl otherwise; debug and profile builds also accept ws://.
  • Takes effect at the next build.
  • Must agree with your reverse proxy. It must pass WebSocket upgrades on /api/... through to the backend and must not strip the headers the app sends with them (accesstoken, sessionid, csrftoken, platform), or the connections that need a signed-in user fail while prices still work. See Nginx and reverse proxy.

Name, identifiers and colours

These keys are covered in full, with what each platform does at build time, on Branding.

appName

appNametype: stringdefault: BiCrypto
Your app's name: inside the app, and under the icon on the Android and iOS home screens.
  • Format. One line of text. A tab or line break stops the build. Absent or blank gives BiCrypto. A value that is not text stops the app on the Configuration Error screen.
  • Takes effect at the next build, on both platforms, with nothing else to run: Gradle reads it on every Android build, and the Apply app_config.json build phase on every iOS build.
  • Server counterpart: none. Your store listing's name is set separately in Play Console and App Store Connect.

androidApplicationId

androidApplicationIdtype: stringdefault: com.bicrypto.mobile
The Android app's identity on the phone and on Google Play.
  • Format. Two or more parts separated by dots, each starting with a letter, using only letters, digits and underscores. An invalid value stops the Android build.
  • Takes effect at the next Android build. Gradle reads it every time.
  • Changing it after release makes a new app. Play will not accept it as an update to your listing.
  • Must agree with android/app/google-services.json (for push), which must come from a Firebase Android app registered with the same id, and with the Android OAuth client you register for Google sign-in.

iosBundleId

iosBundleIdtype: stringdefault: empty
The iOS app's identity on the phone and on the App Store.
  • Format. Two or more parts separated by dots, using only letters, digits and hyphens. No underscores.
  • Empty or absent means the build keeps whatever id the Xcode project has (the template's is com.bicryptto.mobile) and does not check it. The example file ships it as "".
  • Takes effect after you run dart run tool/apply_app_config.dart, which writes it into the Xcode project. An iOS build whose project disagrees with a set iosBundleId stops, with both ways to fix it in the message.
  • Must agree with the App ID registered in your Apple Developer account, your provisioning profile, and ios/Runner/GoogleService-Info.plist if you use push.

iosTeamId

iosTeamIdtype: stringdefault: empty
Your Apple Developer Team ID, used to sign the iOS app.
  • Format. Exactly 10 characters, upper-case letters and digits, as developer.apple.com → Account → Membership details shows it. Any other value is refused by dart run tool/apply_app_config.dart, which then writes nothing. The app itself never reads this key.
  • Empty or absent means nothing is written: the Xcode project keeps whatever Team it has, and you choose yours in Xcode under Runner → Signing & Capabilities. The template's project carries no Team, and the example file ships the key as "".
  • Takes effect after you run dart run tool/apply_app_config.dart, which writes it into DEVELOPMENT_TEAM in every Runner build configuration. With --check, the tool exits 1 while the project's Team differs from it.
  • The release preflight reports ios-team while the project names no Team for Release, or still carries 52K7QMD7KR (the Team the template's project carried up to 5.3.9), and ios-team-mismatch when the project's Team differs from this key.
  • Must agree with the Apple Developer account that owns your bundle id.

primaryColor, buyColor, sellColor, accentColor

primaryColortype: stringdefault: #0ECE7A
The four brand colours, in both the dark and the light theme.
Key Default Paints
primaryColor #0ECE7A Your brand colour: buttons, tabs and links
buyColor #0ECE7A Buy, prices going up, positive changes
sellColor #FF5A5F Sell, prices going down, negative changes
accentColor #1890FF Informational accents
  • Format. "#RRGGBB" or "#AARRGGBB" (opacity first), in either case. An empty string counts as not set. Any other value, such as "blue" or "0ECE7A" without the #, stops the app on the Configuration Error screen naming the key.
  • Not configurable. Errors stay red (#FF5A5F) and success stays green (#0ECE7A) whatever the four keys say, and text on primary-coloured buttons switches to dark on a very light primary. The exception in this release is the Transfer screens and the wallet's Deposit screens, which still colour their own success and error marks with buyColor and sellColor, and keep white text on some primary-coloured buttons and selected items.
  • Takes effect at the next build or flutter run.
  • Server counterpart: none. The website's colours do not reach the app.

Google sign-in

How to set Google sign-in up on both platforms, and what it can and cannot do, is on Sign-in methods.

googleServerClientId

googleServerClientIdtype: stringdefault: empty
The OAuth Web client ID the app asks Google to issue its sign-in token for.
  • Required for Google sign-in. Empty means the app asks Google without a server client ID.
  • Takes effect at the next build.
  • Must agree with your server's NEXT_PUBLIC_GOOGLE_CLIENT_ID: the same Web client ID. The server accepts a Google token only if it was issued for that ID, and refuses any other with an error starting Google authentication failed:. See Environment variables.
  • Never validated by the app. A wrong value shows up only when someone taps Continue with Google.
  • It is a public identifier, not a secret. Never put a client secret here.

googleAuthEnabled

googleAuthEnabledtype: booleandefault: true if googleServerClientId is set
Shows or hides the Continue with Google button on the sign-in and registration screens.
  • true shows the button. false hides it. Either is obeyed as written.
  • Absent shows the button only when googleServerClientId is set (not blank), so a config with no client ID has no button that could only fail.
  • Android with google-services.json. On Android the Google plugin can take the Web client ID from google-services.json when googleServerClientId is empty. The absent-key rule looks only at googleServerClientId, so in that setup write "googleAuthEnabled": true.
  • Takes effect at the next build.
  • Not linked to your server's Google OAuth Login switch. That switch (Admin → System → Platform Settings → Security → Authentication) governs the website's buttons only. Turning it off does not hide the button in the app; this key does.
  • The installers (setup/installers/install.sh, install.bat) leave this key out, so the button follows the Google client ID you give them. The example file ships "googleAuthEnabled": false.

Card deposits

stripePublishableKey

stripePublishableKeytype: stringdefault: empty
Your Stripe publishable key, used by the card payment sheet on the fiat deposit screen.
  • Required for Stripe card deposits, and used by nothing else in the app.
  • Empty means Stripe is not set up in the app. If your server still offers Stripe, customers can choose it and the payment fails when the payment sheet opens. Leave it empty only if your server does not offer Stripe.
  • Takes effect at the next build.
  • Must agree with your server's APP_STRIPE_SECRET_KEY: a key pair from the same Stripe account and the same mode — pk_test_… with sk_test_…, pk_live_… with sk_live_…. The server creates each payment with its secret key and the app completes it with this one.
  • It is a publishable key. Never put the sk_… secret key here.

Setup, and what the customer sees, is on Payments.

Trading defaults

defaultTradingPair

defaultTradingPairtype: stringdefault: BTC/USDT
The market the Trade tab opens on when the customer has not picked one.
  • Format. BASE/QUOTE with a slash, as your markets are named, such as ETH/USDT. Leave the key out rather than empty: "" is not replaced by the default.
  • What it does. The Trade tab opens on this market when the customer arrives without tapping a market, and the live trading connection subscribes to it first.
  • Takes effect at the next build.
  • Must agree with a market that exists and is enabled on your server. If it does not, the app refuses an order placed from it with We couldn't confirm which market <symbol> belongs to. Pull down to refresh the market list and try again.

defaultExchangeProvider

defaultExchangeProvidertype: stringdefault: bin
Which exchange's list of chart timeframes the chart offers. Nothing else.

Despite its name, this key does not choose the exchange your server trades on, and the app never asks your server which one it uses. Its only effect is which timeframes the chart's timeframe picker offers:

Value Timeframes offered
bin (Binance) 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w, 1M
kuc (KuCoin) 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 1w
okx 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 12h, 1d, 3d, 1w, 1M
xt 1m, 5m, 15m, 30m, 1h, 4h, 1d, 1w
kra 1m, 5m, 15m, 30m, 1h, 4h, 1d, 1w
Anything else The Binance list
  • Only the short codes match, in upper or lower case. "binance" or "kucoin" fall back to the Binance list.
  • xt works from 5.4.0. Earlier releases had a stray space in the app's XT entry, so "xt" got the Binance list; an XT install that used "kra" as a workaround gets the same list either way.
  • Takes effect at the next build.
  • Must agree with the spot exchange provider that is active on your server (Binance → bin, KuCoin → kuc), so the chart does not offer timeframes your exchange does not have. See Exchange provider.

Housekeeping

appVersion

appVersiontype: stringdefault: 5.0.0
A fallback version number. The app shows the version the build was stamped with, not this.
  • What it does. The version customers see comes from the build itself, from the version: line in pubspec.yaml, shown as <version> (<build number>) on Profile → Open-source Licenses. This key is used only when the phone cannot report the build's version, which does not happen on a normal install.
  • You do not need to edit it when you release. Change the version in pubspec.yaml; see Build for Android.
  • Server counterpart: none. The app does not send its version to your server.

settingsCacheDuration

settingsCacheDurationtype: integerdefault: 3600
How many seconds a saved copy of your server's public settings counts as fresh.
  • What it does, in practice: very little. The app downloads your server's public settings (GET /api/settings) when it starts and again every five minutes, and both of those always go to the server. This value only lets one screen that asks without forcing a download reuse a copy younger than this. Offline, the app uses its saved copy whatever its age.
  • Format. A whole number of seconds, written without quotes. "3600" or 3600.0 stops the app on the Configuration Error screen.
  • Leave it at 3600. It does not make the app pick up your settings faster or slower; the five-minute refresh does that.
  • Takes effect at the next build.

_clientCredentialNotice

_clientCredentialNoticetype: string
A note for you. The app never reads it.

The example file carries: "This distributed file contains placeholders only. Configure your own public client identifiers before building. Never put secret/private keys in a mobile app." Every key that starts with _ is treated the same way, so you can add notes of your own.

Keys the app ignores

Configurations from releases up to 5.3.9, and files written by their installers, carry keys this release does not read. None of them is in the example file any more, and the installers no longer write them.

Key What decides it instead
recaptchaEnabled, recaptchaSiteKey Your server's Captcha Provider. The app answers the built-in proof-of-work at sign-up and password reset, and sends customers to the website under a hosted captcha; see Sign-in methods
walletAuthEnabled, walletConnectProjectId Nothing: the app has no wallet sign-in
twoFactorEnabled, twoFactorSmsEnabled, twoFactorEmailEnabled, twoFactorAppEnabled Your server's Two-Factor Authentication settings
emailVerificationEnabled Your server's Email Verification Required setting
backgroundUpdateInterval Nothing: the app's refresh intervals are built in
cryptoCompareApiKey, _cryptoCompareApiKeyHelp Your server: the app reads news from your backend, which holds the provider key
defaultShowComingSoon Nothing: which modules appear is your server's decision

None of these keys changes anything, whatever its value — a wrongly typed one cannot stop the app — so they are safe to leave or delete.

A complete file

Every key this release reads, with example values. Replace them with your own.

{
  "baseUrl": "https://exchange.example.com",
  "wsBaseUrl": "wss://exchange.example.com",

  "appName": "MyExchange",
  "androidApplicationId": "com.myexchange.app",
  "iosBundleId": "com.myexchange.app",
  "iosTeamId": "",

  "primaryColor": "#2F6BFF",
  "buyColor": "#16C784",
  "sellColor": "#EA3943",
  "accentColor": "#F0B90B",

  "googleServerClientId": "1234567890-abc123.apps.googleusercontent.com",
  "googleAuthEnabled": true,

  "stripePublishableKey": "pk_live_...",

  "defaultTradingPair": "BTC/USDT",
  "defaultExchangeProvider": "bin",

  "appVersion": "5.3.9",
  "settingsCacheDuration": 3600,

  "_clientCredentialNotice": "Public values only. Never put secret or private keys in this file."
}

Not in this file

What Where it is set
Push notifications android/app/google-services.json and ios/Runner/GoogleService-Info.plist — see Push notifications
The icon assets/icons/app_icon.png, then dart run tool/apply_app_config.dart --icons — see Branding
The version and build number version: in pubspec.yaml
Android release signing android/key.properties — see Build for Android
Which modules, sign-in checks and deposit gateways customers get Your server's settings