DEV Community

Daniel Mercer
Daniel Mercer

Posted on

How we generate thumbnails for 56,000 browser games without a render farm

Every game on GameZiko needs a thumbnail. Fifty-six thousand games means fifty-six thousand thumbnails, and they are the first thing a visitor sees. A slow or broken thumbnail pipeline means a homepage full of grey boxes, which means nobody clicks anything. Here is how we built a pipeline that keeps up, on a budget that would make a render farm laugh.

The naive approach (and why it died)

Our first version was simple: when a game was added, a headless browser screenshotted it. This worked for the first thousand games and then fell over. Headless Chrome eats roughly 300MB per instance, screenshots take 3 to 8 seconds each, and game pages with animated ads or video pre-rolls produced garbage captures half the time. At 56,000 games, the math was brutal: weeks of continuous rendering, and any game update meant re-running the whole thing.

What we do now: three tiers

Tier 1: publisher art first. Most HTML5 games ship with a cover image from the developer. We fetch it, validate it (real image, reasonable dimensions, not a 404 page saved as a PNG), and use it. This covers about 70 percent of the library with zero rendering cost.

Tier 2: screenshot service, but lazy. For games without usable art, we screenshot on demand, not upfront. The first visitor to a game page triggers a background capture job; until it completes, the game shows a generated placeholder with the game's title and category colors. Because long-tail games get their first visit weeks after being added, the rendering load spreads itself naturally over time instead of arriving as one giant batch.

Tier 3: generated placeholders that do not look broken. The placeholder matters more than you would think. Our first placeholder was a grey box, and click-through on unthumbnailed games was near zero. The current one uses the game's title, a category-tinted gradient, and a simple gamepad glyph. It looks intentional. Click-through recovered to about 60 percent of games with real art, which buys the screenshot queue time to catch up.

The boring details that actually matter

Deduplication. The same game gets submitted under different names constantly. We perceptual-hash every thumbnail and merge duplicates before they multiply. This alone cut our storage by about a third.

Format discipline. Everything is served as WebP with a JPEG fallback, resized to exactly the three sizes the frontend uses (card, list, hero). No on-the-fly resizing in production, ever. The resize happens once, at ingest.

Validation as a gate. Every image goes through a check: is it actually an image, is it bigger than 10KB (smaller usually means a broken capture), and does it pass a simple "not mostly one color" test (catches blank white captures from failed loads). Failures go back into the queue with a retry counter instead of silently shipping grey boxes.

What I would do differently

I would have built the placeholder system first. We spent months treating missing thumbnails as a rendering problem when it was really a UX problem. A good placeholder plus lazy rendering beats a perfect pipeline that takes six weeks to process the backlog.

If you run any kind of large catalog, game portal or otherwise, the lesson generalizes: make the missing state look deliberate, render lazily, and validate everything at ingest. Your homepage will thank you.

Top comments (0)