Inspiration
Standing on the rim of Bryce Canyon this spring, I overheard two hikers debating which U.S. national park “deserved” the #1 spot on their bucket lists. Their phones were out, Google searches flying, but every “Top 10” article ranked parks differently, and most gave zero context on why you’d love one park more than another. It hit me: why keep rankings static when millions of park-lovers could decide in real time?
At the same time, the Bolt Hackathon challenge emphasized building something viral, community-powered, and fun. A head-to-head voting mechanic—think March-Madness-meets-nature—felt like the perfect way to:
- Democratize discovery – let everyday explorers, not travel editors, surface hidden-gem parks.
- Spark wanderlust – beautiful park photos + quick one-click votes make you want to keep exploring.
- Give back to the parks – highlighting lesser-known parks can help spread visitor traffic and stewardship love.
Combining my obsession with national parks, a love for data-driven rankings (I’m a chess ELO nerd), and Bolt.new’s rapid-build power, ParkRanker was born.
What it does
ParkRanker turns the “best national park” debate into an addictive, community-driven game:
Instant Matchups
Every visit loads two random U.S. national parks side by side—complete with high-resolution photos, location, and a one-line teaser pulled from Wikipedia.One-Click Voting
You click the park you’d rather visit. No sign-up, no friction.Real-Time ELO Scoring
Behind the scenes, the vote feeds an ELO algorithm (borrowed from chess). Scores for both parks adjust instantly and the leaderboard reshuffles on the spot.Live Leaderboard & Trending Parks
A dynamic table showcases the current top parks, movers of the day, and hidden gems climbing the ranks.Recent Votes Feed
A rolling ticker shows the latest head-to-head results, creating a sense of live community activity.Zero-Friction Discovery Loop
After each vote, the app immediately serves up a fresh matchup—encouraging endless exploration and shareability.Built for the Web, Anywhere
Deployed on Netlify at https://growthgrail.net, with a custom Entri/IONOS domain integration. Fully responsive, so park lovers can rank from trailheads or couches alike.Data That Stays Fresh
An Apify crawler pulls official park data and images from Wikipedia, pipes it into Supabase, and Bolt.new handles the frontend logic—ready for periodic re-crawls as parks evolve.
Result: ParkRanker gives outdoor enthusiasts a fun way to discover and champion their favorite national parks, while creating a living, community-validated ranking the internet has never seen before.
How we built it
1. Stack at a glance
| Layer | Tech | Role |
|---|---|---|
| Frontend & Logic | Bolt.new | UI, routing, state, ELO algorithm, API calls |
| Database | Supabase | Tables (parks, votes, settings), real-time updates |
| Data Ingestion | Apify | Scrapes the National Parks Wikipedia table with image URLs |
| AI Summaries | ChatGPT-4 | Condenses park descriptions into 1-line summaries |
| Hosting | Netlify | CI/CD + global CDN deployment |
| Custom Domain | Entri / IONOS | Domain purchase & DNS (https://growthgrail.net) |
2. Data pipeline
- Apify actor pulls raw fields:
name,location,description,image_url. - A Bolt serverless step calls ChatGPT-4 to convert each description into a crisp, <20-word summary.
- Enriched JSON is upserted into Supabase’s
parkstable with a defaultelo_scoreof 1500. - Supabase broadcasts changes; Bolt components subscribe for live updates.
3. Core Bolt.new logic
- MatchupPage – shows two random park cards → one-click vote → triggers ELO update.
- Leaderboard – listens to Supabase’s
parkschannel and re-orders instantly. - RecentFeed – streams the latest 25 votes in real time.
- ELO function (Bolt serverless): ```javascript const k = 32; const expect = (a, b) => 1 / (1 + 10 ** ((b - a) / 400)); export const updateElo = (w, l) => ({ newWinner: w + k * (1 - expect(w, l)), newLoser: l + k * (0 - expect(l, w)) }); Feature flag – auth_required = false in settings; ready to flip for future login.
Challenges we ran into
Bolt’s web-crawling black hole
I first asked Bolt to scrape the National Parks table directly from Wikipedia. It kept insisting it could “fix a few selectors and try again”… then quietly burned through 2.5 M+ tokens without ever returning clean data. Lesson learned: cut losses early. I pivoted to Apify, but that meant an extra day of reading docs and building a custom crawler from scratch.Moving data from Apify → Supabase
Apify spit out beautiful JSON, but wiring an automated pipe into Supabase tables was trickier than expected. I fought through CORS issues and malformed rows before landing on a Bolt serverless function that pulls the Apify dataset and upserts it.Custom-domain DNS gymnastics
Buying the domain via Entri + IONOS was one click. Getting it to actually resolve to my Netlify site was not. DNS propagation lag, mis-autoprovisioned CNAMEs, and a rogue AAAA record meant the site stayed on the Netlify subdomain for hours. I finally dove into both IONOS and Netlify dashboards to wire the records manually—glad I didn’t save that step for the last minute.Missing
https:on Wikipedia thumbnails
Wikipedia image URLs come back protocol-relative (//upload.wikimedia.org/...). Without the secure prefix, browsers block them. I added a tiny utility in Bolt to prependhttps:before saving to Supabase.Supabase Row-Level Security (RLS) tweaks
With authentication off for the MVP, I still needed public read access for the leaderboard but write access for server functions only. Crafting those RLS policies (and verifying them in real time) took multiple iterations.Display not optimized for mobile
After deployment I discovered the desktop-first layout didn’t translate to phones—cards overlapped, tap targets were too small, and scrolling felt clunky. A mobile-first redesign is now top priority.
Accomplishments that we're proud of
Solo builder → live product
Took the project from a sketch on paper to a fully functioning web app—design, data, code, and deployment—all on my own within the hackathon window.End-to-end stack mastery
Wired together Bolt.new, Supabase, Apify, ChatGPT-4, Netlify, and Entri/IONOS—six different platforms—into one seamless workflow.Real-time ELO leaderboard
Implemented chess-style scoring so every click instantly reshuffles park rankings—no page refresh needed.AI-generated micro-content
Used ChatGPT-4 to condense long Wikipedia park descriptions into punchy one-liners that fit perfectly on mobile cards.Custom domain & SSL in 24 hrs
Deployed the app to production on https://growthgrail.net, complete with HTTPS and a “Built on Bolt” badge.Performance on a shoestring
Despite rich images and live data, the site loads in under two seconds on 4G thanks to Netlify’s CDN and lazy-loaded thumbnails.Resilient pivoting
When Bolt’s crawler stalled, I learned Apify overnight, rebuilt the pipeline, and still shipped on time.
ParkRanker is now live, shareable, and ready for thousands of park lovers to play—proof that one determined builder can create viral-ready experiences with Bolt.
What we learned
Know when to pivot.
Watching Bolt burn millions of tokens trying to crawl Wikipedia taught me to trust my gut and switch tools sooner rather than later. Apify rescued the data pipeline.No-code ≠ no-thinking.
Bolt.new handles a ton, but stitching six services together still requires architectural decisions—API contracts, rate limits, CORS, and security policies don’t magically disappear.AI excels at micro-copy.
ChatGPT-4 can crank out crisp, engaging one-liners far faster than I can write them. The trick is nailing the prompt and setting a tight word limit.DNS is never “one click.”
Buying a domain is easy; waiting for propagation and hunting stray records at 2 a.m. is not. Always budget time for domain + SSL hiccups.ELO isn’t just for chess.
The rating system translates beautifully to crowdsourced preferences—every vote feels meaningful, and the math keeps the leaderboard dynamic and fair.Supabase RLS is powerful (and picky).
Public read, server-only write policies took a few tries to get right, but once dialed in they make the app both secure and frictionless.Performance matters—even in hackathons.
Lazy-loading images and trimming JSON reduced load times to <2 s, which keeps users voting longer.
Most of all, I learned that with the right stack—and a willingness to pivot—you can turn a spark of an idea into a polished, share-worthy product in a single week.
What’s next for ParkRanker
Mobile-first redesign
The desktop layout looks great, but the cards feel cramped on smaller screens. I’ll refactor the grid, add swipe-friendly gestures, and tighten image compression so the experience sings on phones.Flip the auth feature flag
Enable Supabase Auth so users can create profiles, track their voting history, and earn badges for streaks.Social sharing hooks
One-tap “Share this matchup” buttons (OG-image + park thumbnails) to boost viral reach on X, Reddit, and Instagram Stories.Park deep-dive pages
Click any park on the leaderboard to see best seasons, must-do hikes, and recent images pulled from NPS APIs.Periodic data refresh
Schedule the Apify crawler to rerun monthly, auto-updating new visitation stats or image changes in Supabase.Themed tournaments
Run limited-time brackets like “Best Winter Parks” or “Top Dark-Sky Spots,” resetting ELO within each event.PWA & offline mode
Cache images and data so users can keep voting (and dreaming) even when they’re off the grid in the backcountry.Partnerships with park nonprofits
Surface donation links or volunteer sign-ups for each park—turn discoverers into stewards.
These upgrades will polish the mobile experience, deepen engagement, and turn ParkRanker into the go-to community for national-park inspiration.
Built With
- apify
- bolt.new
- chatgpt4
- entri
- ionos
- netlify
- supabase

Log in or sign up for Devpost to join the conversation.