mobilegame-qaliveopseventsconfigqa

LiveOps events — releases without App Review that get the least testing

The game release is tested, shipped, everyone exhales. Then the real life begins: a new event every week. A battle pass, a weekend tournament, a sale, a season. And all of it ships without a release: via server config, no App Review, no binary — often on Friday evening, because the event starts on the weekend. An event is a full-fledged mini-release that reaches users faster and easier than any build. Yet in my experience it gets a fraction of the testing. It should be the opposite: an event has no store-review safety net and no staged rollout by default.

Let me break down what exactly breaks in events and how I test them.

An event is config, time, economy and production. All at once

Four properties make events a special test object. The content arrives as server config — bypassing all the usual release protections. It arrives on top of any client version — including the one released six months ago. It has a window in time — while users’ time runs in 38 timezones, and some users know how to change it. And it hands out rewards — touching the game’s economy. Each of the four properties is its own bug class.

Window boundaries: start, end, and the user from UTC+13

The first question for any event: start and end — in whose time? UTC, server, user’s local? Whatever the team answers, check the edge users: Auckland (UTC+13) and Honolulu (UTC-11) see the event at different calendar times, and someone’s “weekend event” starts on Friday afternoon — or ends on Monday.

Then the boundaries themselves. What does the user see before the start — a timer, a teaser, nothing? What happens to a user who entered the event a minute before it ends — kicked mid-match? And most importantly: what about rewards earned but not claimed by the end? Good teams build a claim grace period or auto-grant; bad ones silently burn them, and support spends a week on “my rewards disappeared.” Whichever behavior you have — it should be decided and verified before the launch, not after the complaints.

Clock manipulation: the main cheat and the main bug source

A genre classic: the user sets the device clock forward — and energy has regenerated, the cooldown has passed, the daily reward paid out again. Sets it back — the event “hasn’t started,” although it’s live. The rule is simple: the source of truth is server time; client time is for rendering timers only. But that rule must be verified on every event flow separately: clock forward, clock back, timezone change, a flight across the ocean (a legitimate case that looks exactly like cheating!). If the game is offline-capable or syncs rarely, deciding what to trust becomes a product decision — also made before the launch.

Config on top of an old client

I covered the version matrix in the app update testing post; for events it’s doubly critical: the config goes to all versions at once. A new event references an item/mechanic/screen that doesn’t exist in a six-month-old client. The right behavior is a minimum-version field in the event config and graceful hiding on old clients. The wrong but common one is a parsing crash — or, subtler, the event shows up but its button leads nowhere. Testing on the oldest supported version is mandatory — not just on the current one.

Rewards: exactly once, even when the network dies

Claiming a reward is a transaction, and it must be idempotent: tap “Claim,” network drops, retry — one reward, not zero and not two. It’s exactly the class of checks from the idempotency and retries post: double tap, killing the app between request and response, re-claiming from another device.

Separately — prices and denominations. Event configs are filled in by hand in a spreadsheet or JSON, and “a comma in the wrong place” turns into a top-tier sword for 1 coin. Those stories end in economy rollbacks and refund waves. The cheap insurance is schema validation of the config plus range sanity checks (“price > 0,” “reward < X”) in the config pipeline. If there’s no validation — request it before the first incident, not after.

Config is code. With everything that follows

The lesson of the CrowdStrike breakdown applies to events literally: content that bypasses the release process takes production down just like code — only faster. So I hold event configs to the same standards as code: it passes staging (an environment where the config can be deployed and exercised before prod), it has review (who can edit the prod config? two pairs of eyes?), it rolls out gradually (at least to a percentage of users, if the platform can), and it has a kill switch — a way to turn the event off within a minute without waiting for anyone. If any of that is missing — that’s a tester finding more important than any bug inside the event itself.

An event start is a load test in production

At the start, everyone rushes in simultaneously: open the event screen, buy in the event shop, hit the leaderboard. At the end — a mass claim. That’s a ready-made spike profile from the load testing post: if the leaderboard and the shop were never run under start-shaped load, your first big event will run that test for you, on live users.

Event #2 and dirty state

Events repeat, and the second run of the same template breaks on the leftovers of the first: unclosed entities, stuck progress, a user entering the new event with the previous event’s active state. A regression check that “the previous event ended cleanly and tidied up after itself” belongs in every next launch checklist. And test not only on a fresh account: the bulk of your users enter a new event trailing the residue of old ones.

Tooling: time travel or nothing

You can only honestly test events if staging can move server time (a time-travel API, or at least editing the config’s start date). Without it, “testing the event” degenerates into “looked at it the day before launch, then hope” — monitoring instead of testing. If your backend lacks that lever, it’s the first thing worth requesting from the team — more important than any tooling. The rest of the kit: a staging config, client-side config substitution via Proxyman/Charles (Map Local) for quick edge-value checks, and a device with a manually adjustable clock.

The event launch checklist

  • Start/end: explicitly defined, verified in extreme timezones (UTC+13 / UTC-11)
  • Before start / after end: deliberate behavior, the claim grace period decided
  • Clock forward/back and a long flight: server time is the truth
  • Oldest supported client version: event hidden or working, no crash
  • Claim is idempotent: network drop, double tap, second device — one reward
  • Prices/denominations: schema-validated config, range sanity checks
  • Config: staging, prod-edit review, staged rollout, kill switch — present and tested
  • Start and end under load: leaderboard, shop, mass claim
  • Previous event’s leftovers cleaned up; test on a “lived-in” account
  • An on-call person assigned for the launch (especially a weekend one)

The irony of LiveOps is that a “small event” touches all the most dangerous things at once — production, the economy, time, and old clients — while skipping every process that protects a “big release.” Give those processes back to it, and events stop being a weekly roulette.