Muse AI docs
v2.0.0
Live demoConsole demo Get help
● Set up · Every setting

Configuration.
Every variable, where it lives, what it does.

Muse AI has very few environment variables on purpose. Keys and product settings are entered in the console and stored in Firestore, so most buyers only ever touch two files: the console's .env and, optionally, the backend region. This page lists the build-time settings of the app, the environment of the console and the backend, and the two configuration documents.

3 app defines9 console variables1 backend variableKeys only in the console

01App: build-time settings (--dart-define)

Passed to flutter run and flutter build. They are compiled into the app, so changing one needs a new build.

DefinePurposeWhere to get the value
API_BASE_URL RequiredAddress of your backend, no slash at the end. Paths are added to it (<API_BASE_URL>/v1/config); any prefix before /v1 is allowed. Without it the app shows "Set your API address".The URL printed by firebase deploy: https://<region>-<project-id>.cloudfunctions.net/api, or your Hosting rewrite such as https://your-domain/api (own domain).
DEMO_MODE=trueWeb demo only (it has no effect in Android and iOS builds): no Firebase, a demo sign-in per browser, simulated and labelled ads and purchases ("Demo — no charge"). Never use it for a store build.Only for the demo and the Quick start.
USE_EMULATOR=true, EMULATOR_HOSTUse the local Firebase Auth and Firestore emulators. EMULATOR_HOST is optional (default localhost, Android emulator 10.0.2.2).Only for local development (emulators).

Firebase itself is configured by flutterfire configure, which writes lib/firebase_options.dart, android/app/google-services.json and ios/Runner/GoogleService-Info.plist. Those files contain your Firebase project's public client identifiers, not secrets.

02Console: environment (admin/.env)

Copy admin/.env.example to admin/.env (never commit it) or set the same names in your host's environment.

VariablePurposeWhere to get it
ADMIN_SECRET_KEY Required32 random bytes (64 hex characters) that encrypt every secret the console stores: AI keys, image keys, store keys, reporting tokens. Without it the console creates data/.admin-secret-key and warns; on serverless or Postgres setups it must be set. Back it up.Generate: openssl rand -hex 32. See Secrets at rest.
GOOGLE_APPLICATION_CREDENTIALS Required (except on Google Cloud)Path to a service-account key file of your Firebase project, used by the Admin SDK. Leave empty on Cloud Run or Compute Engine to use the attached service account.Firebase console → Project settings → Service accounts → Generate new private key.
FIREBASE_PROJECT_ID OptionalOnly when the credentials do not name the project.Firebase console → Project settings → Project ID.
FIREBASE_STORAGE_BUCKET OptionalOnly to preview a reported image in the Reports queue.Firebase console → Storage, for example your-app.firebasestorage.app.
FIRESTORE_EMULATOR_HOST DevelopmentPoint the console at the Firestore emulator, for example 127.0.0.1:8080 (project demo-museai unless FIREBASE_PROJECT_ID is set).Local only.
ADMIN_DATAsample = built-in sample data, no Firebase (public demo, quick start). Empty = your Firestore.Leave empty on your install.
ADMIN_DEMO_PASSWORDOnly on a public demo host: makes the console read-only with the account demo@museai.demo (a viewer). Every write answers 403.Leave empty on your install.
PORTPort of the console. Default 8790.Your host may set it for you.
DATABASE_URL OptionalA pooled Postgres URL (sslmode=require) for the console's own data (team, sessions, settings, audit) instead of data/admin.sqlite. Needed on serverless hosts or with several instances. Tables are named mk_museai_*.Your Postgres provider.

03Backend: environment (firebase/functions/.env)

VariablePurposeWhere to get it
FUNCTIONS_REGION OptionalCloud Functions region, default us-central1. Use the same region in API_BASE_URL.Copy functions/.env.example to functions/.env before deploying.

