Dashboard
The extension answers "did they read it". The dashboard answers "why do you think so".
A web app in your own Firebase project that reads your history live and shows the whole of it: how much you sent, how much landed, when people read you, who actually answers, and, for every single event, the sentence that justifies the verdict.
Seven pages, seven questions
| Page | The question it answers |
|---|---|
| Overview | How much did I send, how much landed, when, and what just happened |
| Emails | The full history, filtered by search, status, mailbox and sent date; the 500 most recent matches, and it says so when the cap is hit |
| Email detail | Every recorded hit, with the sentence explaining the verdict and who was behind it |
| Contacts | Who actually reads me: sorted by open rate, anyone with fewer than three sends greyed out, rates with no denominator sorted last |
| Links | Which links were clicked, by a person or a bot, in separate columns; rows with only bot traffic dimmed |
| Alerts | What was worth interrupting for: unread, all, snoozed |
| Settings | Linked Gmail accounts, every knob, agent keys, export and deletion |
The detail page
The product's actual differentiator lives here.
- The reason is body text, not a tooltip and not a disclosure. If a verdict cannot be justified in one readable line, it should not be shown.
- Each entry: the classification badge, with "N% sure" only when confidence is below 85%; the verb (Pixel loaded, Link clicked, Reply received, Delivery failed); the time and delay since send; the reason; the destination for clicks; device, family and truncated network; and a "Who" line in plain words.
- Any open or click not already judged yours can be claimed as your own, and undone. With two or more proxied opens, one button claims them all.
- After two claims, a card explains that you read your sent mail on a device without MailSignals and points at Gmail's external-images setting.
- The Tracked links panel distinguishes link tracking off at send, on but nothing eligible, and N links left as written, with the reason.
- A multi-recipient message carries the note that an open tells you someone read it, not which one.
- Header actions: Open in Gmail, Mute, and "Closed by you · Reopen" when you archived the thread.
- +3 s Delivered, open unconfirmed · 80% sure Pixel loaded Apple Mail Privacy Protection downloaded the image on delivery. The message reached the device, but we cannot tell whether it was read. Who: Nobody yet: the recipient's mail app fetched it on delivery.
- +26 min Opened Link clicked A mail client downloaded the image directly (Safari on iPhone), which happens when someone displays the message. Who: The recipient, on their own device.
- +3 d Delivery failed Delivery failed Gmail could not deliver to cc@oldvendor.example: Address not found. Who: Gmail, reporting that it could not deliver.
Reads are live
Every list is a live Firestore subscription, so a pixel hit appears within a second or two with no polling and no refresh. Every query is scoped to your account by path or by clause, mirroring the security rules, so a mistake shows up as a permission error rather than as someone else's data.
Writes go through the API
Every change goes through the same validated API the extension uses; the only direct writes are the read and snooze flags on your own alerts. Settings edits are held in a local draft and written in one request, so a half-typed number never reaches the server, and a live update never wipes out what you are typing.
Nothing third-party
The page loads no fonts and no analytics. Firebase and the charting library are split into their own chunks and cached for a year, so a redeploy does not invalidate the vendor code in everyone's cache. Errors are shown with a reload button and reported nowhere.
Export and delete
Messages, events, contacts and links export as CSV or JSON, capped at 5,000 messages, 20,000 events, 5,000 contacts and 5,000 links, with the JSON reporting a truncation flag rather than cutting off silently. CSV is RFC 4180 with CRLF line endings, and any cell beginning with a character that would make a spreadsheet execute it is guarded: an export contains recipient-controlled strings.
"Delete everything" requires typing the phrase, re-checked on the server, and removes every message, event, link, contact, statistic and alert. It keeps the account, its settings, its linked mailboxes and its agent keys: this is "start again", not "close account".
Where it lives
dashboard/src/pages/EmailDetail.tsx- The timeline, the reason as body text, the Who line, claims and undo.
dashboard/src/lib/metrics.ts- Status at your sensitivity, the funnel, the heatmap, contact rows.
dashboard/src/lib/data.ts- Every read, as a live subscription.
firestore.rules- The real read boundary, tested as a real end user by the security suite.
Related: the verdicts · what is stored, and export and deletion in full.
Run it in your own project.
One Firebase project, two subdomains, one deploy script. About an hour the first time, and no subscription afterwards.