We will be undergoing planned maintenance on Oct 7th 6:00AM UTC / Oct 7th 2:00AM ET

Inspiration

Pricing a stack of trading cards means typing each name into a search bar, guessing which of a dozen near-identical printings you're holding, then checking two or three sites that disagree. We wanted to point a phone at a card, or a whole binder page, and get the right card and the right price in a second, even at a card show with no signal.

What it does

CardPriceCheck identifies trading cards from the camera and prices them.

  • Scan a single card, a graded slab, or a whole binder page. One photo of a 3×3 page finds all nine cards.
  • Get prices at the right grain: the exact printing, finish and condition, or the grader and grade for slabbed cards, plus price history.
  • Build collections with per-copy prices and running totals. Collections sync across devices and keep working offline.
  • Share a collection as a public link with themed pages, without exposing what you paid.
  • Supports multiple games and languages: Pokémon, One Piece and Lorcana, with Japanese Pokémon scanning on par with English.
  • Free to use, with an optional Pro subscription. Pro adds longer price history, bulk binder scanning, premium share themes and username changes.

Apps. The iOS app is SwiftUI. The web app is Next.js, for search, collections and shared links. A design-token generator keeps Swift, Kotlin and CSS in sync.

Backend. Supabase Postgres, built from declarative schemas:

  • Catalog: a Cards → Printings → Products (raw or graded) → Prices model, with immutable portable keys.
  • Prices: ingested from market sources on pg_cron and published as downloadable bundles for offline use.
  • Security: Row-level security on every table. Logged-out visitors hold zero table grants, and everything they can see goes through a handful of audited functions.
  • Entitlements: which features each plan includes is a database row, not an app release.
  • Edge functions: Deno, for billing and ingest.

Subscriptions. Purchases go through RevenueCat with StoreKit 2. The webhook doesn't trust the event body: it re-reads the subscription from RevenueCat's API before writing anything. The app only unlocks features the server confirms.

Testing. A 20-scenario Postman integration suite asserts the anonymous, free and Pro tier line on every endpoint.

Challenges we ran into

  • Twins. Pokémon reprints the same artwork constantly. 74% of English cards have another card with embedding similarity above 0.95. Telling them apart meant scoring the name bar and the set-number strip separately and fusing the results, rather than trusting one whole-card match.
  • Binder pages. Our first detector found all nine cards on just 1 of 24 real binder pages. After retraining on multi-card data, it finds them on 24 of 24.
  • Graded prices without a combinatorial explosion. Every grader × grade × printing combination would be about 8.4M rows per catalog, and only about a tenth would ever be priced. We create graded products only when a market actually quotes them. Unmatched prices go to a reviewed backlog instead of being guessed.
  • Offline and consistency. Collections that edit offline and sync later without duplicates. An account-deletion gate that locks writes but not read-only queries.
  • Shipping subscriptions. Getting sandbox and production purchases, webhooks, entitlements and App Store review requirements to agree end to end.

Accomplishments that we're proud of

  • Card identification that runs entirely on the phone, works offline and is private by design.
  • Japanese scanning at parity with English (91.0% vs 92.5% top-1 on degraded scans) with no retraining.
  • Whole binder pages in one photo.
  • A backend where the security model is enforced by the database itself and verified by tests, not by convention.
  • End-to-end subscriptions, from App Store purchase to server-verified entitlement.

What we learned

  • A general-purpose vision model plus smart cropping and fusion beats training a classifier per card.
  • Keep the source of truth on the server. The app's cached purchase state runs ahead of reality, so gating on the database avoids a whole class of bugs.
  • Bake security invariants into automated checks. Ours caught a silently dropped permission revoke that code review had missed.
  • App Store review is its own engineering project: subscription disclosures, terms links and account deletion all have specific rules.

What's next for CardPriceCheck

  • Android app and a fuller web experience.
  • More games and languages in the scanner.
  • More price sources and graded coverage.
  • Portfolio insights: value over time and alerts when a card moves.
  • Collection trading and want-lists built on shareable links.

Built With

Share this project:

Updates

Submission history