Keyboard shortcuts

Anywhere on the site, while you are not typing.

M
Weather sound on or off
E
Copy my email
T
Day or night
S
Change the season
D
Portfolio
?
These shortcuts
Esc
Close what is open

all posts

A chapter site that keeps itself current from Instagram

A FastAPI service that reads an IEEE student chapter's Instagram, has Gemini turn each post into a structured event, drops reposts and feeds the chapter's PWA.

Instagramthe chapter's postsScraperFastAPI · on a scheduleGeminiimage + caption → eventDedupeagainst stored eventsMongoDBimages on CloudinaryThe sitePWA · JSON-LDnew
The chapter posts once, on Instagram; the site follows without anyone copying it over.

The IEEE student chapter at my college posted everything on Instagram, and its website went stale the week after every event. As Vice Chairperson for web development I led the team that closed the gap: the chapter posts once, and the site follows on its own.

Reading the feed

A small FastAPI service signs in to Instagram with a saved session and reads the chapter's latest posts, up to 45 at a time, pausing between calls the way a person scrolling would. Each post comes back as its images and its caption.

A post is not an event

"See you Friday!" over a poster doesn't say what, when or where in a form a page can show. So Gemini reads each post's image and caption together and fills one fixed shape: the event's name, date, time, venue, description, and whether registration is open. A field it can't find stays empty rather than guessed. The keys rotate round robin, so one quota running out doesn't stop a run.

Once, not every time it's posted

Chapters post the same event three times: the teaser, the day, the recap. Before anything is stored, each new event is compared with the ones already kept, and a repost is dropped. New events go into MongoDB with their images on Cloudinary, and the site shows them.

The site

I built the site itself: React and TypeScript on Vite, eleven routes, an installable PWA (a Workbox precache of 21 files, cached fonts, and an install prompt that remembers a no for a week), Open Graph and Twitter cards, a canonical address on every page, Organization structured data and a sitemap.

Inside Instagram's limits

Reading a platform you don't own means living inside its limits: Instagram watches how often one address signs in. So the bot signs in once, saves the session and reuses it on every run, which keeps it well inside the line. It is still a line someone else draws, which is why the next step is below.

What breaks first at 10× the traffic

Two things go first. Comparing every new event with every stored one costs one model call per pair, which is fine for a chapter and quadratic for a city's worth of clubs; the fix is to embed each event once and compare vectors, keeping the model for the close calls. And polling a feed is the wrong shape at scale: Instagram's Graph API with a webhook means nothing polls and nothing gets blocked.

Keep reading