Busabase
Busabase is an open-source (MIT) database and workspace for AI agents — data, docs, skills, and apps in one place. Run it locally, self-host it inside your network, or use Busabase Cloud, and turn age
Explore Toronto neighbourhood Airbnb performance by occupancy and rating
Translation pending
AI summary · website content
DataJavaScript · PythonGitHub @ylh551400OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗Live demo → toronto-airbnb-dashboard.vercel.app
A data pipeline and interactive dashboard that maps 22,050 Toronto Airbnb listings across 140 neighbourhoods into four market quadrants. Built as a portfolio project to demonstrate end-to-end data engineering, from raw CSV to live, auto-updating web product.
Every neighbourhood is scored on two axes — occupancy (estimated nights booked per year) and guest rating — then placed into one of four quadrants:
| Quadrant | Occupancy | Rating | Story |
|---|---|---|---|
| Q1 Star | ≥ median | ≥ median | Highly booked and highly rated — market leaders |
| Q2 Volume | ≥ median | < median | Busy but under-delivering on guest experience |
| Q3 Hidden Gem | < median | ≥ median | Well-reviewed but underdiscovered |
| Q4 Struggling | < median | < median | Low demand and low satisfaction |
The dashboard also compares listing performance by number of amenities listed, room type composition, property type comparisons, a 3-year monthly activity trend, and neighbourhood leaderboards.
Inside Airbnb CSV (manual download, quarterly)
│
│ git push rawdata_new/
▼
┌─────────────────────────────────────┐
│ GitHub Actions │
│ │
│ 1. clean.py — normalise & dedupe │
│ 2. analyze.py — pre-compute stats │
│ 3. load.py — upsert to database │
└─────────────────────────────────────┘
│
│ supabase-py (service role key, stored as GH Secret)
▼
┌─────────────────────────────────────┐
│ Supabase (Postgres + REST API) │
│ 9 tables, all pre-computed │
└─────────────────────────────────────┘
│
│ fetch() on page load (anon key, safe to expose)
▼
┌─────────────────────────────────────┐
│ Vercel (static frontend) │
│ Chart.js · Leaflet · vanilla JS │
└─────────────────────────────────────┘
Update cycle: Drop new CSVs into rawdata_new/, push. GitHub Actions handles the rest. reviews.csv only needs the listing_id and date columns. Trim it to those before pushing so it stays under GitHub's 100 MB file limit. calendar.csv isn't used and is gitignored. No server to maintain; entire stack runs on free tiers.
Nine Postgres tables hold all pre-computed results. The frontend reads directly via Supabase's auto-generated REST API. No custom backend needed.
| Table | Rows | Purpose |
|---|---|---|
neighbourhoods | 140 | Core quadrant data, coordinates, aggregated metrics |
monthly_activity | 4,861 | Neighbourhood × month time-series (review & occupancy) |
monthly_totals | 35 | Citywide monthly aggregates — used by the trend chart |
room_type_stats | 316 | Neighbourhood × room type breakdown |
room_type_citywide | 4 | Citywide stats per room type (true median, nulls excluded) |
amenity_count_stats | 6 | Listing performance grouped by number of amenities listed |
property_type_stats | 8 | Top 8 property types by supply |
leaderboards | 30 | Pre-ranked top-10 lists for three categories |
citywide_medians | 2 | Reference values that define the quadrant split lines |
Row-level security is enabled on every table with a public-read policy. The pipeline writes via service role key (GitHub Secret); the frontend reads via anon key.
Why occupancy instead of price? Inside Airbnb removed price data from their public dataset in 2025. Rather than approximate price from third-party sources, I pivoted the quadrant axis to occupancy (estimated nights booked per year), which is arguably a more direct signal of market performance anyway. The quadrant model stays logically coherent. It just answers "who's busy and well-reviewed" instead of "who's expensive and well-reviewed".
Why compute quadrant medians from neighbourhood aggregates, not raw listings? Airbnb's rating system is heavily inflated at the listing level, the citywide median rating across 22,050 listings is 4.9, which would place almost every neighbourhood below the median. Instead, the pipeline first aggregates to neighbourhood-level averages, then takes the median of those 140 values (4.79). This produces a balanced four-way split.
Why a monthly_totals pre-aggregation table?
Supabase's free tier enforces a 1,000-row hard limit per API response. The monthly_activity table has 4,861 rows (140 neighbourhoods × up to 36 months). Fetching it in chunks would require sequential paginated requests, which slows page load and complicates client code. Pre-aggregating to one row per month reduces the payload to 35 rows and makes the frontend code simpler.
Why compare amenity counts instead of individual amenities? A listing typically has 30 to 50 amenities, so "average of listings with amenity X" mostly measures the same listings over and over. Labels also fragment: "Heating" and "Central heating" are separate tags, which made heating look like it hurt bookings. Grouping listings by how many amenities they list gives a clean, readable signal: more complete listings get more bookings and better ratings. It's presented as a correlation, not cause and effect.
Why keep all computation in Python rather than SQL views? The pipeline runs in GitHub Actions, not inside the database. Keeping logic in Python (pandas) makes it easier to test locally, version-control, and reason about without needing a live DB connection. The tradeoff is slightly more code, but the testability is worth it for a project that updates on a push-triggered schedule.
| Layer | Tool | Why |
|---|---|---|
| Data source | Inside Airbnb | Quarterly Toronto scrape, publicly available |
| CI / pipeline trigger | GitHub Actions | Free, push-triggered, no infra to manage |
| Data processing | Python · pandas · numpy | Flexible, readable, easy to run locally |
| Database + API | Supabase (Postgres) | Auto-generated REST API, free tier, RLS built-in |
| Frontend | Vanilla JS · Chart.js · Leaflet | No framework overhead for a single-page viz |
| Hosting | Vercel | Zero-config static deploy from GitHub |
Source: Inside Airbnb — Toronto Snapshot date: September 2026