How it works
Each person is represented by an agent. The agent reads its person from two public profiles, then goes on dates with other agents on that person's behalf. Afterwards every agent ranks who fits its person best.
Apify scrapers
Public data only, PII stripped
Reader agent
Read pass, then synthesis pass
Profile page
Needs, hobbies, interests, qualities
Dates
Agent vs agent, 3 acts, private debriefs
Ranking
Everyone, for everyone
The two sources
Every person goes in as exactly two official links: their LinkedIn profile and the Instagram that belongs to them. Nothing else. The agents have no web search and no other tools, and every claim on a profile has to point back to a LinkedIn section or an Instagram post.
Only public Instagram accounts are allowed. Private accounts are rejected before any analysis, and the link checker refuses shortlinks, company pages and post links with a clear message for each line.
The reader agent
The reader works in two passes. The read pass goes through the LinkedIn headline, about, experience, education and skills, then the Instagram bio and latest posts (captions, hashtags, locations, and the images themselves when the model supports vision). It writes a reading log: what it looked at, what it noticed, and the evidence.
The synthesis pass turns that log into the profile: needs, hobbies, interests and other qualities, each with a confidence level and at least one piece of evidence (source, reference and quote). It also writes green flags, possible dealbreakers, conversation hooks and an ideal first date.
Finally it runs an identity check: do the LinkedIn and Instagram belong to the same person? It compares names, locations and cross-links. If it looks like two different people, the profile pauses until someone confirms.
The representative agents
On a date, each person is represented by their own agent. That agent's instructions are built only from its person's profile, plus a private agenda: which needs to probe, which dealbreakers to watch for, and which hooks to bring up.
An agent never sees the other person's analysis, and it may not invent facts. If it doesn't know something about its person, it says so.
The date
Agent A
Knows only A's profile and private agenda: needs to probe, dealbreakers, hooks.
Shared: venue plan and transcript
- Act 1, arriving and icebreakers
- Act 2, values, goals and dealbreakers
- Act 3, a week together and the goodbye
Agent B
Knows only B's profile and private agenda. Never sees A's notes.
A matchmaker pairs people using profile overlap (shared hobbies, interests and values, plus complementary traits), respecting who each person is interested in. Every person gets at least one date per round.
The two agents first agree on a venue and activity from both profiles, with a reason that cites each side. Then they talk for 8 turns over 3 acts. Every turn is a separate model call made as that agent alone, with its own profile, agenda and the transcript so far. With each line the agent keeps a private thought and a vibe score from 0 to 10, which is what the replay's vibe meter shows.
After the goodbye, each agent writes a private debrief for its person: chemistry out of 10, what clicked, concerns, a one-line verdict, and whether it wants a second date. When both say yes, it's mutual.
When free-tier quota runs low, a date can run in compact mode: one call writes the conversation with strict role separation, and the two debriefs are still separate calls. The replay labels which mode was used.
The ranking
For every person, every other person in the pool is ranked. For someone they dated:
score = 100 × (0.5 × my agent's chemistry + 0.3 × their agent's chemistry + 0.2 × profile prescore)
Chemistry is the debrief score divided by 10. Your own agent's view counts most, but a date only scores well if the other side felt it too.
People they haven't dated yet are still ranked, labelled projected: score = 80 × prescore. Capping guesses at 80 means a genuinely good date always outranks a guess.
Scraping stack
Scraping runs on Apify. Instagram uses apify/instagram-profile-scraper (bio, counts, privacy flag and the latest posts). LinkedIn uses supreme_coder/linkedin-profile-scraper, with bovi/linkedin-profile-scraper as a fallback.
Runs are started asynchronously and in batches, so pasting a whole list costs a few actor runs rather than one per person. Raw output is normalized into one shape and emails and phone numbers are stripped. Instagram images are captured as small thumbnails at scrape time, because Instagram's image links expire.
Models
Everything runs on free tiers. Gemini is the primary model family, with Groq free-tier models as the fallback. Reading, dating and debriefing each have their own ordered chain of models.
A per-model rate limiter tracks requests and tokens per minute and per day. When one model is out of quota the next one takes over; when all are out, people show “Paused for quota” and resume automatically.
Infrastructure
Next.js on Vercel, with Supabase Postgres for the live pool. The pipeline is a set of short, resumable ticks: each one advances a few people or dates by one step and saves the result, so no request runs long and nothing is lost if one fails. Your browser drives the ticks while you watch the live pool.
The demo pool is a frozen snapshot bundled with the site. It renders without the database, and visitors can't change it, except to remove a person.
Privacy
- Only public data from the two links. Private Instagram accounts are rejected.
- Emails and phone numbers are stripped before anything is stored or shown.
- Every page is marked noindex, so none of this shows up in search engines.
- Every profile has a Remove this person button. It removes them from the pool, their dates and every ranking straight away.
- Everything here is an AI simulation for a technical exercise. Nobody shown is affiliated with or endorses it.