StatsHub Docs
Audits

StatsHub SEO Audit Report

A full technical SEO review of the web app as it stood on 2026-01-29 — per-page grades, missing schema, and the fixes proposed at the time.

Date: January 29, 2026 Framework: Next.js 14.2.18 (Pages Router) Pages Audited: 32 (30 routes + 2 global files)


Executive Summary

Overall Health: ⚠️ Mixed

StatsHub has strong SEO foundations on key pages (homepage, blog, betting-academy, referees, stats-explained, odds-converter) but significant gaps on tool pages and the entire basketball section.

Top 5 Priority Issues

  1. Basketball pages have zero SEO — All 3 basketball dynamic routes (fixture, player, team) use generic football-focused MetaTags with no dynamic data, no structured data, and hardcoded og
    to the homepage. Grade: F
  2. Tool pages missing all SEO tags — /prop-screener, /team-screener, and /value-bets have no title, meta description, canonical URL, OG tags, or structured data. Grade: F
  3. MetaTags component og
    bug
    — The default MetaTags component hardcodes og:url to https://statshub.com/ for all pages, causing incorrect OG URLs across 8+ pages.
  4. Client-side rendering on indexable pages — Most static content pages (features, free-tools, odds-converter, player-stats, team-stats) use CSR instead of SSG, meaning crawlers may not see content.
  5. League/Team dynamic meta tags invisible to crawlers — Rich meta tag data (season, team count, champion) depends on client-side SWR fetches, so SSR HTML lacks this information.

Quick Wins

  • Add <Head> blocks with title/description to /prop-screener, /team-screener, /value-bets (~30 min)
  • Fix /lineup-bot canonical from statshub.io to statshub.com (~1 min)
  • Add <meta name="robots" content="noindex" /> to /404 and /favourites (~5 min)
  • Fix &apos; HTML entities in meta descriptions on /free-tools and /odds-converter (~5 min)
  • Add getStaticProps to purely static pages like /features, /free-tools, /odds-converter (~15 min each)

Global Files Audit

_document.tsx

File: src/pages/_document.tsx

CheckStatusDetails
HTML lang✅<Html lang="en"> properly set
Viewport✅Configured with viewport-fit=cover for notch support
Favicons✅32x32, 16x16, apple-touch-icon all present
PWA Manifest✅/manifest.json linked
PWA Meta Tags✅application-name, theme-color, apple-mobile-web-app-capable
Analytics✅Google Analytics (G-FNRHWN8908) + Umami analytics
Default Title❌No default <title> fallback — pages without Head will show no title

Issues:

  • Viewport meta tag is in _document.tsx Head, but Next.js recommends putting viewport in _app.tsx or per-page. Having it here works but triggers a Next.js warning.
  • No default <title> tag — pages that forget to add their own will have no title.

Recommendations:

  • Add a default <title>StatsHub | Free Football & Basketball Stats</title> as a fallback.
  • Consider moving viewport to next.config.js viewport export.

_app.tsx

File: src/pages/_app.tsx

CheckStatusDetails
Error Boundary✅Wraps entire app
Theme Support✅next-themes with system default
Layout System✅Per-page layouts via getLayout
SWR Config✅Deduplication and revalidation configured
Global SEO❌No global meta tags, no DefaultSeo component

