Skip to content

Architecture & Docs

A discovery platform for pickleball cash games. Partnership-first, scrape-last.

Ingestion pipeline

Each source is a pluggable adapter. Deterministic, source-specific parsing is preferred; unstructured discovery is a fallback. A typical run:

structured / source-specific adapters → (optional) discovery + extraction → normalize → classify → dedupe(venue/time±30m/buy-in±$5) → eligibility check → upsert → scrape_run log

The feed is amateur-first: it includes real tournaments (cash or non-cash), competitive cash games and organized ladders/KOTC — each labelled accurately (Tournament / Cash game / Competitive session, with a separate prize-status label). Clinics, lessons, camps and pure open-play/drop-in socials are excluded.

Listings we cannot verify — a stale or year-mismatched source, an untraceable price, a different sport (e.g. padel) — are deferred or rejected, never normalized speculatively into the feed.

Classification & labels

Deterministic first: structured adapter fields + regex/keyword signals (buy-in, pot, prize pool, payout, moneyball, KOTC) and an organizer allowlist. Fast, free, auditable.

Optional LLM normalization (OpenRouter): used only for unstructured discovery pages. It is opt-in and defaults OFF (OPENROUTER_NORMALIZATION_ENABLED); ordinary refresh and the whole feed run without it. It is an optional enhancement, never a required dependency.

Prize labels are evidence-based: an entry fee / buy-in is not evidence of a cash prize. "Cash prizes" is shown only with source-confirmed player-money evidence; otherwise the card reads "Prize details not published" or "Non-cash awards".

Dedupe & cross-listing

Events are blocked by normalized venue, then clustered within tolerance (start ±30 min, buy-in ±$5). Cross-listed duplicates — including the same event surfaced by several sources — collapse into one canonical event that shows all “Listed on” source badges, and a parser that confuses a purse with an entry fee is reconciled rather than double-counted.

Data source tiers

Tier 1 — Sanctioned APIs (DUPR)
Tier 2 — Public organizer pages (robots audited)
Tier 3 — Host submissions & claims
Tier 4 — Never scrape (Meta, Eventbrite, PBT, Discord)

The current feed is served from a validated, source-backed inventory. Discovery adapters (Exa + Firecrawl extraction, with the optional OpenRouter normalizer) and structured-API adapters (allpickleballtournaments.com, pickleball.com) activate when their keys + flags are set. Toggle sources in Admin → Sources.

How to add a metro

1. Add the metro to ingestion/seed_data.py (name, slug, center lat/lng, timezone). 2. Add venues + organizers. 3. Add event templates or enable adapters scoped to that metro. 4. The UI, /m/[slug] route, feed, and SEO page are templated — no code changes needed.

How to add a source

1. Subclass BaseAdapter in ingestion/adapters.py. 2. Implement fetch() returning the base event shape. 3. Set source_tier. 4. Complete the robots.txt/ToS audit, then enable from Admin → Sources.

Legal & compliance

No scraping of authenticated/private pages, Meta surfaces, or Discord selfbots. Every event shows source attribution + click-through. Image provenance is stored; only small thumbnails for ingested content. DMCA takedown SLA is 48 hours.

KitchenLine logoKitchenLine

A discovery platform for pickleball cash games. We are not an operator and never take custody of buy-ins or prize pools. Always confirm details on the source page.

© 2026 KitchenLine. Source attribution shown on every event. Play responsibly. We use local storage for essential functionality only (no third-party ad cookies) — see our Privacy Policy.