No key goes into this file. The backend reads every key from config/private in Firestore. The variables DEMO_AI_PROVIDER, DEMO_AI_KEY, DEMO_AI_MODEL, DEMO_AI_BASE_URL, DEMO_IMAGE_PROVIDER, DEMO_IMAGE_KEY and DEMO_IMAGE_MODEL exist only for the local dev API and a public demo host; export them in a shell, never put them in a file of the project.

04The configuration documents

Two Firestore documents hold every product setting. The console is their only writer: it writes both in one transaction on every save and once when it starts, raises the shared version and sets updatedAt. Do not edit them by hand, because the next console save overwrites them. An invalid line (for example a catalog entry over a limit) is skipped, never guessed, and Console → Status, check App config written to Firestore, names it.

DocumentWho can read itHolds
config/publicThe backend; the app gets a filtered copy through GET /v1/config. Firestore rules deny direct client access.Everything the app needs to draw itself: brand, switches, catalogs, plans, store product ids, ad unit ids
config/privateThe backend only. Never sent to the app.Provider keys, store verification keys, global caps

The TypeScript types that define both documents are PublicConfig and PrivateConfig in admin/src/sync.ts; the backend reads them with the same defaults in firebase/functions/src/api/defaults.ts. If you extend the backend, add a field in both places and in the console manifest (admin/src/manifest.ts).

config/public

