Inspiration

Buying Pokémon cards online can be surprisingly difficult. The same card may appear under different listing titles, in different languages, conditions, editions, and grading formats. A low price does not necessarily mean that an offer is a good deal, because the listing may refer to a different card, have an unclear condition, include expensive shipping, or contain other risk signals.

I created CardPriceLab to make eBay Pokémon card listings easier to understand and compare.

The current version focuses on one main question:

Is this eBay listing correctly matched to a Pokémon card, and is its price reasonable compared with similar offers?

Instead of simply showing the cheapest listing, CardPriceLab separates card matching, market value estimation, deal quality, and risk assessment.

What it does

CardPriceLab currently analyzes live Pokémon card listings from eBay.

Users can:

  • Search for Pokémon cards by name, set, or card number
  • Browse live eBay listings
  • Compare listings from the United States and United Kingdom markets
  • Filter offers by card set, condition, language, grading, price, deal rating, and risk level
  • View the item price and shipping cost as one total price
  • Display prices in different currencies
  • Check estimated card values using the Pokémon Card Value Checker
  • View market ranges separated by condition, language, and grading
  • See how confidently an eBay listing was matched to a specific card
  • Open a detailed analysis before continuing to the original eBay listing

Each analyzed listing can receive two separate evaluations.

Deal Score

The Deal Score compares the normalized total listing price with the available market reference for the matching card segment.

Listings can be classified as:

  • Very good
  • Good
  • Fair
  • Expensive
  • Overpriced
  • Unknown

Risk Score

The Risk Score is calculated independently from the Deal Score.

A listing may have a low price while still receiving a higher risk rating because of signals such as:

  • An uncertain card match
  • Missing condition information
  • Missing language information
  • Suspicious wording
  • Missing seller information
  • A low seller rating

This separation is important because a cheap listing is not automatically a safe purchase.

How I built it

CardPriceLab is a full-stack application built with Next.js, React, TypeScript, PostgreSQL, and Prisma.

The application uses the eBay Browse API as its current live marketplace source. It does not scrape eBay pages. Listing data is retrieved through the official API and stored in a normalized internal format.

The Pokémon card catalog is populated using the Pokémon TCG API. Catalog records contain information such as:

  • Card name
  • Set
  • Card number
  • Rarity
  • Card image
  • Release information
  • External catalog identifiers

The backend generates targeted eBay search queries for catalog cards and processes the returned listings through several stages:

  1. Import the original marketplace response
  2. Normalize the listing title and marketplace fields
  3. Detect condition, language, grading company, and grade
  4. Match the listing to a canonical Pokémon card
  5. Calculate a match confidence score
  6. Assign uncertain results to an administrative review queue
  7. Calculate market reference segments
  8. Calculate the Deal Score
  9. Calculate the Risk Score
  10. Publish qualifying listings on the public website

Prices and shipping costs are stored separately and combined into a normalized total price. Currency rates allow listings and market references to be displayed in the user's selected currency.

Automated jobs keep the catalog, listings, market snapshots, currencies, and scores updated. The smart engine is scheduled through GitHub Actions, while Vercel also runs a scheduled ingestion endpoint.

The public interface supports both English and German and automatically adapts the selected marketplace and currency preferences.

I used OpenAI Codex as an AI coding collaborator while designing, implementing, reviewing, and testing the application.

Challenges

Matching unstructured eBay listings

The most difficult part of the project was matching an unstructured eBay title to the correct Pokémon card.

Sellers may write the same card in many different ways. Listing titles can include abbreviations, spelling variations, promotional terms, grading information, set names, collector numbers, or unrelated keywords.

The matching system therefore cannot rely only on a card name. It also considers signals such as:

  • Card number
  • Set name
  • Pokémon name
  • Known aliases
  • Language
  • Grading information
  • Variant information
  • Negative keywords
  • Search-query precision

The result is stored with a confidence score. Listings that cannot be matched reliably can be held for manual review instead of being published automatically.

Comparing equivalent cards

A raw card should not be directly compared with a graded card. A German card may also have a different market from an English or Japanese version.

For that reason, CardPriceLab separates market references by:

  • Condition
  • Language
  • Raw or graded status
  • Grading company
  • Grade
  • Sales market

This creates smaller but more meaningful comparison groups.

Keeping listings current

Marketplace listings can be changed, ended, sold, or removed. CardPriceLab must repeatedly check whether previously imported listings are still active.

The application records when a listing was last seen and how many refresh attempts failed before changing its public status.

API limits and scheduling

eBay APIs have usage limits. The engine therefore has to divide its available calls between discovering new listings and refreshing existing listings.

I built quota-aware scheduling and separate engine modes for:

  • Listing discovery
  • Listing refresh
  • Catalog expansion
  • Scoring
  • Market snapshot calculation
  • Maintenance

Separating deal quality from risk

One of the most important design decisions was not to combine price and trustworthiness into a single number.

A listing can be inexpensive but uncertain. Another listing can be more expensive but have a strong card match, clear grading information, and reliable seller data.

CardPriceLab therefore calculates Deal Score and Risk Score independently.

What I learned

Building CardPriceLab taught me that a price comparison platform is primarily a data-quality problem.

Collecting listings is only the first step. The information must be normalized, matched, segmented, scored, refreshed, and presented in a way that users can understand.

During the project, I gained practical experience with:

  • Full-stack development using Next.js and TypeScript
  • React server-rendered interfaces
  • PostgreSQL database design
  • Prisma data modelling
  • Third-party API integration
  • Marketplace-data normalization
  • Rule-based entity matching
  • Confidence scoring
  • Deal and risk classification
  • Currency conversion
  • Background data pipelines
  • Scheduled GitHub Actions workflows
  • Vercel deployment
  • Internationalization
  • Automated testing
  • SEO and structured data

I also learned that AI-assisted development works best when the project has clear requirements, tests, data models, and measurable rules. Codex helped implement the project, but the system still required careful product decisions, validation, debugging, and repeated improvements.

What's next

The current product is focused on Pokémon cards and eBay.

The next planned improvements include:

  • Improving card and variant matching
  • Expanding United Kingdom marketplace coverage
  • Adding more eBay regions
  • Increasing catalog and listing coverage
  • Improving market-value calculations
  • Adding historical price charts
  • Adding watchlists and price alerts
  • Improving suspicious-listing detection
  • Adding collection-management features
  • Supporting additional trading card games
  • Integrating additional marketplaces after the eBay system is stable

The long-term goal is to develop CardPriceLab into a transparent trading-card price comparison and deal-intelligence platform, while clearly showing users how every listing was matched and evaluated.

Built With

Share this project:

Updates