I'm a Unity developer, and I recently built PikiPlay, a free browser game portal, with Next.js 15, Supabase and Tailwind. Games come from partner feeds plus a few of my own. The catalog keeps growing, so SEO couldn't be a one-time checklist. Here is what I ended up doing, and what I'd tell myself at the start.
- One game, one URL Games used to be reachable by numeric id, by a partner code and by a few older slug spellings. To Google, that is duplicate content.
Now /game/[id] resolves the game, computes its canonical slug, and sends everything else there with a permanent redirect:
const canonical = gameSlug(game);
if (decodeURIComponent(id).trim() !== canonical) {
permanentRedirect(/game/${canonical});
}
The page also sets a canonical URL in generateMetadata, so the redirect and the tag agree.
- Sitemaps that survive a growing catalog A sitemap file is limited to 50,000 URLs, and my catalog only goes up. So /sitemap.xml is an index, and games are split into files of 10,000 URLs each, served from a route handler that reads from Supabase in pages.
Two details that mattered:
I only emit , a real and the image. Google ignores and , and it stops trusting if it is always "now".
Responses are cached (s-maxage with stale-while-revalidate) so crawlers don't hammer the database.
- Structured data with stable @ids Instead of a separate WebSite object on every page, all pages point at one Organization and one WebSite by @id. Game pages add VideoGame, and every page adds a BreadcrumbList. Then Google can tie pages, brand and logo together.
One small security point: JSON.stringify leaves < alone, so text from a feed containing could break out of the JSON-LD tag. I escape it:
JSON.stringify(data).replace(/</g, '\u003c');
Don't index thin pages
Tag pages are a great way to target topic keywords ("card games", "racing games"), but a tag with two games is thin content. Tag pages with too few games render with robots: { index: false, follow: true }, so they stay crawlable for link discovery without diluting the site.ISR instead of fully dynamic pages
Game pages revalidate every 24 hours and tag pages every 12 hours. Crawlers get fast static HTML, and the catalog still stays fresh.Keyword research as code, not a spreadsheet
I keep a typed keyword list in the repo (keyword, search volume, SEO difficulty, target page, status). The rules I follow:
Prefer low difficulty with real volume, not the biggest numbers.
If a keyword is a game name, it maps to that game's page, never to a category.
If I don't host the game, the keyword stays "opportunity" until I pick a stand-in.
Every target URL must return 200 before it goes in the list.
I use Ubersuggest to find competitor keywords and to track rankings. The list lives in version control, so a keyword change is a reviewable diff.
- Telling search engines about new pages I also have an IndexNow endpoint that submits URLs to Bing and others, so new pages need not wait for the next crawl.
What I got wrong
I thought on-page SEO was enough. Bing Webmaster Tools now flags that the site has few links from high-quality domains. Technical SEO gets you crawled; backlinks are what's missing for ranking.
[Add 1-2 real mistakes of your own here: something that broke, a page that got deindexed, a wrong canonical, etc.]
Results so far
[Fill in with real numbers: indexed pages in Search Console, impressions/clicks, how long it took. If numbers are small, say so. Honest small numbers get more trust than vague claims.]
Takeaways
One canonical URL per page, enforced by redirects.
Split sitemaps from day one if the catalog grows.
Don't index thin pages.
Keep keyword mapping in code and check that targets return 200.
Technical SEO is the floor, not the ceiling. Plan for links early.
If you've built something similar, I'd love to hear what worked for you.
Top comments (0)