Guides / SaaS

How to Track Email Opens and Click Events

3 min readยทSaaS

Why log email events

Email open rates and click rates tell you which messages land. Logging them to LogIt lets you:

  • See exactly when a specific user opened a specific email
  • Track whether a re-engagement campaign is working
  • Get notified when a transactional email bounces

Resend webhook handler

ts
// app/api/webhooks/resend/route.ts
import { logit } from "@/lib/logit";

interface ResendWebhookEvent {
  type: string;
  data: {
    email_id: string;
    from: string;
    to: string[];
    subject?: string;
    click?: { link: string };
    bounce?: { message: string };
  };
}

export async function POST(req: Request) {
  const payload = await req.json() as ResendWebhookEvent;

  const to = payload.data.to[0] ?? "unknown";
  const subject = payload.data.subject ?? "unknown";

  switch (payload.type) {
    case "email.opened":
      await logit.now("emails", {
        event: "Email opened",
        description: `${to} opened: ${subject}`,
        icon: "๐Ÿ“ง",
        notify: false,
        tags: { type: "open" },
        metadata: { emailId: payload.data.email_id, to, subject },
      });
      break;

    case "email.clicked":
      await logit.now("emails", {
        event: "Email link clicked",
        description: `${to} clicked: ${payload.data.click?.link ?? "unknown"}`,
        icon: "๐Ÿ–ฑ๏ธ",
        notify: false,
        tags: { type: "click" },
        metadata: { to, link: payload.data.click?.link, subject },
      });
      break;

    case "email.bounced":
      await logit.now("emails", {
        event: "Email bounced",
        description: `${to}: ${payload.data.bounce?.message ?? "hard bounce"}`,
        icon: "โš ๏ธ",
        notify: true,
        tags: { type: "bounce" },
        metadata: { emailId: payload.data.email_id, to, subject },
      });
      break;
  }

  return new Response("ok");
}

SendGrid event webhook

ts
// app/api/webhooks/sendgrid/route.ts
interface SendGridEvent {
  event: string;
  email: string;
  subject?: string;
  url?: string;
  timestamp: number;
}

export async function POST(req: Request) {
  const events = await req.json() as SendGridEvent[];

  for (const ev of events) {
    if (ev.event === "open" || ev.event === "click") {
      await logit.now("emails", {
        event: `Email ${ev.event}`,
        description: ev.email,
        icon: ev.event === "open" ? "๐Ÿ“ง" : "๐Ÿ–ฑ๏ธ",
        notify: false,
        tags: { provider: "sendgrid", type: ev.event },
        metadata: { email: ev.email, subject: ev.subject, timestamp: ev.timestamp },
      });
    }
  }

  return new Response("ok");
}

Try LogIt free

7-day trial. No credit card required.

Start free