The hard problem is not showing more profiles. It is deciding who gets seen, how often, and under what fairness rules.
Every dating app on your phone is great at one thing. It shows you people. Endless profiles, fast filters, a swipe in under a second. That part is basically solved. So why do these apps feel worse every year? Because showing you people was never the hard part. The hard part is who actually gets seen, by whom, and how often. That is the problem I have been working on. The longer I sat with it, the more it looked like a product decision dressed up as an algorithm.
Ask a founder what their app does and you get some version of “we help you find the right person.” Watch the actual product and it does something smaller. It helps you browse people fast. Those are not the same thing. Browsing is discovery. You take a messy pool of strangers and make it scrollable and filterable. We are very good at that now. Nobody built the part that decides who you should actually meet this week, out of everyone you could meet.
Solved · search problem
Discovery
Turn a messy pool of strangers into a scrollable, filterable feed. We are very good at this.
Unsolved · economics problem
Allocation
Of everyone you could meet, who actually gets seen, and how fairly? A few soak up the attention. The rest swipe into nothing.
Discovery is a search problem. Allocation is about who gets the scarce thing. We solved the first one and hoped the second would sort itself out.
Allocation is hard because attention runs out. There are only so many people you can seriously consider in a week. When an app hands that attention out badly, it does not break in an obvious way. It quietly sends almost all of it to a small group of very desirable people. Everyone else swipes into nothing. The dashboards still look healthy. The market underneath them is not.
Discovery means making the haystack easy to search. Allocation means deciding who gets the scarce thing. We spent ten years on the first one and barely touched the second.
Here is the uncomfortable part for product people. When you tune a dating app for engagement, more time in app, more swipes, more daily actives, you are picking a goal. That goal fights the thing the user actually wants, which is to leave. Someone who finds a real partner stops opening the app. So an app built to maximize swiping is, in practice, built to keep you single but busy.
Where the attention goes
illustrative model · 24 people, sorted most → least sought-after
An engagement goal lands here by itself. The most wanted few take almost everything. Drag the skew up to watch the gap grow.
An engagement goal drifts toward concentration on its own. The most wanted few soak up almost everything. Capping attention is what spreads it back.
This is a plain incentive problem. The concentration is not a bug someone forgot to fix. It is where an engagement goal naturally lands, because the most desirable profiles pull swipes from everyone else.
If you make more money when people keep searching, you built a search company and called it matchmaking. The goal you optimize for is the product. Everything after that is detail.
People have studied this for sixty years, just not inside an app. Two old algorithms taught me how matching should feel, and where they fall short for someone trying to get married.
Browse, swipe, pile up likes. Good at finding people, not at handing them out well.
Popularity markets→Deferred acceptance. A stable one-to-one match with no blocking pairs. This is the core we keep.
Stable matching→Drops the two-sides rule. One pool, anyone with anyone. But a stable match may not exist.
Stable roommates→Run it weekly as an optimization. Several introductions, fairness built in, always an answer.
Weekly allocationSixty years of matching theory, and the question each one was really asking.
Gale–Shapley (1962) is the one I build on, and I keep it at the center. The idea is simple and it holds up. Only put two people together when the interest runs both ways. No match should be great for one person and miserable for the other. It also guarantees stability, which means no two people will both want to drop their match for each other. That guarantee is the core of what I do. I did not throw it out.
What Gale–Shapley does not handle is the shape of the problem, not the idea behind it. It gives each person one partner, once. Real matchmaking is a few introductions every week. It needs two clean sides. And on its own it lets the most desirable people take everything while others get skipped. Irving (1985) fixed the two-sides issue by putting everyone in one pool, but it can come back and say no stable matching exists at all. You cannot tell a paying user the system could not seat them this week.
So I changed the question I was asking. “What is the one stable pairing of everyone” is the wrong question for a market that keeps running. The better question is more practical. Given how compatible people are, and how fairly each person has been treated so far, who should meet whom this week?
That one change does a lot. A single pairing becomes a weekly allocation. One partner becomes a few introductions. Last week's results feed into this week's. And because it is an optimization with limits, it always returns something. The system can fail to find a great match. It cannot fail to run.
Going from “solve the market once” to “allocate it fairly every week” is the whole idea. Once it is a weekly allocation, the math stops being a wall and becomes a tool.
FairMatch is Gale–Shapley at the center with two things wrapped around it. Fairness, and a calendar. Every week it runs the same four steps.
Filter
Hard rules decide who is even possible. Keeps the pool dense enough for real choices.
→Score
A mutual compatibility score per pair, built so a match only counts when it's good for both. This is the Gale-Shapley part.
→Balance
A fairness dial steers desirable partners toward the under-served, without ignoring compatibility.
→Introduce
Everyone gets the same small set of introductions. Next week the loop runs again with new feedback.
The same four steps run every week. Score is pure Gale-Shapley. Balance and the weekly cap are what we add.
First it filters. Hard rules like age, location, and dealbreakers decide who is even possible. Second it scores. For every possible pair it works out a compatibility number, built so a match only counts as good when it is good for both sides. That scoring is Gale–Shapley's mutuality, kept as is. Third it balances. It tracks who has been under-served and steers desirable partners toward them. Fourth it introduces. Everyone gets the same small number of introductions, and next week the loop runs again with new feedback.
The balance step has one dial, called lambda. At zero, the system only cares about compatibility and ignores who gets left out. Turn it up and it actively pushes sought-after people toward those who keep getting skipped. Drag it below and watch quality trade against reach.
Quality × Fairness frontier
each dot is a value of λ · your current λ is highlighted
Match value
1.48
Under-served reach
0.74
Blocking pairs
3
Push the dial right and the engine sends sought-after partners toward people who keep getting skipped. Reach for the under-served goes up. Raw match value gives a little back. No setting wins on everything. You are picking a point on a tradeoff, and that is a product call.
A real model, run live on six people. Drag the dial and watch match quality trade against reach for the under-served.
One detail here took me a while to get right. The fairness bonus has to reward a pairing, not a person. The obvious version is “give lonely people extra points,” and it does nothing. With a fixed number of introductions per person, a per-person bonus cancels out in the math and changes the result by zero. The bonus only works when it rewards connecting a lonely person to a desirable one. It has to be about the pair. You only catch that by writing the objective down and checking it.
Underneath all of it, the thing we optimize for is still a stable, mutual match. Gale–Shapley's guarantee is the target. Fairness and the weekly cap sit on top of it, not in place of it.
None of this is free, and I would rather be straight about that. Spreading desirable partners around costs you some raw match quality. The system measures exactly how much and reports it.
Three engines, same six people
longer bar = better · computed live
Match value delivered (total)
Fairness · reach for the under-served
On pure stability, Gale–Shapley and Irving are hard to beat. One partner each, perfectly stable. FairMatch keeps that same stability at its core and adds two things. Several introductions per person, and a push that sends sought-after partners toward people who would otherwise be skipped. So it gets more total match value and more reach for the under-served, and unlike the other two it can never come back with no solution.
On pure stability, Gale-Shapley and Irving are hard to beat. FairMatch keeps that core and adds reach and multiple introductions, without ever failing to run.
I think the honesty is part of the product. Most platforms hide what they optimize for, because if you saw it you would not like it. I would rather count the blocking pairs and put the number on screen. A product that can show you the tradeoff it picked, and why, is making a different promise about who it is for.
It is tempting to file this under “neat algorithm.” It is not really about the algorithm. That part is the easy half. B-matching and min-cost flow are standard, fast, and decades old. The hard half is the set of calls a product person actually owns. Deciding the job is allocation, not engagement. Deciding fairness belongs in the objective at all. Deciding where on the tradeoff to sit. Deciding to show the stability cost instead of burying it.
Each of those is a judgment about who the product serves. The math just does what you tell it. The biggest decision in a matching product is not how you compute the matches. It is what you chose to optimize for in the first place. Get that wrong and a brilliant algorithm will efficiently give you the wrong result. Get it right and a basic solver gives you a market people can trust.
Key Takeaways
Dating apps solved discovery, which is a search problem. Who actually gets seen is the part still left open.
Optimizing for engagement rewards keeping people under-served. The goal you pick, not the UI, is the real product.
Gale–Shapley is the core, not the thing being replaced. Its mutuality and stability stay. The weekly, fair layer is built around it.
Reframing from one stable matching to a fair weekly allocation means the system always returns an answer.
Fairness has to reward a pairing, not a person. A per-person bonus cancels out and does nothing.
The tradeoff between quality, fairness, and stability is real. Picking a point on it is a product call, and worth making in the open.
More from the journal
A practical look at scale, rhythm, hierarchy, responsive type, and the token decisions that make text usable across product surfaces.
Jun 2024
Foundations, surfaces, semantic roles, accessibility, and how to build an 11-stop scale that teams can apply consistently.
Jun 2024
When AI pays for you, the payment brand has fewer visible moments. The design problem becomes when trust should appear.
Jun 2026