🦡 BadgerFit
Find your perfect gym in Madison, WI — built for Badgers at CheesHacks 2025.
BadgerFit is a gym finder for the Madison, Wisconsin area. Users fill out a survey about their preferences (hours, budget, location, amenities, equipment, and fitness goals) and are matched with the top 3 gyms that best fit what they're looking for, along with a match percentage and the specific criteria that matched.
🚀 Getting Started Prerequisites
Node.js v18 or higher A Google Cloud account with the following APIs enabled:
Places API Geocoding API Maps JavaScript API
- Clone the repo bashgit clone https://github.com/BenJPanackal/Badger-Fit.git cd Badger-Fit
- Install dependencies bashnpm install
- Set up your environment variables Create a .env file in the project root: GOOGLE_PLACES_KEY=your_google_api_key_here
- Generate the gym data (run once) This script calls the Google Places API and builds gyms.json — the dataset that powers all matching. bashnode scripts/fetchGyms.js After it runs, open gyms.json and manually fill in the amenities, equipment, and monthlyPrice fields for each gym by checking their websites. This is what makes the matching meaningful.
✅ Once gyms.json is generated and filled in, commit it to the repo so teammates don't have to run this script themselves.
- Start the server bashnode server.js
- Open the app Go to http://localhost:3000 in your browser.
🗂️ Project Structure Badger-Fit/ server.js # Express server — entry point, run this to start the app gyms.json # Gym dataset generated by fetchGyms.js + manually enriched
routes/ match.js # POST /api/match — receives survey input, returns top 3 matches gyms.js # GET /api/gyms — returns full gym list
services/ matchService.js # Scoring algorithm — compares user preferences to gym data geocodeService.js # Converts a typed address to lat/lng via Google Geocoding API
scripts/ fetchGyms.js # One-time script to fetch all Madison gyms from Google Places
index.html # Home page survey.html # User preference survey output.html # Results page — displays top 3 matched gyms survey.js # Handles survey UI interactions survey.css # Styles for survey + output pages styles.css # Global styles for the rest of the site
🧠 How the Matching Works When a user submits the survey, their answers are sent to POST /api/match. The backend scores every gym in gyms.json across five weighted categories: CategoryWeightAmenities25%Equipment20%Hours20%Location20%Budget15% Each gym gets a score from 0–100 based on how many of the user's preferences it satisfies. The top 3 are returned with their match percentage and the specific criteria that matched (e.g. "Has pool", "Open during your preferred hours"). The user's fitness goal also influences equipment scoring — selecting "Build muscle" automatically factors in squat racks, free weights, and cable machines even if the user didn't check those boxes explicitly.
👥 Running on Multiple Machines Because gyms.json is committed to the repo, teammates only need to: bashgit clone https://github.com/BenJPanackal/Badger-Fit.git cd Badger-Fit npm install Then create their own .env file with a Google API key, and run: bashnode server.js Each person's server runs locally on their own machine on localhost:3000. The app does not require an internet-accessible server to run — it's fully local.
If you want the app accessible from other devices on the same WiFi network (e.g. for a demo), find your local IP address and share it: bash# Windows ipconfig
ifconfig Then visit http://YOUR_LOCAL_IP:3000 from another device on the same network.
🗺️ Roadmap ✅ Current Features
Survey-based gym matching with weighted scoring algorithm Match percentage + matched criteria displayed per gym Google Places integration for accurate gym data Distance scoring via Google Geocoding API
🔜 Planned: User Reviews We want to add a reviews feature where users can leave reviews on gyms that are visible to everyone using the app. This requires a shared backend database so reviews persist across sessions and machines. Recommended approach:
Add MongoDB Atlas (free tier) as the database — it's cloud-hosted so all users see the same data Install Mongoose: npm install mongoose Add a Review model with fields: gymPlaceId, author, rating, body, createdAt Add two new routes:
GET /api/reviews/:placeId — fetch all reviews for a gym POST /api/reviews — submit a new review
Render reviews on output.html below each matched gym card Add a MONGODB_URI variable to .env for the connection string
🛠️ Built With
Node.js + Express Google Places API Google Geocoding API Vanilla HTML, CSS, and JavaScript