Issues:

  • No global SEO defaults (e.g., next-seo's DefaultSeo) — each page must independently define all meta tags.

Recommendations:

  • Consider adding a global SEO defaults component that provides fallback title, description, OG tags for any page that doesn't override them.

Static Pages

/

File: src/pages/index.tsx | Rendering: CSR

CheckStatusDetails
Title Tag✅"Free Football & Player Stats -- Shots, Tackles + More | StatsHub" (64 chars — slightly over 60)
Meta Description✅Present, ~170 chars. Slightly over 160 but keyword-rich
Open Graph Tags✅Full suite: og
, og
, og
, og
, og
, og
, og
, og
dimensions
Twitter Card Tags✅Full suite: twitter
, twitter
, twitter
, twitter
, twitter
, twitter
Canonical URL✅Self-referencing: https://statshub.com
H1 Tag⚠️"Today's Football Fixtures, Player Stats & Team Stats" — keyword-rich, but two H1 tags on page
Heading Hierarchy⚠️Two H1s detected. H2/H3 follow logically after the first H1
Structured Data✅Excellent — WebSite, FAQPage, Organization, and dynamic SportsEvent ItemList schemas
Image Alt Text✅Tournament logos, team logos all have alt attributes
Rendering⚠️CSR only — fixture data fetched client-side, not visible to crawlers

Issues:

  • Two H1 tags on the page
  • Title 64 chars (slightly over 60)
  • Meta description ~170 chars (over 160)
  • CSR — fixture data invisible to crawlers

Recommendations:

  • Reduce to single H1
  • Trim title to under 60 chars
  • Trim description to 150-160 chars
  • Add getServerSideProps or getStaticProps with ISR for fixture data

/100-club

File: src/pages/100-club.tsx | Rendering: CSR

CheckStatusDetails
Title Tag⚠️Generic default from MetaTags — not specific to 100% Club
Meta Description⚠️Generic default — not page-specific
Open Graph Tags⚠️Generic, og
points to homepage
Twitter Card Tags⚠️Generic defaults
Canonical URL❌Not set
H1 Tag✅"100% CLUB"
Heading Hierarchy⚠️H1 followed by H4, H3, H2 — skips levels
Structured Data❌None
Image Alt Text✅AvatarImage has alt attributes
Rendering❌CSR only — no content for crawlers

Issues:

  • All meta tags are generic defaults
  • No canonical URL, no structured data
  • Heading hierarchy broken (H1 → H4)
  • CSR with no pre-rendered content

Recommendations:

  • Add custom title: "100% Club - Perfect Hit Rate Player Props | StatsHub" (~55 chars)
  • Add page-specific meta description
  • Add canonical: https://statshub.com/100-club
  • Fix heading hierarchy: H1 → H2 → H3
  • Add WebPage JSON-LD

/favourites

File: src/pages/favourites.tsx | Rendering: SSR (empty props)

CheckStatusDetails
Title Tag⚠️Generic default
Meta Description⚠️Generic default
Open Graph Tags⚠️Two meta tag components (MetaTags + EnhancedMetaTags) may conflict
Twitter Card Tags⚠️Generic defaults
Canonical URL❌Not set
H1 Tag✅"MY FAVORITES" / "Sign in to view favorites"
Heading Hierarchy⚠️Acceptable but user-specific, not SEO-oriented
Structured Data❌None
Image Alt Text✅Alt attributes present
Rendering⚠️SSR returns empty props — effectively CSR

Issues:

  • Auth-gated page with generic meta tags
  • Two meta tag components may cause duplicate tags
  • getServerSideProps returns empty props

Recommendations:

  • Add <meta name="robots" content="noindex, nofollow" /> — this is a user-private page
  • Remove duplicate MetaTags + EnhancedMetaTags — use one approach

/features

File: src/pages/features.tsx | Rendering: CSR

CheckStatusDetails
Title Tag⚠️"Football Stats Tools & player stats features | StatsHub PropHunter + More" (74 chars — too long)
Meta Description✅Present, ~155 chars, keyword-rich
Open Graph Tags⚠️Missing og
and og
Twitter Card Tags⚠️Missing twitter
and twitter
Canonical URL❌Not set
H1 Tag✅"Powerful Football Analytics Features"
Heading Hierarchy✅Good: H1 → H2 → H3
Structured Data✅WebPage + SoftwareApplication with featureList
Image Alt Text⚠️N/A — uses Lucide icons
Rendering⚠️CSR — entirely static content, should be SSG

Issues:

  • Title too long (74 chars)
  • Missing og
    , og
    , twitter
    , twitter
  • No canonical URL
  • Static content rendered client-side

Recommendations:

  • Shorten title to ~55 chars: "Football Analytics Features & Tools | StatsHub"
  • Add missing OG/Twitter tags
  • Add canonical: https://statshub.com/features
  • Add getStaticProps for SSG

/free-tools

File: src/pages/free-tools.tsx | Rendering: CSR

CheckStatusDetails
Title Tag✅"Free Football Betting Tools & Analytics | StatsHub" (51 chars)
Meta Description⚠️Contains &apos; HTML entity that renders literally
Open Graph Tags✅Full suite present
Twitter Card Tags⚠️Missing twitter
Canonical URL✅Self-referencing: https://statshub.com/free-tools
H1 Tag✅"Free Football Betting Tools"
Heading Hierarchy✅Good: H1 → H2 → H3 → H4
Structured Data✅WebPage + BreadcrumbList
Image Alt Text⚠️N/A — Lucide icons
Rendering⚠️CSR — static content ideal for SSG

Issues:

  • &apos; in meta description won't render as apostrophe
  • Missing twitter
  • Static content should use SSG

Recommendations:

  • Fix &apos; → ' in meta description
  • Add twitter
  • Add getStaticProps for SSG

/lineup-bot

File: src/pages/lineup-bot.tsx | Rendering: SSG

CheckStatusDetails
Title Tag✅"Lineup Hunter AI - Premium Betting Intelligence | Statshub" (60 chars)
Meta Description⚠️Present but only 112 chars — under 150 target
Open Graph Tags⚠️Missing og
, og
, og
Twitter Card Tags❌No Twitter Card tags at all
Canonical URL⚠️Points to statshub.io instead of statshub.com — wrong domain
H1 Tag✅"Detect Lineup Changes. Exploit Mispriced Odds."
Heading Hierarchy✅Good: H1 → H2 → H3
Structured Data❌None
Image Alt Text⚠️No images on page
Rendering✅SSG via getStaticProps

Issues:

  • Canonical URL uses wrong domain (statshub.io vs statshub.com)
  • No Twitter Card tags
  • Missing og
    , og
    , og
  • No structured data
  • Brand inconsistency: "Statshub" vs "StatsHub"

Recommendations:

  • Fix canonical to https://statshub.com/lineup-bot
  • Add Twitter Card tags
  • Add missing OG tags
  • Add Product or Service structured data
  • Expand meta description to 150-160 chars
  • Standardize brand to "StatsHub"

/odds-converter

File: src/pages/odds-converter.tsx | Rendering: CSR

CheckStatusDetails
Title Tag⚠️"Odds Converter | Convert Fractional, Decimal & American Odds Instantly" (72 chars — over 60)
Meta Description✅~155 chars, keyword-rich
Open Graph Tags✅Full suite present
Twitter Card Tags⚠️Missing twitter
Canonical URL✅Self-referencing: https://statshub.com/odds-converter
H1 Tag✅"Odds Converter"
Heading Hierarchy✅Excellent: H1 → H2 → H3
Structured Data✅Excellent — WebPage, FAQPage, BreadcrumbList, VideoObject
Image Alt Text⚠️YouTube iframe has title but no img tags
Rendering⚠️CSR — static content ideal for SSG

Issues:

  • Title 72 chars — will be truncated
  • Missing twitter
  • &apos; HTML entity in FAQ JSON-LD
  • Static content should use SSG

Recommendations:

  • Shorten title to ~60 chars
  • Add twitter
  • Fix &apos; in FAQ data
  • Add getStaticProps — best candidate for SSG template

/outliers

File: src/pages/outliers.tsx | Rendering: CSR

CheckStatusDetails
Title Tag⚠️Generic default — not specific to outliers
Meta Description⚠️Generic default
Open Graph Tags⚠️Generic, og
points to homepage
Twitter Card Tags⚠️Generic defaults
Canonical URL❌Not set
H1 Tag✅"Betting Market Outliers"
Heading Hierarchy⚠️Only H1 — no H2 or H3 subheadings
Structured Data❌None
Image Alt Text⚠️No images
Rendering❌CSR only — crawlers see empty page

Issues:

  • All meta tags generic, no canonical, no structured data
  • No heading hierarchy below H1
  • CSR with no content for crawlers

Recommendations:

  • Add custom title: "Betting Market Outliers - Odds Discrepancy Finder | StatsHub"
  • Add page-specific meta description
  • Add canonical: https://statshub.com/outliers
  • Add WebPage JSON-LD
  • Add H2 section headings

/player-stats

File: src/pages/player-stats.tsx | Rendering: CSR

CheckStatusDetails
Title Tag⚠️"Football Player Stats -- xG, Shots, Tackles, Shots On Target & More | StatsHub" (74 chars — too long)
Meta Description✅156 chars, compelling and keyword-rich
Open Graph Tags✅Full suite present
Twitter Card Tags✅Full suite present
Canonical URL✅Self-referencing: https://statshub.com/player-stats
H1 Tag✅"Explore Player Stats in One Place"
Heading Hierarchy✅Logical: H1 → H2 → H3
Structured Data✅WebPage + BreadcrumbList + FAQPage (5 questions)
Image Alt Text⚠️No images — emoji icons used
Rendering⚠️CSR — static content should use SSG

Issues:

  • Title 74 chars — will be truncated
  • Duplicate MetaTags component alongside custom Head tags
  • Static content using CSR

Recommendations:

  • Shorten title to ~58 chars
  • Remove MetaTags component (custom Head already defines everything)
  • Add getStaticProps for SSG

/prop-screener

File: src/pages/prop-screener.tsx | Rendering: CSR

CheckStatusDetails
Title Tag❌No title — only generic MetaTags default
Meta Description❌No page-specific description
Open Graph Tags❌Generic defaults, og
points to homepage
Twitter Card Tags❌Generic defaults
Canonical URL❌Not set
H1 Tag✅"PROP SCREENER"
Heading Hierarchy⚠️H1 present, no H2s, H3 used for empty states
Structured Data❌None
Image Alt Text⚠️No images
Rendering⚠️CSR — acceptable for dynamic tool but shell could be SSR

Issues:

  • Missing all page-specific SEO: title, description, canonical, OG, Twitter, JSON-LD

Recommendations:

  • Add title: "Prop Screener - Filter Player Props by Hit Rate & Odds | StatsHub"
  • Add meta description targeting "prop screener", "player props"
  • Add canonical: https://statshub.com/prop-screener
  • Add WebApplication JSON-LD

/prophunter

File: src/pages/prophunter.tsx | Rendering: SSR

CheckStatusDetails
Title Tag⚠️"PropHunter -- Find Value in Player Props Using Football player Stats | StatsHub" (82 chars — too long)
Meta Description⚠️176 chars — over 160 target
Open Graph Tags✅Full suite present
Twitter Card Tags✅Full suite present
Canonical URL✅Self-referencing: https://statshub.com/prophunter
H1 Tag✅"PROP HUNTER"
Heading Hierarchy⚠️H1 only — no H2/H3 in page content
Structured Data❌None
Image Alt Text⚠️No standard images visible
Rendering✅SSR via GetServerSideProps

Issues:

  • Title 82 chars — too long
  • Meta description 176 chars — too long
  • "Football player Stats" should be "Football Player Stats" (capitalization)
  • No structured data

Recommendations:

  • Shorten title to ~60 chars
  • Trim description to 155-160 chars
  • Fix capitalization
  • Add WebApplication JSON-LD

/referees

File: src/pages/referees.tsx | Rendering: CSR

CheckStatusDetails
Title Tag✅"Football Referee Stats & Card Statistics | StatsHub" (51 chars)
Meta Description✅161 chars — just 1 char over ideal
Open Graph Tags✅Full suite present
Twitter Card Tags✅Full suite present
Canonical URL✅Self-referencing: https://statshub.com/referees
H1 Tag✅"Referee Stats"
Heading Hierarchy✅H1 → H2 (FAQ) with accordion items
Structured Data✅FAQPage with 8 questions
Image Alt Text✅alt={referee.name} on all avatars
Rendering⚠️CSR — data fetched via SWR

Issues:

  • Description 1 char over 160 limit
  • CSR means referee data table not visible to crawlers on first load

Recommendations:

  • Trim description by 1-2 chars
  • Consider SSR for initial data table rendering
  • Add WebPage JSON-LD alongside FAQPage

/stats-explained

File: src/pages/stats-explained.tsx | Rendering: SSG (ISR, daily)

CheckStatusDetails
Title Tag⚠️"Football Stats Explained | Complete 2025 Guide to Player Stats & Football Statistics - StatsHub" (94 chars — very long)
Meta Description✅145 chars, keyword-rich
Open Graph Tags✅Full suite with image dimensions and alt text
Twitter Card Tags✅Full suite with image alt
Canonical URL✅Self-referencing: https://statshub.com/stats-explained
H1 Tag✅"Football Stats Explained"
Heading Hierarchy✅Excellent: H1 → H2 → H3 → H4
Structured Data✅Article + FAQPage — both well-structured
Image Alt Text⚠️No images — emoji icons
Rendering✅SSG with ISR (revalidate: 86400)

Issues:

  • Title 94 chars — far too long
  • Contains "2025" which is now outdated (January 2026)

Recommendations:

  • Shorten title to ~60 chars: "Football Stats Explained - xG, Passes & More | StatsHub"
  • Update or remove the year reference
  • Best-optimized page — use as template for others

/team-screener

File: src/pages/team-screener.tsx | Rendering: CSR

CheckStatusDetails
Title Tag❌No title — generic MetaTags default
Meta Description❌No page-specific description
Open Graph Tags❌Generic defaults
Twitter Card Tags❌Generic defaults
Canonical URL❌Not set
H1 Tag✅"TEAM SCREENER"
Heading Hierarchy⚠️H1 → H3 (no H2)
Structured Data❌None
Image Alt Text⚠️No images
Rendering⚠️CSR

Issues:

  • Missing all page-specific SEO tags

Recommendations:

  • Add title: "Team Screener - Filter Team Props by Odds & Hit Rates | StatsHub"
  • Add meta description, canonical, OG tags, Twitter cards, JSON-LD

/team-stats

File: src/pages/team-stats.tsx | Rendering: CSR

CheckStatusDetails
Title Tag⚠️"Football Stats | Soccer Statistics | Form Tables | StatsHub" (58 chars) — doesn't mention "Team Stats"
Meta Description⚠️133 chars — under 150 target
Open Graph Tags✅Full suite present
Twitter Card Tags✅Full suite present
Canonical URL✅Self-referencing: https://statshub.com/team-stats
H1 Tag✅"Comprehensive Team Stats"
Heading Hierarchy✅Excellent: H1 → H2 → H3
Structured Data✅WebPage + BreadcrumbList + FAQPage
Image Alt Text⚠️No images — emoji icons
Rendering⚠️CSR — static content should be SSG

Issues:

  • Title doesn't mention "Team Stats" which is the page focus
  • Description too short (133 chars)
  • Duplicate MetaTags component
  • Static content using CSR

Recommendations:

  • Update title: "Football Team Stats - Goals, xG, Shots & More | StatsHub"
  • Expand description to 150-160 chars
  • Remove MetaTags component
  • Add getStaticProps for SSG

/value-bets

File: src/pages/value-bets.tsx | Rendering: CSR

CheckStatusDetails
Title Tag❌No title — generic MetaTags default
Meta Description❌No page-specific description
Open Graph Tags❌Generic defaults
Twitter Card Tags❌Generic defaults
Canonical URL❌Not set
H1 Tag✅"Value Bets"
Heading Hierarchy⚠️H1 only — no semantic sub-sections
Structured Data❌None
Image Alt Text✅alt={source} and alt={bet.source} present
Rendering⚠️CSR

Issues:

  • Missing all page-specific SEO tags

Recommendations:

  • Add title: "Value Bets - Football Betting Edge Finder | StatsHub"
  • Add meta description, canonical, OG tags, Twitter cards, JSON-LD

/404

File: src/pages/404.tsx | Rendering: SSG (Next.js default)

CheckStatusDetails
Title Tag❌No Head component at all
Meta Description❌None
Open Graph Tags❌None
Twitter Card Tags❌None
Canonical URL❌N/A for 404
H1 Tag✅"404 - Page Not Found"
Heading Hierarchy✅Single H1 — appropriate for 404
Structured Data❌N/A for 404
Image Alt Text⚠️No images
Rendering✅SSG (default for 404)

Issues:

  • No <Head> — browser tab shows default/empty title
  • No <meta name="robots" content="noindex"> to prevent indexing

Recommendations:

  • Add <Head> with title: "404 - Page Not Found | StatsHub"
  • Add <meta name="robots" content="noindex, nofollow" />

Index / Landing Pages

/blog

File: src/pages/blog/index.tsx | Rendering: SSG (ISR, revalidate: 60s)

CheckStatusDetails
Title Tag⚠️"Football Blog | Expert Analysis, Player Stats & Football Insights - StatsHub" (74 chars — over 60)
Meta Description⚠️183 chars — over 160 target
Open Graph Tags✅Full suite with image dimensions and alt text
Twitter Card Tags✅Full suite with image alt
Canonical URL✅Self-referencing: https://statshub.com/blog
H1 Tag✅"Football Blog & Expert Analysis"
Heading Hierarchy✅H1 → H2 → H3
Structured Data✅Blog with BlogPosting items + FAQPage
Image Alt Text⚠️Depends on CardArticleUnified component
Rendering✅SSG with ISR

Issues:

  • Title 74 chars — will be truncated
  • Description 183 chars — over limit
  • Generic og

Recommendations:

  • Shorten title to ~55 chars
  • Trim description to 155 chars
  • Create unique blog-specific og

/betting-academy

File: src/pages/betting-academy/index.tsx | Rendering: SSG (ISR, revalidate: 60s)

CheckStatusDetails
Title Tag⚠️"Betting Academy | Expert Betting Guides & Strategies - StatsHub" (65 chars — slightly over)
Meta Description⚠️169 chars — slightly over 160 target
Open Graph Tags✅Full suite with dimensions
Twitter Card Tags✅Full suite with alt
Canonical URL✅Self-referencing: https://statshub.com/betting-academy
H1 Tag✅"StatsHub Betting Academy"
Heading Hierarchy✅H1 → H2 → H3
Structured Data✅EducationalOrganization + FAQPage
Image Alt Text⚠️Depends on CardArticleUnified component
Rendering✅SSG with ISR

Issues:

  • Title 65 chars — slightly over
  • Description 169 chars — slightly over
  • EducationalOrganization schema uses courseMode/teaches which belong to Course schema

Recommendations:

  • Trim title to ~55 chars
  • Trim description to 155 chars
  • Fix JSON-LD type or remove non-standard properties
  • Create unique og

/league

File: src/pages/league/index.tsx | Rendering: CSR

CheckStatusDetails
Title Tag❌No Head component at all
Meta Description❌None
Open Graph Tags❌None
Twitter Card Tags❌None
Canonical URL❌None
H1 Tag✅"Football Leagues"
Heading Hierarchy✅H1 → H2 ("Popular Leagues", "All Leagues") → H3
Structured Data❌None
Image Alt Text✅alt={league.name} present
Rendering❌CSR via useSWR — crawlers see empty shell

Issues:

  • Most SEO-deficient page in the audit — no Head, no meta tags, no structured data, CSR only
  • League list invisible to crawlers

Recommendations:

  • Add full <Head> block with title, description, OG tags, Twitter cards
  • Add canonical: https://statshub.com/league
  • Add getStaticProps or getServerSideProps to pre-render league list
  • Add ItemList or CollectionPage JSON-LD
  • Critical fix — this is a high-value SEO page

/basketball

File: src/pages/basketball/index.tsx | Rendering: CSR

CheckStatusDetails
Title Tag✅"Basketball Games & Scores | StatsHub" (43 chars)
Meta Description⚠️119 chars — under 150 target
Open Graph Tags⚠️Missing og
, og
, og
Twitter Card Tags❌None present
Canonical URL✅https://statshub.com/basketball
H1 Tag✅"Today's Basketball Games & Scores"
Heading Hierarchy✅H1 → H2
Structured Data❌None
Image Alt Text✅Alt attributes on team/tournament images
Rendering❌CSR via useSWR — game data invisible to crawlers

Issues:

  • Short meta description (119 chars)
  • Missing OG tags (og
    , og
    , og
    )
  • No Twitter Card tags
  • No structured data
  • CSR only

Recommendations:

  • Expand description to 150-160 chars
  • Add missing OG and Twitter Card tags
  • Add SportsEvent or WebPage JSON-LD
  • Consider SSR for game data

Dynamic Route Templates

/betting-academy/[slug]

File: src/pages/betting-academy/[slug].tsx | Rendering: SSG (ISR, revalidate: 60s)

CheckStatusDetails
Title Tag✅Dynamic: {post.title} - StatsHub Betting Academy
Meta Description✅Dynamic: uses post.metaDescription from CMS
Open Graph Tags✅All present with dynamic data, conditional cover image
Twitter Card Tags✅summary_large_image with dynamic data
Canonical URL✅Dynamic: https://statshub.com/betting-academy/${post.slug}
H1 Tag✅Dynamic from post.title via BlogHero
Heading Hierarchy✅H1 in hero, H2/H3 via markdown renderer
Structured Data✅Article schema with dynamic headline, dates, author, publisher
Image Alt Text⚠️Depends on BlogHero component
Rendering✅SSG with ISR
Dynamic SEO✅All meta tags fully data-driven

Issues: None significant. Best-optimized page in the codebase.

Recommendations:

  • Verify BlogHero applies alt text to cover image
  • Consider adding twitter:site handle

/fixture/[fixtureSlug]/[fixtureId]

File: src/pages/fixture/[fixtureSlug]/[fixtureId].tsx | Rendering: SSR

CheckStatusDetails
Title Tag✅Dynamic: {team1} vs {team2} {date} | Live Stats, H2H, Lineups & Analysis
Meta Description✅Dynamic with both team names and date
Open Graph Tags✅Full suite via EnhancedMetaTags
Twitter Card Tags✅summary_large_image with dynamic data
Canonical URL✅Dynamic: https://statshub.com/fixture/{slug}/{id}
H1 Tag⚠️No explicit H1 — relies on FixtureHeader component
Heading Hierarchy⚠️No visible headings in page file
Structured Data✅SportsEvent with dynamic teams, date, venue, league
Image Alt Text✅Dynamic alt text on team avatars
Rendering✅SSR
Dynamic SEO✅All meta tags use dynamic fixture data

Issues:

  • og
    defaults to generic og-image.png
  • No explicit H1 visible in page file

Recommendations:

  • Verify FixtureHeader renders an H1
  • Consider dynamic OG image generation per fixture

/player/[playerSlug]/[playerId]

File: src/pages/player/[playerSlug]/[playerId].tsx | Rendering: SSR

CheckStatusDetails
Title Tag✅Dynamic: {playerName} Stats | {teamName} {position} Performance & Analysis
Meta Description✅Dynamic with player and team names
Open Graph Tags✅Full suite via EnhancedMetaTags
Twitter Card Tags✅summary_large_image with dynamic data
Canonical URL✅Dynamic: https://statshub.com/player/{slug}/{id}
H1 Tag⚠️No explicit H1 — relies on PlayerHeader
Heading Hierarchy⚠️Depends on child components
Structured Data✅Person schema with name, team, position, nationality, age, jersey
Image Alt Text✅Alt attributes on player/team avatars
Rendering✅SSR
Dynamic SEO⚠️Stats not passed to EnhancedMetaTags — description uses generic fallback

Issues:

  • Player statistics not passed to meta tags — description says "detailed stats" instead of actual numbers
  • og
    defaults to generic
  • No explicit H1

Recommendations:

  • Pass stats prop to EnhancedMetaTags from getServerSideProps
  • Verify PlayerHeader renders H1
  • Consider player-specific OG image

/team/[teamSlug]/[teamId]

File: src/pages/team/[teamSlug]/[teamId].tsx | Rendering: SSR

CheckStatusDetails
Title Tag✅Dynamic: {teamName} Stats {season} | Squad, Fixtures, Results & Analysis
Meta Description✅Dynamic with team name
Open Graph Tags✅Full suite via EnhancedMetaTags
Twitter Card Tags✅summary_large_image with dynamic data
Canonical URL✅Dynamic: https://statshub.com/team/{slug}/{id}
H1 Tag⚠️No explicit H1 — relies on TeamHeader
Heading Hierarchy⚠️Depends on child components
Structured Data✅SportsTeam with name, league, venue
Image Alt Text✅Alt attributes present
Rendering✅SSR
Dynamic SEO⚠️Season prop depends on client-side SWR — undefined at SSR time

Issues:

  • season depends on client-side data — crawlers see no season in title
  • og
    defaults to generic

Recommendations:

  • Fetch season in getServerSideProps
  • Verify TeamHeader renders H1
  • Consider team badge as OG image

/league/[leagueSlug]/[leagueId]

File: src/pages/league/[leagueSlug]/[leagueId].tsx | Rendering: SSR

CheckStatusDetails
Title Tag✅Dynamic: {leagueName} {season} Table, Fixtures & Results {country} | {teamCount} Teams | StatsHub
Meta Description✅Highly dynamic: league name, season, team count, champion, match count
Open Graph Tags✅Full suite via EnhancedMetaTags
Twitter Card Tags✅Enhanced with twitter
/data1 for top scorer
Canonical URL✅Dynamic: https://statshub.com/league/{slug}/{id}
H1 Tag⚠️No explicit H1 — relies on LeagueHeader
Heading Hierarchy⚠️Depends on child components
Structured Data✅Excellent: SportsOrganization, SportsCompetition, BreadcrumbList, FAQPage
Image Alt Text⚠️In child components
Rendering✅SSR
Dynamic SEO⚠️Critical: season, teamCount, champion, leagueStats all from client-side SWR — absent in SSR HTML

Issues:

  • High impact: All rich meta tag data is invisible to crawlers because it depends on client-side SWR
  • lastUpdated runs on client, not server
  • og
    defaults to generic

Recommendations:

  • Fetch standings data in getServerSideProps so teamCount, champion, season are in SSR HTML
  • This is the highest-impact fix — excellent meta logic but invisible to crawlers
  • Verify LeagueHeader renders H1

/referee/[refereeSlug]

File: src/pages/referee/[refereeSlug].tsx | Rendering: SSR

CheckStatusDetails
Title Tag✅Dynamic: {refereeName} Referee Stats | {yellowCards/game} | Match History & Analysis
Meta Description✅Dynamic: referee name, games officiated, cards per game
Open Graph Tags✅Full suite with referee-specific image
Twitter Card Tags✅summary_large_image with dynamic data
Canonical URL✅Dynamic: https://statshub.com/referee/{slug}
H1 Tag⚠️No explicit H1 — relies on RefereeHeader
Heading Hierarchy✅H2 → H3 → H4 in SEO content section
Structured Data✅Person, BreadcrumbList, FAQPage — all fully dynamic
Image Alt Text✅Alt attributes with tournament names
Rendering✅SSR with all key data prefetched
Dynamic SEO✅All meta data from SSR props — most complete dynamic page

Issues:

  • No explicit H1 visible (relies on RefereeHeader)
  • Referee image may 404 if not uploaded

Recommendations:

  • Verify RefereeHeader renders H1
  • Add fallback for og

/basketball/fixture/[fixtureSlug]/[fixtureId]

File: src/pages/basketball/fixture/[fixtureSlug]/[fixtureId].tsx | Rendering: SSR

CheckStatusDetails
Title Tag❌Generic "Free Football & Player Stats" — not basketball, not dynamic
Meta Description❌Generic football description
Open Graph Tags❌Generic, og
hardcoded to homepage
Twitter Card Tags❌Generic defaults
Canonical URL❌Not set
H1 Tag⚠️Relies on BasketballFixtureHeader
Heading Hierarchy⚠️No headings in page file
Structured Data❌None
Image Alt Text✅Team alt text present
Rendering✅SSR
Dynamic SEO❌No dynamic SEO whatsoever

Issues:

  • Zero SEO — all meta tags are generic football defaults on a basketball page

Recommendations:

  • Replace MetaTags with EnhancedMetaTags using basketball fixture data
  • Add StructuredData with sportsEvent type
  • Add canonical URL

/basketball/player/[playerSlug]/[playerId]

File: src/pages/basketball/player/[playerSlug]/[playerId].tsx | Rendering: SSR

CheckStatusDetails
Title Tag⚠️Dynamic but generic: {playerName} - Player Stats
Meta Description⚠️References "goals, assists, shots" — football terminology on basketball page
Open Graph Tags⚠️Dynamic title but og
hardcoded to homepage
Twitter Card Tags⚠️Dynamic title but generic image
Canonical URL❌Not set
H1 Tag⚠️Relies on BasketballPlayerHeader
Heading Hierarchy⚠️No headings in page file
Structured Data❌None
Image Alt Text✅Alt text present
Rendering✅SSR with slug redirect
Dynamic SEO⚠️Partially dynamic but uses wrong sport terminology

Issues:

  • Meta description uses football terms ("goals, assists, shots") instead of basketball ("points, rebounds, assists")
  • No canonical, no structured data, og
    wrong

Recommendations:

  • Create basketball-specific meta component with basketball terminology
  • Add canonical: https://statshub.com/basketball/player/{slug}/{id}
  • Add Person structured data
  • Fix og

/basketball/team/[teamSlug]/[teamId]

File: src/pages/basketball/team/[teamSlug]/[teamId].tsx | Rendering: SSR

CheckStatusDetails
Title Tag❌Generic "Free Football & Player Stats" — not basketball, not dynamic
Meta Description❌Generic football description
Open Graph Tags❌Generic, og
hardcoded to homepage
Twitter Card Tags❌Generic defaults
Canonical URL❌Not set
H1 Tag⚠️Relies on BasketballTeamHeader
Heading Hierarchy⚠️No headings in page file
Structured Data❌None
Image Alt Text✅Team alt text present
Rendering✅SSR
Dynamic SEO❌No dynamic SEO whatsoever

Issues:

  • Zero SEO — generic football defaults on a basketball page

Recommendations:

  • Replace MetaTags with EnhancedMetaTags using basketball team data
  • Add SportsTeam structured data
  • Add canonical: https://statshub.com/basketball/team/{slug}/{id}

Overall Scorecard

PageTitleDescOGTwitterCanonicalH1JSON-LDRenderingGrade
/✅✅✅✅✅⚠️✅⚠️B+
/100-club⚠️⚠️⚠️⚠️❌✅❌❌D
/favourites⚠️⚠️⚠️⚠️❌✅❌⚠️D
/features⚠️✅⚠️⚠️❌✅✅⚠️C+
/free-tools✅⚠️✅⚠️✅✅✅⚠️B
/lineup-bot✅⚠️⚠️❌⚠️✅❌✅C
/odds-converter⚠️✅✅⚠️✅✅✅⚠️B+
/outliers⚠️⚠️⚠️⚠️❌✅❌❌D
/player-stats⚠️✅✅✅✅✅✅⚠️B+
/prop-screener❌❌❌❌❌✅❌⚠️F
/prophunter⚠️⚠️✅✅✅✅❌✅B-
/referees✅✅✅✅✅✅✅⚠️A-
/stats-explained⚠️✅✅✅✅✅✅✅A-
/team-screener❌❌❌❌❌✅❌⚠️F
/team-stats⚠️⚠️✅✅✅✅✅⚠️B
/value-bets❌❌❌❌❌✅❌⚠️F
/404❌❌❌❌❌✅❌✅D
/blog⚠️⚠️✅✅✅✅✅✅A-
/betting-academy⚠️⚠️✅✅✅✅✅✅A-
/league❌❌❌❌❌✅❌❌F
/basketball✅⚠️⚠️❌✅✅❌❌C-
/betting-academy/[slug]✅✅✅✅✅✅✅✅A
/fixture/[slug]/[id]✅✅✅✅✅⚠️✅✅A-
/player/[slug]/[id]✅✅✅✅✅⚠️✅✅B+
/team/[slug]/[id]✅✅✅✅✅⚠️✅✅B+
/league/[slug]/[id]✅✅✅✅✅⚠️✅✅B
/referee/[slug]✅✅✅✅✅⚠️✅✅A
/basketball/fixture❌❌❌❌❌⚠️❌✅F
/basketball/player⚠️⚠️⚠️⚠️❌⚠️❌✅D
/basketball/team❌❌❌❌❌⚠️❌✅F

Prioritized Action Plan

Critical Fixes (Blocking Ranking)

#FixPages AffectedImpact
1Add page-specific <Head> with title, description, canonical, OG, Twitter to F-graded pages/prop-screener, /team-screener, /value-bets, /leagueHigh — these pages are invisible to search engines
2Replace generic football MetaTags with basketball-specific EnhancedMetaTags on all basketball dynamic routes/basketball/fixture, /basketball/player, /basketball/teamHigh — wrong sport terminology, no dynamic data
3Fix MetaTags component og:url bug — hardcoded to homepage for all "default" pages8+ pages using MetaTags pageType="default"High — incorrect OG URL across the site
4Fix /lineup-bot canonical URL from statshub.io to statshub.com/lineup-botHigh — pointing crawlers to wrong domain

High-Impact Improvements

#FixPages AffectedImpact
5Move league standings/season data fetch into getServerSideProps/league/[slug]/[id]High — rich meta tags invisible to crawlers
6Pass player stats to EnhancedMetaTags from getServerSideProps/player/[slug]/[id]Medium — generic description instead of actual stats
7Fetch season in getServerSideProps for team pages/team/[slug]/[id]Medium — season missing from title at SSR
8Audit all Header components for H1 renderingAll dynamic route pagesMedium — may be missing H1 tags

Quick Wins (Easy, Immediate Benefit)

#FixPages AffectedImpact
9Add <meta name="robots" content="noindex" /> to non-indexable pages/404, /favouritesLow — prevents wasted crawl budget
10Fix &apos; HTML entities in meta descriptions and JSON-LD/free-tools, /odds-converterLow — broken characters in SERPs
11Shorten over-length title tags to 50-60 chars/, /blog, /betting-academy, /features, /player-stats, /prophunter, /stats-explained, /odds-converterMedium — prevents SERP truncation
12Add missing twitter:image tags/features, /free-tools, /odds-converter, /lineup-botLow — missing social sharing image
13Update "2025" to "2026" in /stats-explained title/stats-explainedLow — outdated year reference

Long-Term Recommendations

#FixPages AffectedImpact
14Add getStaticProps to all purely static content pages for SSG/features, /free-tools, /odds-converter, /player-stats, /team-statsMedium — faster loads, better crawlability
15Create a global DefaultSeo component with fallback meta tagsAll pagesMedium — prevents pages from having zero SEO
16Migrate all remaining MetaTags usage to EnhancedMetaTagsAll pages still using MetaTagsMedium — EnhancedMetaTags has dynamic URL support
17Generate dynamic OG images per fixture/player/team/leagueAll dynamic routesLow — improved social sharing CTR
18Add WebApplication JSON-LD to tool pages/prop-screener, /team-screener, /value-bets, /100-club, /outliersLow — rich search results for tools
19Use /odds-converter and /stats-explained as SEO templates for other pagesAll pages— Best-practice reference pages

Template Pages (Use as Reference)

The following pages represent best practices and should be used as templates when fixing other pages:

  1. /betting-academy/[slug] — Grade A — Perfect dynamic SSG page with full meta tags, structured data, and data-driven SEO
  2. /referee/[refereeSlug] — Grade A — Perfect dynamic SSR page with full meta tags, multiple JSON-LD schemas, and all data from SSR props
  3. /stats-explained — Grade A- — Best static page with Article + FAQPage schemas, ISR, and comprehensive meta tags
  4. /odds-converter — Grade B+ — Best tool page with 4 JSON-LD schemas (WebPage, FAQPage, BreadcrumbList, VideoObject)

On this page