Email analytics
Track opens and clicks on marketing emails with signed, provider-agnostic hooks and read per-template rates on the admin Emails page.
Email analytics measures how your marketing emails perform. Every founder-style send is tagged, its opens and clicks are recorded by your own backend, and the numbers roll up into an admin Emails page at /admin/emails. It is on by default and works with any provider - no vendor dashboard, no external setup.
What gets tracked
Only the five founder-style marketing templates carry tracking:
| Template | Purpose |
|---|---|
welcome | Post-signup founder hello |
announcement | Product announcement |
getting-started-check-in | Onboarding nudge |
feedback-request | Ask for feedback |
we-miss-you | Re-engagement |
Transactional emails are never tracked. Password resets, verifications, magic links, and invitations carry no pixel and no rewritten links, so they never appear in analytics.
How it works
Each tracked send gets two signed hooks, both served by your own backend - so analytics behaves identically on SMTP, SES, and Resend with zero provider configuration.
| Hook | Mechanism |
|---|---|
| Open | A 1x1 pixel with a signed token. The backend verifies the signature and records an open. |
| Click | Every link is rewritten to a signed redirect. The backend verifies the token, records a click, then 302s to the real destination. |
| Prefetch window | Hits arriving within 10 seconds of dispatch are ignored. The pixel still returns and links still redirect, but no event is recorded. |
| Noise limits | Known bot user-agents are filtered out, and each send records at most 50 events. |
| Machine opens | Opens prefetched by Apple Mail Privacy Protection are stored as machine opens and left out of views and open rate. Gmail's and Yahoo's image proxies fetch only when the reader opens, so they count as real opens. |
Signing means counts cannot be forged by replaying a URL. The prefetch window exists because mailbox providers fetch images and security gateways follow links as the message lands - without it every send would score a 100% open rate instantly.
Metrics
The same counts drive every card and chart. Rates fall back to 0 when the denominator is 0.
| Metric | Definition |
|---|---|
| Sent | Emails sent for that template in the selected period. |
| Views | Total opens, repeat opens included. A count, never a share of sent. |
| Open rate | Unique opens / sent. Each recipient counts once, so it never exceeds 100%. |
| Click rate | Unique clicks / sent. Each recipient counts once. |
| CTOR | Click-to-open rate: unique clicks / unique opens. |
Opens are approximate; clicks are not. Machine opens are excluded where they can be recognized, but some proxies look like readers. Treat click rate as the trustworthy metric when comparing subject lines or copy.
The endpoint also returns deliverability totals over every send in the range - see Email deliverability.
The admin Emails page
The Overview tab of /admin/emails shows the deliverability cards, then:
- Per-template cards - sent, views, open rate, click rate, and CTOR for the range, one card per tracked template.
- Rate chart - open rate and click rate plotted over time, with 7 / 30 / 90 day tabs and a per-template filter.
The page loads the last 90 days once and re-slices it in the browser, so switching views is instant. The Log and Blocked tabs are covered in Email deliverability.
Configuration
Analytics is governed by config.email.tracking in packages/config/src/index.ts:
email: {
// ...
tracking: {
enabled: true, // default - master switch
retentionDays: 90 // default - days of event history to keep
}
}| Key | Effect |
|---|---|
enabled | Turns the feature on or off. |
retentionDays | Caps the email log and its events; a daily cleanup job deletes anything older. |
enabled: false stops recording opens and clicks, and the Overview tab shows a notice in place of the cards and chart; the delivery cards, Log and Blocked tabs stay. Links in already-sent emails keep redirecting so readers are never stranded - they simply are not counted.
Privacy
- No personal identifiers stored. Events record which send was opened or clicked and when - never the reader's IP address or user agent.
- Cascade deletion. A user's email events are deleted with the user.
- Retention cleanup. The daily job prunes sends and events past
retentionDays, keeping the tables bounded.
Rotating BETTER_AUTH_SECRET invalidates tracking URLs in already-delivered emails: opens stop counting and tracked links stop redirecting, since the destination is signature-verified like other signed links.
Send transactional and marketing email through SMTP, SES, or Resend with @repo/mail, and sync newsletter lists with config.newsletter.
Email deliverability
Log every email the app sends, read bounces and complaints from SES or Resend webhooks, and block suppressed addresses before they reach the provider.