Skip to content
Godot · Remote config

Remote config for Godot

Remote config for Godot games. Change prices, offers, quests and events without a new build, check them before they ship, target builds and roll back.

Updated

Remote config lets you change a value in a game that's already shipped, without a new build or a store review. For a Godot game that usually starts as a JSON file on a server. This page shows that simple version in GDScript, explains where it stops being enough (prices and rewards), and covers how PowerUp handles remote config for Godot: every price, offer and LiveOps setting lives in a draft, gets checked, and only reaches players once you publish it.

The do-it-yourself version

For tuning values that don't cost anyone money, a hosted JSON file works fine. This autoload loads the last copy it saved, asks for a fresh one, and falls back to defaults when the network is down:

# remote_config.gd: add it as an autoload
extends Node

const URL := "https://example.com/config.json"
const CACHE := "user://remote_config.json"

var values := {"enemy_speed": 1.0, "daily_bonus": 50}

func _ready() -> void:
    _load(FileAccess.get_file_as_string(CACHE) if FileAccess.file_exists(CACHE) else "")
    var http := HTTPRequest.new()
    http.timeout = 5.0
    add_child(http)
    http.request_completed.connect(_on_done.bind(http))
    http.request(URL)

func _on_done(result: int, code: int, _headers: PackedStringArray, body: PackedByteArray, http: HTTPRequest) -> void:
    http.queue_free()
    if result != HTTPRequest.RESULT_SUCCESS or code != 200:
        return   # keep the cached or default values
    var text := body.get_string_from_utf8()
    if _load(text):
        var file := FileAccess.open(CACHE, FileAccess.WRITE)
        if file:
            file.store_string(text)

func _load(text: String) -> bool:
    var parsed: Variant = JSON.parse_string(text) if text != "" else null
    if parsed is Dictionary:
        values.merge(parsed, true)
        return true
    return false

A few things to know. JSON numbers come back as floats, so wrap counts in int(). Anything that read a value before the fetch finished keeps the old one, so read values when you need them, or emit a signal when the fetch lands. And on a web export the request is a browser fetch, so the server hosting the file has to allow your game's origin (CORS).

Where a JSON file stops being enough

The trouble starts when the value is a price or a reward. A file tells the client what to show, but the client can't be trusted to charge it: whatever decides what a purchase costs and what it grants has to run on a server. Then come the questions a file can't answer. Did that edit just break the store? What did players have yesterday, and how do you get it back? What does a player on last month's build see when you add an item it can't draw?

How PowerUp does it

What counts as config

In PowerUp, everything your store and LiveOps run on is config: prices and coin amounts, sale windows and platforms, store items and their unlock rules, your coins and their dollar rate, season passes, quests, events, match rewards, ad placements and their pacing, news, clubs, and the parameters you define for each boost (a number with a minimum and maximum, or a list of choices). The server decides every purchase and reward from it, so a player can't edit the price they pay.

Draft, check, publish

Every edit in the console goes into a draft and is logged. When you publish, 48 automated checks run on the draft first (49 with Stripe Managed Payments). If one fails, nothing ships and the console shows which check and why. Warnings don't block. A publish that leaves owners of an item unable to use it in new builds also asks you for a note. The publish checks page lists what they cover.

Players only get published versions

Each publish freezes the draft as a numbered version. Players are served that version and nothing else, so a half-finished edit never leaks. Every answer the game gets says which version it came from, which helps when a player reports something odd. Your game server reads its own slice of the config, such as event times and boost parameters. It can ask every minute, and the answer is a quick "nothing new" until you publish again.

If a player has the shop open while you change an item's coin price, a buy at the old price is refused with the new price, and no coins are taken.

PowerUp Console · sandbox
The Releases page of the PowerUp console: the published versions, the draft compared with v1, the preflight stored with it, and a home preview on the draft
Releases: every published version, a field-by-field diff of the draft against any of them, and a preview of what a player would get.

Compare versions and roll back

The Releases page lists every version with its note, who published it, and the checks as they ran that day. Pick any version to compare the draft with it, section by section and field by field. Rolling back republishes an older version as a new one after running today's checks on it, and leaves your draft as it was. If the version you return to asks more XP for an item, or stops giving it away free, players who had already reached it keep it.

Target game builds

Items carry version rules: an exact version, "1.4 and later", "up to 1.6", a range, or exclusions. The Godot SDK sends the build's version with every request (by default from your project's version setting), and each build only gets the items and offers it can use. Checks warn when a subscription, pass or featured offer grants something some builds can't use, because those builds would never see the offer.

Preview before you publish

The console can show the lobby a real player would get from the draft, on one platform and one game version. It runs the real server logic and then throws the result away, so a preview grants nothing. Test builds on a sandbox key can also play the draft directly.

In your Godot code

const PLAY_DRAFT := false   # true only in a test build on your sandbox key

func _ready() -> void:
    PowerUp.initialize("YOUR_PUBLISHABLE_KEY", save.client_id, {
        "baseUrl": API_URL,
        "appVersion": "1.4.2",   # leave it out to use application/config/version
        "draftConfig": PLAY_DRAFT,
    })

func _on_buy_pressed(item: Dictionary) -> void:
    var res: Dictionary = await PowerUp.buy_item(item.key, int(item.price.coins))
    if res.ok:
        return
    match res.code:
        "price_changed":   # you published a new price; nothing was charged
            _confirm_new_price(item, int(res.details.priceCoins))
        "update_required":   # this build can't use the item
            _toast("Update the game to get this.")   # your UI

Experiments: what's there and what isn't

The console has an experiments register: the change you want to test, what you expect, the metric you'll judge it by, and a guardrail metric that would make you stop. If you mark an unfinished experiment as past its guardrail, a check warns at every publish until you clear the flag or complete the experiment. What it doesn't do yet is split players into groups. Nothing is served to some players and not others, so today you test a price by changing it for everyone and comparing periods. If live A/B assignment matters to you now, a tool built for it is the better choice.

Other options for Godot

As of October 2026, Talo's live config sends key-value properties from its dashboard to a Godot game, keeps an offline copy for when the player has no connection, and fires a signal over its socket when a value changes, so a running game picks it up. Heroic Labs' Satori Godot client offers feature flags, experiments and live events for Godot 4. Both are general tools for any value, and Satori runs experiments in a live game, which PowerUp doesn't yet. PowerUp is narrower: it runs the store, the wallet and LiveOps themselves, and checks the config they run on. See PowerUp and Talo and the Godot backends comparison, and LiveOps for Godot games for what the events, quests and news inbox do.

Questions

Can I store any gameplay value in PowerUp, like enemy speed?

No. PowerUp serves your monetization and LiveOps setup, plus the parameters you define for each boost. For other tuning values, a JSON file you host or a general live config tool is the better fit.

Can I run A/B tests on prices?

Not live yet. The console has a register where you write down what you're testing, the metric you're watching and the guardrail that would make you stop, but nothing splits players into groups today. A change you publish reaches every player.

How quickly do players get a change?

On their next request after you publish. Every answer is worked out from the version that's live at that moment and says which version that was. Your game server can check for a new version every minute.

What happens to players on an older build of my game?

Items carry version rules, so an older build only gets offered what it can use. If a player owns something their build can't show, the catalog still lists it with the reason, so your game can mark it "Update to use". That build can't sell it or equip it.

See it running on a real game.

We’ll walk you through the console with buggs.io’s setup.