Canopi - Find your place. Not just an apartment.

Canopi

timeline: 2026

tech stack: Next.js, React, TypeScript, Gemini AI, Mapbox GL, Three.js, Supabase, Tailwind CSS, Geoapify, GitHub Actions, Vercel

Overview

Canopi is an AI-powered rental discovery platform that replaces traditional filters with conversation. Instead of searching by beds and price, users talk to an AI assistant that infers their lifestyle across 8 preference axes — walkability, nourishment, wellness, greenery, buzz, essentials, safety, and transit. A live radar chart updates in real time as the AI learns who you are, and on every chat turn the map re-ranks 3,500+ real Canadian listings against that preference vector to match your actual life, not just a checkbox of constraints. Shipped on Next.js and Vercel to 500+ peak monthly users.

How It Works

Canopi is built on three connected systems. A daily sync job, run as a GitHub Action, pulls 3,500+ active rental listings from RentFaster (Toronto) and RentCast (San Francisco), enriches each one with nearby amenities from Geoapify — cafés, groceries, restaurants, parks, schools, pharmacies, transit — counted inside a 1 km radius, and upserts the result into a Supabase listings table with the amenity counts precomputed.

At runtime, an AI chat layer drives the experience. A Next.js API route sends each user message to Gemini with a system prompt that forces structured JSON output: a natural-language reply, a delta across the 8 lifestyle axes as an 8-axis preference vector, and a ranked list of matching listing IDs. The chat asks indirect, personality-revealing questions — "what does a good Sunday morning look like?" — instead of interrogating the user about square footage.

The frontend ties it together. A Mapbox GL map renders price pins and flies to AI-recommended listings, a hand-rolled SVG radar chart animates as preferences shift, and a Three.js diorama renders a 3D neighborhood vitality view for any selected property. Supabase handles auth and persists saved listings, and the assistant replies in whatever language you write in. Everything deploys to Vercel; the sync job is the only piece that runs elsewhere.

How It Works

Architecture

The sync job, AI layer, and frontend are loosely coupled through a small set of Next.js API routes. A daily GitHub Action pulls listings into a Supabase table and enriches them with precomputed amenity counts; at runtime, chat messages flow into Gemini and come back out as structured preference deltas that drive the map and radar chart.

loading diagram…

Performance

Three changes made the difference between a demo and something people kept using. Neighborhood lookups originally hit a third-party map API on every request and took 9.4 s; precomputing amenity counts per listing in a daily sync job brought that under 225 ms, a 40x improvement. Caching amenity results per 100 m grid cell removed 5,600+ duplicate API calls, since listings on the same block share the same surroundings. And encoding each listing as a single pipe-delimited line instead of JSON cut the Gemini prompt size by 62%, which kept re-ranking 3,500+ listings on every chat turn fast and cheap.

Results

We shipped a fully working AI-to-map feedback loop — talk to the assistant, watch the map change — and it reached 500+ peak monthly users. The platform serves 3,500+ real, enriched rental listings across Toronto and San Francisco with smooth sub-second re-ranking on every preference update, a hand-rolled 8-axis radar chart that animates as the AI learns you, multilingual chat, a 3D neighborhood diorama, and Supabase-backed saved listings. The biggest challenge was data acquisition — rental platforms in Canada are fragmented and hostile to reuse, so we had to fight through inconsistent formats, missing fields, and freeform descriptions before we could even start on the product.

Results