Guides / SaaS
Most teams start with signups and payments and add channels as they think of them. After 6 months they have 30 channels with overlapping concerns, inconsistent naming, and Smart Actions rules that are hard to reason about.
A deliberate channel strategy prevents this.
Organize channels into four domains — each with a clear owner and purpose:
payments # Successful charges, payment intents
payment-failures # Declined charges, failed intents
subscriptions # Trial starts, conversions, upgrades, downgrades
churn # Cancellations, subscription deletions
refunds # Refunds and chargebacks
disputes # Stripe/payment disputes
signups # Account creation
activation # First value milestones (see activation guide)
feature-usage # Key feature interactions
onboarding # Onboarding step completions
emails # Transactional email sent/bounced/opened
deployments # Production deploys
errors # Application errors and exceptions
cron # Scheduled job results
jobs # Background worker events
api-usage # API call volume (if applicable)
security # Auth failures, suspicious activity
db-queries # Slow query alerts
uptime # Health check results
performance # Core Web Vitals, API latency spikes
// ✅ Good channel names
"payments"
"payment-failures"
"trial-signups"
"api-usage"
// ❌ Avoid
"payment_failures" // inconsistent casing
"all-events" // too broad
"payments-v2" // versioning in channel names
"misc" // a dumping ground
// lib/events.ts — centralized event logging
import { logit } from "@/lib/logit";
export const events = {
signups: {
userSignedUp: (email: string, plan: string) =>
logit.now("signups", { event: "New user signed up", description: email, icon: "👤", notify: true, tags: { plan } }),
},
payments: {
paymentReceived: (email: string, amount: number, currency: string) =>
logit.now("payments", { event: "Payment received", description: `${email} — ${(amount/100).toFixed(2)} ${currency.toUpperCase()}`, icon: "💰", notify: true, tags: { currency } }),
paymentFailed: (email: string, reason: string) =>
logit.now("payment-failures", { event: "Payment failed", description: `${email} — ${reason}`, icon: "❌", notify: false, tags: { reason } }),
},
ops: {
deploySucceeded: (sha: string, actor: string) =>
logit.now("deployments", { event: "Production deployment succeeded", description: `${sha.slice(0, 7)} by ${actor}`, icon: "🚀", notify: true, tags: { actor } }),
},
};
lib/events.ts wrapper so channel names and event names are defined in one place, not scattered across every file.Try LogIt free
7-day trial. No credit card required.