Skip to content

SEO

Overview

Playupi’s SEO strategy is built around the fact that every game has a unique, crawlable page with rich metadata. The platform uses server-side rendering (Next.js SSR) so all content is available to search engines without JavaScript execution.

Key Advantages

  • Thousands of unique pages — each game, category, and author gets a dedicated URL
  • SSR by default — all pages are server-rendered and cacheable at the edge
  • Structured data — game pages include JSON-LD markup for rich search results
  • Fast load times — static assets on CDN, game content loads lazily in iframes

URL Structure

Clean, readable, keyword-rich URLs:

PageURL PatternExample
Home/playupi.com
Category/category/:slugplayupi.com/category/action
Game detail/games/:slugplayupi.com/games/subway-surfers
Author/authors/:slugplayupi.com/authors/kiloo-games
Search/search?q=:queryplayupi.com/search?q=puzzle

URL Rules

RuleImplementation
Lowercase onlySlugs are always lowercase
Hyphens as separatorsmy-game-title, never my_game_title or MyGameTitle
No trailing slashes/games/tetris not /games/tetris/. Redirect if accessed with trailing slash
No IDs in URLsUse slugs, not UUIDs. /games/subway-surfers not /games/abc-123
Max lengthSlugs capped at 80 characters
Slug generationAuto-generated from title on creation. Editable by admin. Must be unique
Slug persistenceOnce a game is Visible, changing the slug creates a 301 redirect from the old URL

Meta Tags

Per-Page Tags

Page<title><meta description>OG Image
HomePlayupi — Free Browser Games OnlinePlay hundreds of free browser games instantly. No downloads, no installs.Brand OG image
Category{Category} Games — PlayupiPlay the best {category} games online for free on Playupi.Brand OG image
AuthorGames by {Author} — PlayupiPlay all games from {Author} on Playupi.Brand OG image
Game Detail{Game Title} — Play Free on PlayupiFirst 155 chars of game description + ”…”Game thumbnail
SearchSearch: {query} — PlayupiFind free browser games on Playupi.Brand OG image
404Page Not Found — PlayupiThis page doesn’t exist. Browse our free browser games.Brand OG image

Title Rules

  • Brand name (“Playupi”) always at the end, separated by ” — ”
  • Page-specific keyword at the start (most important for SEO)
  • Max 60 characters (Google truncates longer titles)

Description Rules

  • Max 155 characters
  • Include a call to action (“Play”, “Browse”, “Find”)
  • Game descriptions: use the first 155 chars of the admin-provided description, not auto-generated text
  • Never duplicate titles as descriptions

Open Graph & Social Sharing

Every page includes Open Graph and Twitter Card meta tags for rich previews when shared on social media.

Tags

<!-- Open Graph -->
<meta property="og:type" content="website" />
<meta property="og:site_name" content="Playupi" />
<meta property="og:title" content="{Page Title}" />
<meta property="og:description" content="{Page Description}" />
<meta property="og:url" content="https://playupi.com/games/subway-surfers" />
<meta property="og:image" content="https://playupi.com/og/games/subway-surfers.png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="{Page Title}" />
<meta name="twitter:description" content="{Page Description}" />
<meta name="twitter:image" content="https://playupi.com/og/games/subway-surfers.png" />

OG Image Strategy

Page TypeOG ImageSize
Home, Category, Author, Search, 404Brand OG image: “Playupi” wordmark + tagline on branded background1200x630
Game DetailGame thumbnail overlaid on branded template (game icon + title + “Play Free on Playupi”)1200x630

Game OG images can be dynamically generated using Next.js ImageResponse (or @vercel/og):

app/games/[slug]/opengraph-image.tsx
import { ImageResponse } from 'next/og'
export default async function OGImage({ params }) {
const game = await getGame(params.slug)
return new ImageResponse(
<div style={{ /* branded template with game.title, game.thumbnailUrl */ }} />,
{ width: 1200, height: 630 }
)
}

Structured Data (JSON-LD)

Game Detail Page

{
"@context": "https://schema.org",
"@type": "VideoGame",
"name": "Subway Surfers",
"description": "Run, dodge trains, and collect coins in this endless runner.",
"url": "https://playupi.com/games/subway-surfers",
"image": "https://playupi.com/thumbnails/subway-surfers.png",
"author": {
"@type": "Organization",
"name": "Kiloo Games",
"url": "https://playupi.com/authors/kiloo-games"
},
"genre": ["Action", "Arcade"],
"playMode": "SinglePlayer",
"gamePlatform": ["Web Browser"],
"operatingSystem": "Any",
"applicationCategory": "Game",
"offers": {
"@type": "Offer",
"price": "0",
"priceCurrency": "USD"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": 4.2,
"ratingCount": 1580,
"bestRating": 5,
"worstRating": 1
}
}

