Back to News & Insights
Web Development August 31, 2026 · 4 min read

How I faked a real-time opponent on shared hosting with zero background processes

Shared hosting has one rule that quietly kills most multiplayer designs: you cannot run a persistent...

How I faked a real-time opponent on shared hosting with zero background processes

Shared hosting has one rule that quietly kills most multiplayer designs: you cannot run a persistent process. No WebSocket server, no daemon, no long-lived worker. Your PHP is born when a request arrives and dies when the response is sent.

I ran into this building a head-to-head word game — two players racing to guess the same five-letter word. The multiplayer part was fine. The problem was what happens when nobody else is online.

An empty matchmaking queue is the fastest way to kill a new game. So I needed a bot. And a bot, conventionally, is a process: something that wakes up every few seconds, decides on a move, and writes it somewhere. That is exactly the thing I could not have.

The instinct is to reach for a cron job that ticks bot games forward. That works, but it is coarse (most shared hosts cap you at one minute), it needs state, and it burns resources on games nobody is watching.

It does not. Nobody observes the bot except the opponent, and the opponent only observes it when they poll for status. If I can compute what the bot would have done by now, at the moment I'm asked, the bot never needs to run at all.

Same inputs, same output, every time. No storage, no scheduler, no race conditions.

The whole thing hinges on randomness that isn't random. Every decision the bot makes is seeded from the battle's own ID:

Separate seeds for separate concerns — one for guess timing, one for which words it picks, one for chat messages:

Because crc32 of a fixed string is stable, battle #4471 produces the same bot every single time it is evaluated. Two polls a second apart return a consistent world. A page refresh doesn't reroll the opponent. Two devices watching the same battle agree.

The _v2 suffix is doing real work, by the way. It is a cheap version namespace: when I want to retune bot behaviour, I bump it and every new battle gets the new personality while in-flight ones stay consistent. Changing the seed string is the migration.

The second trick is that the bot's result is chosen when the battle is created, not discovered as it plays:

It makes difficulty tunable as a distribution rather than emergent from a solver. I am not writing an AI that plays well and then trying to handicap it. I am picking a target outcome — "this bot solves on guess 4" — and then working backwards to a plausible-looking path. Balancing becomes a matter of adjusting probabilities, not rewriting logic.

It also means the bot cannot embarrass itself. A real solver has bad days; it stumbles into a lookalike trap and burns four guesses on PARER / PACER / PAPER. That is realistic and it is a terrible new-player experience.

The reveal is still honest — the bot's guesses appear over time, at human-plausible intervals, and you genuinely can beat it by being faster. What is predetermined is the ceiling, not the race.

which returns both players' progress and any chat. On each call the server recomputes the bot from scratch:

Polling gets a bad reputation it only partly deserves. It is genuinely wasteful for chat apps, live cursors, anything with high-frequency updates. But this game has a handful of state changes over roughly two minutes. The update rate is low. WebSockets would buy me latency I cannot perceive and cost me a server I cannot run.

The general shape is: replace a background process with a deterministic function of time and a stable seed.

It works when the state is derivable from a start timestamp plus fixed parameters, when nobody observes it except on request, and when you can accept computing it repeatedly instead of once. Simulated opponents, staged rollouts, fake-but-consistent activity feeds, scheduled reveals all fit.

Want to discuss this further?

Book a free strategy call with our team to see how these insights apply to your specific business goals.

Book a consultation