DEV Community

mathew lam
mathew lam

Posted on • Originally published at jerseytome.com

I Built a Real-Time NBA Jersey Price Tracker with Next.js, MDX, and Web Scraping

The Problem

NBA jersey prices are all over the place. The same Mitchell & Ness jersey can be $250 on one site and $180 on another. Resale prices on eBay fluctuate daily. If you're a collector, you're constantly checking multiple platforms to find fair prices.

I wanted a single tool that shows real-time market pricing across retailers — so I built one.

The Stack

  • Next.js 16 (App Router, static generation)
  • MDX for content (each jersey has its own article with structured pricing data)
  • Tailwind CSS 4 for UI
  • TypeScript end-to-end
  • Vercel for deployment + analytics
  • Custom scraping pipeline for price updates

Architecture

The site has 270+ pages across 5 locales (EN, ZH, JA, KO, ES). Every jersey article contains structured pricing data in its MDX frontmatter:

pricing:
  fanatics:
    price: 129.99
    url: "https://..."
  mitchellNess:
    price: 299.99
    url: "https://..."
  ebayAvg: 185
  trend: "rising"
Enter fullscreen mode Exit fullscreen mode

A scheduled agent script scrapes current prices and updates the frontmatter. On build, Next.js generates static pages with Product JSON-LD schema — so Google sees structured pricing data.

The Valuation Tool

The most interesting part is the Jersey Valuation Tool. Users select a player + jersey, and it shows:

  • Current retail prices (Fanatics, Mitchell & Ness)
  • eBay average sold price (last 30 days)
  • Price trend (rising/stable/declining)
  • Estimated collector value based on era, condition, and rarity

All computed client-side from the static pricing data — no API calls needed at runtime.

SEO Strategy That Actually Works

This is a content site, so organic traffic is everything. Some things that worked:

1. Structured Data on Every Page

Every jersey page has Article + Product + FAQ + BreadcrumbList schemas. Google Rich Results are the goal — showing prices directly in search results.

2. Multi-locale with Proper Hreflang

Using next-intl with 5 locales. Every page has full hreflang alternates in both the HTML <head> and sitemap. This opens up non-English search traffic (huge for basketball content in Asia).

3. Programmatic Content at Scale

Each player hub page is auto-generated from their jersey collection. Team pages aggregate by franchise. Number pages group by jersey number. This creates a dense internal linking structure without manual work.

4. Active Indexing

Passive sitemap submission is too slow for new sites. I built a script that pushes URLs directly to Google's Indexing API and Bing's URL Submission API on every deploy. 98 URLs indexed within days instead of weeks.

Challenges

  • Affiliate compliance: Every pricing link needs FTC disclosure. Built a component that auto-injects disclaimers.
  • Stale prices: Prices change daily. The scraping pipeline runs on a schedule, but I still need to handle the "price was X when we checked" transparency.
  • Image generation: Needed unique hero images for 45+ jerseys. Used AI image generation with careful prompts to avoid trademark issues.

Results So Far

  • 270+ pages indexed
  • 5 language variants
  • Sub-1s LCP on all pages (static generation FTW)
  • Structured data validated on 100% of product pages

Still early on traffic — the site is only a few weeks old — but the technical foundation is solid.

Open Source?

Not yet, but thinking about it. The content pipeline (MDX + frontmatter pricing + automated scraping + multi-locale) is pretty reusable for any product comparison site.

If you're building something similar, happy to answer questions about the architecture.


Check it out: JerseyToMe — NBA Jersey Encyclopedia & Price Guide

The valuation tool: Jersey Valuation Tool

Top comments (0)