Note: aggregateRating should only be included once a star-rating system is implemented (future feature). For MVP, use like/dislike ratio to approximate, or omit the rating block.

Category Page

{
"@context": "https://schema.org",
"@type": "CollectionPage",
"name": "Action Games",
"description": "Play the best action games online for free on Playupi.",
"url": "https://playupi.com/category/action",
"mainEntity": {
"@type": "ItemList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"url": "https://playupi.com/games/subway-surfers"
}
]
}
}

Home Page

{
"@context": "https://schema.org",
"@type": "WebSite",
"name": "Playupi",
"url": "https://playupi.com",
"description": "Play hundreds of free browser games instantly.",
"potentialAction": {
"@type": "SearchAction",
"target": "https://playupi.com/search?q={search_term_string}",
"query-input": "required name=search_term_string"
}
}

The SearchAction enables Google’s sitelinks search box (search directly from the SERP).


Sitemap

Generation

Auto-generate sitemap.xml at build time or on-demand (ISR):

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://playupi.com/</loc>
<changefreq>daily</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://playupi.com/category/action</loc>
<changefreq>daily</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://playupi.com/games/subway-surfers</loc>
<lastmod>2026-02-10</lastmod>
<changefreq>weekly</changefreq>
<priority>0.7</priority>
</url>
</urlset>

Rules

RuleDetail
Only visible gamesDraft and Hidden games are excluded
Sitemap indexIf > 50K URLs, split into multiple sitemaps with a sitemap index
lastmodUse game.updatedAt for game pages, current date for Home/category
changefreqHome: daily. Categories: daily. Games: weekly. Authors: weekly
priorityHome: 1.0. Categories: 0.8. Games: 0.7. Authors: 0.5
Auto-submitReference sitemap in robots.txt. Google auto-discovers it

Next.js Implementation

app/sitemap.ts
export default async function sitemap() {
const games = await getVisibleGames()
const categories = await getCategories()
return [
{ url: 'https://playupi.com', changeFrequency: 'daily', priority: 1 },
...categories.map(cat => ({
url: `https://playupi.com/category/${cat.slug}`,
changeFrequency: 'daily',
priority: 0.8,
})),
...games.map(game => ({
url: `https://playupi.com/games/${game.slug}`,
lastModified: game.updatedAt,
changeFrequency: 'weekly',
priority: 0.7,
})),
]
}

Robots.txt

User-agent: *
Allow: /
Disallow: /api/
Disallow: /admin/
Sitemap: https://playupi.com/sitemap.xml
RuleReason
Block /api/API responses are not useful as search results
Block /admin/Admin dashboard should never be indexed
Allow everything elseAll public pages should be crawlable

Canonical URLs

Every page includes a <link rel="canonical"> tag pointing to the definitive URL.

