triggair

Blog / live-ops

Change your game live with remote config

3 min read

Change your game live with remote config cover art

Your game is live. A drop rate is twice what it should be, or a shiny new feature is crashing a slice of players, or you want to run a double-XP weekend starting Friday. With a hardcoded build, every one of those is an app-store submission and a multi-day review wait, during which the bug keeps biting and the weekend passes. That's the tax of baking numbers into the binary.

Remote config removes the tax. You read a server-controlled blob at runtime; changing a value in the dashboard changes the game for everyone, live, with no redeploy. Tuning, feature flags, and scheduled events all flow through the same tg.config.get().

Read config on boot and apply it

Fetch the blob early, right after login, and let it parameterize your game instead of hardcoded constants.

ts
const cfg = await tg.config.get();

const dropRate   = cfg.legendary_drop_rate ?? 0.02;  // sane fallback
const scripMult  = cfg.scrip_multiplier ?? 1;
const eventName  = cfg.event_name ?? null;

applyDropRate(dropRate);

The pattern that matters is the ?? fallback on every read. Config is authoritative when present, but you always ship a default so a missing or slow config never leaves the game in a broken state. Read once on boot, hold the values, and you've replaced a wall of magic numbers with dashboard-tunable knobs.

Run a double-XP weekend

A live event is just config values the client already knows how to read. Flip scrip_multiplier to 2 and set an event_name in the dashboard on Friday, revert Sunday night, and no build is involved.

ts
const cfg = await tg.config.get();
const multiplier = cfg.scrip_multiplier ?? 1;

function awardScrip(base: number) {
  return Math.round(base * multiplier);
}

if (cfg.event_name) {
  showEventBanner(cfg.event_name);   // "Double Scrip Weekend!"
}

Because the multiplier is server-driven, everyone flips into the event the moment you save, with no staggered rollout and no "please update your app." Schedule it in the dashboard and it turns on and off on its own.

Kill a broken feature instantly

The most valuable config value you'll ever set is a boolean kill switch. Gate any risky feature behind a flag, and the day it misbehaves you turn it off from the dashboard instead of rushing a hotfix through review.

ts
const cfg = await tg.config.get();

if (cfg.features?.new_arena_enabled) {
  enableNewArena();
} else {
  showClassicArena();               // instant, safe fallback
}

One flag flipped to false and the broken arena is gone for every player in seconds. That's the difference between a bad afternoon and a bad week.

Gotchas

  • Always default. Every read needs a ?? fallback. Never assume a key exists. A typo in the dashboard or a first-run race shouldn't crash the client.
  • Config is not player state. It's global tuning and flags, the same for everyone (resolved for their context). Don't try to stash a player's inventory here. That's what stats and the inbox are for.
  • Decide your refresh cadence. Reading on boot is the simple, reliable default. If you want a running event to reach already-open sessions, re-read config.get() at a natural break like returning to the menu, just don't hammer it every frame.
  • Flags fail safe. Write the else branch as the safe, known-good path so that "flag missing" and "flag off" both land on the experience you trust.

Read the blob on boot, default every value, and gate anything risky behind a flag. Your drop rates, live events, and emergency off-switches all move at dashboard speed instead of app-store speed.

Build this into your game.

Everything above is one import and a publishable key away. Start with the quickstart, or read the guide for the exact feature.

Keep reading