Guides / SaaS
B2B account health is a collection of signals over time: logins, feature usage, support tickets, integration activity. When those signals drop off, churn risk rises.
// lib/account-health.ts
import { logit } from "@/lib/logit";
type HealthSignal = "login" | "feature_used" | "export" | "api_call" | "support_ticket" | "inactive_warning";
export async function logAccountActivity(accountId: string, accountName: string, signal: HealthSignal) {
const isRisk = signal === "inactive_warning" || signal === "support_ticket";
await logit.now("account-health", {
event: `Account signal: ${signal}`,
description: `${accountName} — ${signal.replace("_", " ")}`,
icon: isRisk ? "⚠️" : "✅",
notify: isRisk,
tags: { accountId, signal, risk: isRisk ? "true" : "false" },
metadata: { accountId, accountName, signal, timestamp: new Date().toISOString() },
});
}
// jobs/inactive-account-check.ts (runs daily)
export async function checkInactiveAccounts() {
const cutoff = new Date(Date.now() - 14 * 24 * 3600 * 1000);
const inactive = await db.account.findMany({
where: { lastActivityAt: { lt: cutoff }, plan: { not: "free" } },
});
for (const account of inactive) {
await logit.now("account-health", {
event: "Account inactive",
description: `${account.name} has been inactive for 14+ days`,
icon: "😴",
notify: true,
tags: { accountId: account.id, plan: account.plan, risk: "true" },
metadata: { accountId: account.id, accountName: account.name, lastActivityAt: account.lastActivityAt },
});
}
}
| Field | Value |
|---|---|
| Name | Support ticket cluster |
| Channel | account-health |
| Event name | Account signal: support_ticket |
| Threshold | 3 |
| Window | 7 days |
| Cooldown | 7 days |
| Action | Push notification |
accountId in tags so you can filter the dashboard to a single account's full health timeline.Try LogIt free
7-day trial. No credit card required.