Writing / AI ยท Product

Who is this, without leaving the chat

Halfway through a conversation, the question is usually who this person actually is. Answering it means stopping, opening a tab and searching. I built a Chrome side panel that answers it inside LinkedIn and Facebook Messenger, while the chat is open, only in threads I'm part of. Most of the time went into deciding what it should refuse to do.

A Chrome window on linkedin.com/messaging with a conversation from Daniel Sorkin-Lavi asking for a call. Docked on the right, the Who is this side panel shows his photo and name, a green Identified, high confidence pill, a one-line summary, and sourced facts under the label Not visible on the profile.
On LinkedIn, in day mode: the panel docks next to the conversation and answers before I have to ask. The people and companies in this piece are fictional and their photos are generated; the panel is the real one, running on made-up data.

Most of my new conversations start in a message. Someone writes on LinkedIn about a project, someone answers a Marketplace listing on Facebook, an old colleague resurfaces after two years. By the second or third message I usually want to know who I'm talking to: what their company does, what they've worked on, whether we have something in common. And every time, the answer lives in another tab.

So the conversation stops. I open the profile, then a search, then the company site, and come back a few minutes later having half forgotten what I was going to say. I wanted the answer to be there already, next to the chat, while the conversation is still happening.

I built it as a Chrome extension with a side panel. It works in LinkedIn messaging and in Facebook Messenger, both on the full messages pages and in the small chat windows that pop up at the bottom of the feed. Open a chat, and the panel shows who is on the other side, with a source for every line.

Test the premise before the extension

The extension itself is the easy part. The part that decides whether it is worth building is identity. Plenty of people share a name, and a language model will happily merge three of them into one confident paragraph. A brief about the wrong person is worse than no brief at all, because it sounds right.

So before any extension code, I wrote a small script: run a few web searches, hand the results to Claude, and ask for a brief that only states facts it can tie to an anchor (the profile URL, or details that match what I already know). Name alone is not a match. If several people fit, say so. If nobody fits, say that. And every fact has to carry the URL of the search result it came from.

Then, as I've written before, I fed it inputs where I knew the right answer was nothing. An invented name with an invented job. A very common Israeli name with a vague context line. A real name with plenty of search results, paired with a context that fits none of them. All three came back empty: "not found" or "ambiguous", no facts. In the common-name case it found a near match, an engineer at the right kind of company, and rejected him because he lived in a different city. That was the behaviour I wanted before trusting it with anything real.

Only then did it run on six people I had actually been messaging. All six were identified, every cited source was one of the real search results, and the three I know personally were described correctly.

Real contacts
6 / 6
identified with a matching anchor
Invented sources
0
every fact cites a search result
Decoy inputs
3 / 3
correctly returned nothing
Per brief
~$0.05
10 to 25 seconds, then cached

A correct answer that didn't help

One of the six was an old friend I used to work with. The brief about him was accurate, sourced, and completely useless to me. I know who he is. What I didn't know was what had happened since we last talked, and the brief had no idea we had a history at all.

That split the panel into two modes. Who is this? is for someone new: what isn't visible on their profile, and a few natural ways to open. What's new? is for someone I already know: it reads the dates in the thread, finds the last time we talked, and looks only for things that happened after it. A private note per person, kept only in my browser, tells it what I already know and anchors the search. A note, or a thread history older than a month, switches the default to What's new.

A Chrome window on facebook.com/messages with a Messenger chat with Omri Teller, where the last message before today is from March 2024. The panel is in What's new mode, with the label New since 3.3.2024 and four dated items: a new Creative Director role, a conference talk, a typeface side project, and closing his freelance studio.
In Messenger, with an old friend: What's new mode shows only things dated after the last time we talked, newest first.

Ambiguous is not an answer

The first time I used it for real, on a Marketplace chat, it said "ambiguous": at least two people with that name. That was honest, and it was also no help. The model had found both of them and then shown me neither, because I had told it never to guess.

Not guessing was right. Hiding what it found was not. Now an ambiguous result shows each person as a separate card, with what was found about that person only and where it came from, and a button that says That's them. The panel still never merges two people into one. It just stops pretending the choice isn't mine. Picking one is remembered for that contact and becomes the anchor for every later brief.

A Chrome window on facebook.com with a Marketplace chat popup at the bottom of the feed, from Gal Shenhar, whose chat photo is a family on a beach. The panel shows an amber Ambiguous pill and two cards: Gal Shenhar in DevOps and security at Larkspur Networks with an office headshot and three sourced facts, and Gal Shenhar in IT services at Bramble Systems with a different headshot and one fact. Each card has a That's them button.
In a Facebook Marketplace chat popup: two people with the same name, shown apart. The decision stays with the person in the conversation.

The shortcut I didn't take

Looking at that screen, the obvious idea is the photo. The chat shows one, the candidates have one, so let the machine match them and skip the cards.

I tested the harmless version of that first: not comparing faces, only checking whether the chat photo is the same picture as a candidate's profile photo, using a perceptual hash. Identical pictures score close to zero. The chat photo against the right person's profile photo scored between 21 and 28. Photos of entirely different people, used as a control, scored between 19 and 41. In other words, no signal at all.

Facebook chat photo Generated photo of a man crouching on a Tel Aviv beach with his wife and two young children.
30 hash distance
same man
different men: 24 to 34
identical photos: under 8
LinkedIn profile photo Generated LinkedIn profile photo of the same man in a navy shirt by an office window.
The same check on two generated photos of one fictional man. His own two photos score further apart than photos of three different men.

The reason is obvious once you see it. People put a family photo where they talk to friends and a headshot where they look for work. The only thing those two images share is a face, and matching faces to find out who a stranger is, is a different kind of tool from the one I set out to build. It is also the kind I don't think should exist as a browser extension. So the photos stay in the panel, for me to look at, and the machine doesn't decide anything from them.

The model never says who someone is from a face. It shows me what it found and lets me decide.

What it reads, and what it doesn't

Most of the rules came from the same question: what is the smallest amount this thing needs to see?

What went wrong

Why it stays on my machine

It works, and I use it, but I'm not releasing it. A public extension that reads LinkedIn pages runs against their terms, and a tool for researching the people in your conversations is easy to turn into a tool for researching anyone. The version that makes sense to me is the narrow one: my threads, my notes, a model that shows its sources, and a person who makes the call.

The interesting engineering wasn't the scraping or the prompt. It was the list of things the panel refuses to do, and making each of those refusals a line of code rather than a hope.

About the examples. Daniel, Omri, Gal, Quillmark, Brightloom, Larkspur and Bramble are made up, and every photo in this piece is generated. The numbers come from the real tests on real contacts, whose names stay out of it.