FieldType · defaultWhat it controls · console page
version, updatedAtnumber, timestampRaised on every write (one counter shared by both documents); time of the write
brand.appNamestring
Default: "Muse AI"
Name shown inside the app (the name under the icon is set in the native files) Console → Brand
brand.accentstring #RRGGBB
Default: "#8B5CF6"
Accent colour of the app Console → Brand
brand.tagline, brand.supportEmailstring
Default: tagline; ""
Short line under the app name; the support e-mail address shown to users Console → Brand
brand.privacyUrl, brand.termsUrlstring (URL)
Default: ""
Your privacy policy and terms pages Console → Legal
legal.aiNotice, legal.imageBadgestring
Default: "AI can make mistakes. Check important information.", "AI-generated"
Notice under the composer; label on generated images Console → Legal
legal.minAge, legal.ageGatenumber (13, 16, 17, 18), boolean
Default: 17, true
Age self-confirmation on first start Console → Legal
features.<name>boolean each
Default: see Defaults
Module switches: chat, images, voice, vision, pdf, assistants, prompts, webSearch, cloudSync, share, discover, voiceMode, tts, transcribe, videoEditor, captions, videoGen, imageEdit, imageTools, incognito, followUps Console → Features
auth.google, auth.apple, auth.emailboolean
Default: true
Which sign-in buttons the app shows Console → Sign-in methods
chat.defaultModel, chat.titleModelstring (model id)
Default: "" = first enabled model
Model for new chats; model that names chats Console → Chat
chat.maxContextMessagesnumber 2–100
Default: 30
How many earlier messages are sent with each question Console → Chat
chat.webSearch, chat.followUpsboolean
Default: false, true
Web search for models that support it; follow-up suggestions Console → Chat
chat.suggestionsstring[] (≤ 8, ≤ 80 chars)
Default: 4 examples
Starter chips on the empty chat Console → Chat
models[]array of objects
Default: 3 models, disabled
Chat models: id, label, provider (anthropic, openai, gemini, openai_compatible), model, tier (free or a plan id), creditCost, vision, pdf, webSearch, reasoning, fast, maxOutputTokens, enabled, order, badge, priceIn/priceOut (your price per 1M tokens, console only) Console → Chat models
imageModels[], imageStyles[]arrays
Default: 2 models (disabled), 12 styles
Image models (id, label, provider, model, tier, creditCost, enabled, order, pricePerImage) and styles (id, label, promptSuffix, preview) Console → Image models & styles
imageEditModels[]array
Default: 2, disabled
Image edit models (provider openai or fal, mask, creditCost, …) Console → Image tools
assistants[], prompts[]arrays
Default: 24, 30
Assistants (id, name, emoji, category, description, systemPrompt, starters, model, tier, active, order) and prompt library (id, title, category, text, active, order) Console → Assistants, Prompts
voices[], videoModels[], captionStyles[]arrays
Default: 6, 2, 8 (voices and video disabled)
Natural voices, AI video models and caption styles (fields in docs/CONTRACT.md §17.1) Console → Voices & transcription, Video, Caption styles
limits.free.<key>number each
Default: messages 20, images 2, imageEdits 2, videoSeconds 0, captionMinutes 3, ttsChars 3000, transcribeMinutes 5, discoverBriefs 5, rewarded 3
Free allowance per user (videoSeconds and captionMinutes per month, the rest per day) Console → Limits
plans[]array (≤ 4)
Default: 1 example plan "Pro", inactive
id, name, tagline, order, highlight, active, color, rank, products.<period>.<platform> (store product ids; period weekly, monthly, yearly, lifetime; platform android, ios), trialDays, features[], limits (same keys as free), noAds Console → Plans
paywall.*object
Default: cards, yearly, on limit
layout (cards/list), defaultPeriod, showOnLaunch, everyNLaunches, onLimit, closeDelaySeconds (0–5), title, subtitle, cancelText Console → Paywall
iap.enabledboolean
Default: false
Whether the app sells anything Console → Store & purchases
iap.removeAdsId, iap.credits.<pack>string (store product id)
Default: remove_ads, credits_small, credits_medium, credits_large
Product ids you create in your own store accounts; <pack> is small, medium or large (In-app purchases) Console → Store & purchases
iap.creditPacks.<pack>number
Default: 50, 200, 600
Credits granted per pack Console → Store & purchases
discover.*object
Default: off, 6 categories
enabled, categories[] (id, name), forYou, briefTier Console → Discover
ads.enabledboolean
Default: false
Master switch Show ads Console → Ads
ads.mode, ads.network"single" | "waterfall"; "admob" | "unity" | "ironsource"
Default: "single", "admob"
How ads are filled (Waterfall) Console → Ads
ads.waterfall.<format>string[] of network names
Default: ["admob"] each
Order of networks per format in waterfall mode; <format> is banner, interstitial, rewarded, native or appOpen Console → Ads
ads.ssvboolean
Default: false
AdMob server-side verification of rewarded ads Console → Ads
ads.placements.*object
Default: all off; interstitialMinSeconds 120
appOpen, bannerHome, bannerGallery (boolean), nativeAssistantsEvery, interstitialEveryNMessages (0–100, 0 = off), interstitialMinSeconds (30–3600), rewardedMessages, rewardedImages (boolean) Console → Ads
ads.admob.*string each
Default: ""
androidAppId, iosAppId, android/ios + Banner, Interstitial, Rewarded, Native, AppOpen Console → AdMob ids
ads.unity.*string each
Default: ""
androidGameId, iosGameId, android/ios + Banner, Interstitial, Rewarded Console → Unity Ads ids
ads.ironsource.*string each
Default: ""
androidAppKey, iosAppKey, android/ios + Banner, Interstitial, Rewarded Console → ironSource LevelPlay ids
push.topicAllstring
Default: "all"
FCM topic every device subscribes to

GET /v1/config sends this document to the app without your prices (priceIn, priceOut, pricePerImage, pricePerSecond, pricePerMillionChars), provider names, provider model ids and voice ids, with only the models whose provider has a key, and with "demo":true|false added.

config/private (backend only)