ScenarioCanonical
Normal pageSelf-referencing (https://playupi.com/games/tetris)
Page with query params (pagination, filters)Base URL without params (https://playupi.com/category/action)
Old slug (after rename)301 redirect to new slug — no canonical needed
Duplicate content (same game, different URL)Point to the primary URL
<link rel="canonical" href="https://playupi.com/games/tetris" />

Pagination SEO

Game list pages (Home, category, author) use pagination. Search engines need to understand the relationship between pages.

Load More / Infinite Scroll

If using “Load More” button or infinite scroll:

  • The initial page contains the first N games and is the only URL indexed
  • Loaded-more content is added to the DOM via JavaScript — not crawlable
  • This is fine for SEO because the most relevant (highest-ranked) games are on the initial page

Paginated URLs (alternative)

If using ?page=N pagination:

<!-- Page 1 -->
<link rel="next" href="https://playupi.com/category/action?page=2" />
<!-- Page 2 -->
<link rel="prev" href="https://playupi.com/category/action" />
<link rel="next" href="https://playupi.com/category/action?page=3" />
<!-- Last page -->
<link rel="prev" href="https://playupi.com/category/action?page=4" />

Canonical for all paginated pages points to the base URL (page 1 without ?page=).


Core Web Vitals

Google uses Core Web Vitals as a ranking signal. Gaming platforms are at risk for poor scores due to heavy iframe content.

Targets

MetricTargetRisk Area
LCP (Largest Contentful Paint)< 2.5sGame grid images, hero area
INP (Interaction to Next Paint)< 200msSearch input, filter changes, card clicks
CLS (Cumulative Layout Shift)< 0.1Image loading without dimensions, late-loading ads

Optimizations

OptimizationDetail
Image dimensionsAlways set width and height on game thumbnails to prevent CLS
Lazy loadingGame thumbnails below the fold use loading="lazy"
Priority hintsFirst 6 game card images use fetchpriority="high"
Image formatServe WebP with JPEG fallback. Use Next.js <Image> for automatic optimization
Iframe lazy loadGame iframe uses loading="lazy" — only loads when user scrolls to it (desktop) or taps Play (mobile)
Font loadingInter loaded via next/font (self-hosted, no layout shift). Use font-display: swap
SSR + Edge cachingGame list pages are SSR-cached at the edge (Vercel). TTL: 60s with stale-while-revalidate
Preconnect<link rel="preconnect"> to broker CDN domains for faster iframe load
<link rel="preconnect" href="https://html5.gamedistribution.com" />
<link rel="dns-prefetch" href="https://html5.gamedistribution.com" />

Internal Linking

Strong internal linking helps search engines discover all pages and understand content hierarchy.

Home ──► Category pages ──► Game pages
│ │
└──► Game pages └──► Author page
└──► Related category pages
└──► Recommended game pages
PageLinks To
HomeAll category pages (sidebar), top game pages (grid)
CategoryGame pages in that category, other categories (sidebar)
Game DetailAuthor page, category pages (tags), recommended games, “more by author”
AuthorGame pages by that author, categories (sidebar)

Anchor Text

  • Game cards: game title as anchor text (visible on hover, always in DOM for crawlers)
  • Category links: category name
  • Author links: author name
  • Avoid generic anchor text (“click here”, “read more”)

Image SEO

Alt Text

ImageAlt Text Pattern
Game thumbnail (grid)"{Game Title} — free online {primary category} game"
Game icon (detail page)"{Game Title} game icon"
Category icon"{Category Name} games"
Author avatar (future)"{Author Name} — game developer"

Image Optimization

RuleDetail
FormatWebP primary, JPEG fallback
SizesThumbnails served at 256px, 512px (responsive via srcset)
CompressionQuality 80 for thumbnails (visually lossless)
CDNAll images served through CDN with cache headers
FilenamesUse slugs: subway-surfers-thumb.webp not abc123.webp

Crawl Budget

With thousands of game pages, efficient crawl budget usage matters.

StrategyImplementation
Sitemap priorityHigher-ranked games get higher priority in sitemap
Block low-value pagesAPI routes, admin pages blocked in robots.txt
Server response speedTarget < 200ms TTFB for all public pages
Avoid soft 404sHidden/Draft games return proper 404, not an empty page
Clean URL paramsUse Google Search Console to indicate which params to ignore
No orphan pagesEvery visible game must be reachable from at least one category or the Home page

International SEO (Future)

Not in MVP. When multi-language support is added:

StepDetail
URL structureSubdirectory: playupi.com/fr/games/..., playupi.com/es/games/...
hreflang tags<link rel="alternate" hreflang="fr" href="https://playupi.com/fr/games/tetris" />
Default languageEnglish (hreflang="en") with x-default fallback
Translated contentGame titles and descriptions translated. Slugs stay in English for URL stability
SitemapSeparate sitemap per language, or multi-language sitemap with hreflang

See Decisions → Open Questions for i18n status.


Search Console Setup

After launch, configure Google Search Console:

  1. Verify ownership via DNS TXT record or HTML meta tag
  2. Submit sitemap at https://playupi.com/sitemap.xml
  3. Monitor coverage report for crawl errors, excluded pages, indexing issues
  4. Check Core Web Vitals report for performance regressions
  5. Review search performance (queries, clicks, impressions, position) weekly

Key Reports to Watch

ReportWhat to Look For
CoverageIncreasing indexed pages as new games are added. Zero “Excluded — server error”
PerformanceClick-through rate by page type. Brand vs non-brand query split
Core Web VitalsAll pages in “Good” status. Flag any regressions
SitemapsAll submitted URLs discovered and indexed
RemovalsNo unexpected pages flagged for removal