03 · Campus social app
Campify
A campus social app on web, iOS and Android. Students import their timetable from a screenshot, see when friends are free, and find people in their classes.

- students onboarded
- 300+
- students onboarded
- across multiple universities
- platforms shipped
- 3
- platforms shipped
- iOS · Android · web
- profile completion
- +17 pts
- profile completion
- 54% → 71% after redesign
- to import a timetable
- 1 photo
- to import a timetable
- on-device OCR
Why
Campus life runs on schedules, but nobody shares them.
Meeting up between classes usually means a group chat full of timetable screenshots. Campify puts everyone's timetable in one place. You can see when friends are free, find people in your courses, and follow what's happening on campus.
I built and launched it on iOS, Android and the web with Flutter, React, Firebase and Node.js. It grew to 300+ students across multiple universities, which meant real data and real users finding edge cases I hadn't thought of.
Timetable import
From a messy screenshot to a structured schedule.
01
On-device OCR
ML Kit text blocks, lines and boxes
02
Find day columns
header labels, or x-clustering if none
03
Extract class cards
course codes, times, rooms via regex
04
De-duplicate
merge boxes with heavy IoU overlap
05
User review
low-confidence rows get confirmed
06
Write schedule
Firestore + optional .ics
The hard part was defensive parsing. Course codes come as MAT223H5 or PHYSICS 1D03, times as 9:30 PM, 9PM or 21:30, and OCR breaks words in odd places. So the parser looks at neighbouring lines in a block, normalizes everything to 24-hour time, and falls back to clustering by x-position when no day headers are found. Nothing is written until the student has checked the rows.
// course codes: MAT223H5 / MAT 223H5, then looser fallbacks final _reCourseTight = RegExp(r'\b([A-Z]{3}\s?\d{3}[A-Z]\d?)\b'); final _reCourseLoose = RegExp(r'\b([A-Z]{2,}\s?\d{3}[A-Z]?\d?)\b'); // 9:30 PM – 11 PM → 21:30–23:00 final _reTimeAMPM = RegExp(r'(\d{1,2}(:\d{2})?\s?(AM|PM))\s*[-–]\s*…');
Recommendations
Friend suggestions that make sense.
01
Mutual connections
People your friends already know.
02
Schedule overlap
Shared courses and free time, from imported timetables.
03
Social proximity
How close you already are in the network.
04
Interaction signals
Who you actually engage with in the app.
Onboarding
I used the data to fix the funnel.
Many new students never finished their profile, and an empty profile makes a social app feel empty. I looked at where new users dropped off during activation and redesigned onboarding around those points.
Profile completion+17 percentage points