FieldType · defaultWhat it is · console page
ai.anthropicKey, ai.openaiKey, ai.geminiKeystring (secret)
Default: ""
Chat provider keys (OpenAI also serves moderation; OpenAI and Gemini are the fallback for images and voice) Console → AI providers & keys
ai.openaiBaseUrlstring (URL)
Default: ""
Only for an OpenAI proxy Console → AI providers & keys
ai.compatible[]array of objects
Default: []
Up to 4 OpenAI-compatible endpoints, each id, name, baseUrl, apiKey (ids compat1–compat4) Console → AI providers & keys
ai.maxCallsPerDaynumber
Default: 2000
Global cap on AI calls per day, over all users Console → AI providers & keys
images.openaiKey, geminiKey, falKey, stabilityKeystring (secret)
Default: ""
Image provider keys Console → Image providers & keys
images.maxPerDaynumber
Default: 200
Global cap on images, edits and tool calls per day Console → Image providers & keys
images.tools.removeBg, upscale, removeBgPrice, upscalePricestring
Default: fal-ai/birefnet, fal-ai/esrgan, "", ""
fal.ai model ids of the two tools (empty = tool hidden) and your prices for the spend view Console → Image tools
voice.openaiKey, elevenlabsKey, geminiKey, deepgramKeystring (secret)
Default: ""
Voice and transcription keys Console → Voices & transcription
voice.transcribeProvider, transcribeModel"openai" | "deepgram" | "gemini"; string
Default: "openai", ""
Transcription provider and optional model Console → Voices & transcription
voice.maxTtsCharsPerDay, voice.maxTranscribe­MinutesPerDay, voice.transcribe­PricePerMinutenumber, number, string
Default: 1000000, 1000, ""
Global daily caps; your price for the spend view Console → Voices & transcription
video.falKey, replicateKey, maxPerDaystring, string, number
Default: "", "", 50
AI video keys and the global cap on jobs per day Console → Video
discover.sources[], refreshMinutes, maxAgeDaysarray of objects, number, number
Default: 12 feeds (off), 30, 3
News feeds (each id, name, url, category, enabled), refresh interval (10–1440 minutes), item age (1–14 days) Console → Discover
moderation.provider, blocklist, blockMinorsSexual"none" | "openai", string[] (≤ 500), true
Default: "none", [], true (locked)
Moderation before a request reaches a provider Console → Moderation
iap.googlePackageName, googleServiceAccountJsonstring, string (secret)
Default: ""
Google Play purchase verification with your service account Console → Store & purchases
iap.appleIssuerId, appleKeyId, applePrivateKey, appleBundleId, appleEnvironmentstring; key secret; "production" | "sandbox"
Default: "", "production"
App Store Server API verification with your key Console → Store & purchases
adReporting.*string (the last three secret)
Default: ""
Optional AdMob reporting for the revenue page: admobPublisherId, admobClientId, admobClientSecret, admobRefreshToken Console → Ad revenue reporting
admobSsv.enabledboolean
Default: false
Copy of ads.ssv; the SSV callback is accepted only when both are true Console → Ads

Secret values are stored encrypted in the console's own database with ADMIN_SECRET_KEY and written in plain form only to config/private, which the Firestore rules close to every client (Secrets at rest).

05Defaults of a fresh install

  • Every chat, image, image-edit, voice and video model is disabled.
  • Ads, every ad placement, in-app purchases and every plan are off.
  • Modules that call a paid provider are off: Discover, natural voices, transcription, auto captions, AI video, image edit and image tools. Every default Discover feed is off.
  • Modules on: chat, images, voice input and read-aloud, voice mode, photos, PDF, assistants, prompts, cloud backup, share, the on-device video editor, incognito chats and follow-up suggestions. Web search off.
  • Free users: per day 20 messages, 2 images, 2 image edits and tools, 3,000 voice characters, 5 transcription minutes, 5 Discover briefs and 3 rewarded unlocks; per month 0 AI video seconds and 3 caption minutes. One example plan "Pro" (rank 1, inactive) with the product ids pro_monthly and pro_yearly.
  • Minimum age 17, age check on, notice under the composer "AI can make mistakes. Check important information.", image badge "AI-generated".
  • Sign-in buttons Google, Apple and e-mail on (they only work once enabled in Firebase Authentication).
  • Catalog: 3 chat models (Muse Fast, Muse Pro, Muse Max on Anthropic), 2 image models (OpenAI gpt-image-1, fal.ai FLUX schnell), 12 styles, 24 assistants, 30 prompts, 2 image-edit models, 6 voices (OpenAI), 2 video models (fal.ai Kling), 8 caption styles, 6 Discover categories and 12 feeds.

An untouched console writes exactly these defaults, and the backend uses the same values until the console has saved once.