Swipe travel videos. Get a real itinerary.
Soar is a travel planner that turns YouTube Shorts into a personalised day-by-day itinerary. Pick a destination, swipe through Shorts curated for your location and activity vibes, and Gemini 2.5 Flash builds a specific, timed plan inspired by what you liked.
Planning a trip is overwhelming. You spend hours watching travel content, saving videos, reading blogs — and still end up with a generic itinerary that could have been written in 2019.
Soar lets you build a day-by-day travel itinerary by swiping through YouTube Shorts. Like the videos that match your vibe, skip the rest, and get a personalised itinerary powered by Gemini AI.
- Tell us where: pick a destination, trip length, season, and activity vibes (hiking, dining, nightlife, etc.)
- Swipe the shorts: a curated feed of location-specific YouTube Shorts plays in a card deck; swipe right to like, left to skip. The feed adapts in real time based on what you engage with.
- Get the itinerary: liked video URLs are sent to the AI backend, which generates a detailed day-by-day plan grounded in the specific venues and neighbourhoods from those videos.
There is also a YouTube mode that pulls from your own liked videos, favourites, and playlists instead of the live Shorts feed.
The repo contains three independent services that run together:
frontend-main/ React + Vite frontend (TypeScript)
itinerary-backend-main/ Python / Flask AI backend
shorts-backend/ Node.js Shorts feed API
- React 18 with React Router v6 and TypeScript
- Material Design 3 component system (custom, in
src/components/M3.tsx) - Auth via Auth0 (
@auth0/auth0-react) - Three main flows:
/create-trip— trip details form → swipe feed → itinerary generation/create-trip-youtube— same flow but sourced from the user's YouTube account/your-trip— renders the generated itinerary with a day-by-day timeline/my-trips— saved itineraries fetched from the backend
- Vite dev server proxies
/api/*→localhost:3000(Shorts backend) and/itinerary-api/*→localhost:8080(Python backend)
- Plain Node.js HTTP server (no framework)
- Uses yt-dlp to search YouTube for Shorts matching the destination and activity terms
- Rotates through keyword variants and applies a 100k-view floor to filter low-quality results
- Caches feed results for 20 minutes and CDN stream URLs for 90 minutes
- Endpoints:
GET /api/feed?page=N&location=...&extra=...— returns up to 8 Short video metadata objectsGET /api/stream-url?v=VIDEO_ID— resolves and returns the direct CDN URL as JSONGET /api/proxy?v=VIDEO_ID— resolves the CDN URL and issues a 302 redirect
- Flask with Flask-CORS
- Uses Google Gemini 2.5 Flash (
google-generativeai) to generate itineraries as structured JSON - Auth via Auth0 JWT verification (RS256, JWKS endpoint)
- Itineraries are persisted in Supabase (Postgres)
- Endpoints:
POST /generate_itinerary?prompt=...&video_urls=...— generates a new itineraryPOST /save_itinerary— saves an itinerary to the authenticated user's account (requires Bearer token)GET /my_itineraries— lists the user's saved itineraries (requires Bearer token)DELETE /delete_itinerary/<id>— deletes a saved itinerary (requires Bearer token)
- Node.js 18+
- Python 3.10+
- yt-dlp installed and on your
PATH(pip install yt-dlporbrew install yt-dlp) - A Google Cloud project with the YouTube Data API v3 enabled
- A Google AI Studio API key (Gemini)
- An Auth0 tenant with a Single Page Application and an API configured
- A Supabase project with an
itinerariestable (columns:id,user_id,location,data,created_at)
cd shorts-backend
node server.js
# Listens on http://localhost:3000No dependencies to install — uses only Node built-ins and yt-dlp.
cd itinerary-backend-main
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtCreate a .env file:
GOOGLE_API_KEY=your_gemini_api_key
AUTH0_DOMAIN=your-tenant.auth0.com
AUTH0_AUDIENCE=https://your-api-identifier
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SERVICE_KEY=your_supabase_service_role_keyStart the server:
python server.py
# Listens on http://localhost:8080cd frontend-main
npm installCreate a .env file:
VITE_AUTH0_DOMAIN=your-tenant.auth0.com
VITE_AUTH0_CLIENT_ID=your_auth0_spa_client_id
VITE_AUTH0_AUDIENCE=https://your-api-identifier
VITE_GOOGLE_CLIENT_ID=your_google_oauth_client_idStart the dev server:
npm run dev
# Listens on http://localhost:5173All three services need to be running at the same time for the full flow to work.
Made with ❤️ by the Soar Team