Skip to main content

Overview

The events field in StudioConfig controls how authentication events are captured, stored, and displayed. Events provide visibility into user actions like sign-ups, logins, password changes, and more.

Type Definition

events?: {
  enabled?: boolean;
  tableName?: string;
  provider?: EventIngestionProvider;
  client?: any;
  clientType?: "postgres" | "prisma" | "drizzle" | "clickhouse" | "https" | "custom" | "sqlite" | "node-sqlite";
  include?: AuthEventType[];
  exclude?: AuthEventType[];
  batchSize?: number;
  flushInterval?: number;
  retryOnError?: boolean;
  liveMarquee?: LiveMarqueeConfig;
  onEventIngest?: (event: AuthEvent) => void | Promise<void>;
}

Fields

enabled
boolean
Enable or disable event tracking.Default: falseExample:
events: {
  enabled: true
}
tableName
string
Name of the database table to store events. When provided, Studio will automatically use your Better Auth adapter.Example:
events: {
  enabled: true,
  tableName: "auth_events"
}
provider
EventIngestionProvider
Custom event ingestion provider. Implement this interface for custom event storage backends.
client
any
Database client instance (Postgres pool, Prisma client, Drizzle instance, ClickHouse client, etc.).Used when you want Studio to manage event storage using your existing database connection.
clientType
string
Type of database client being used.Options:
  • "postgres" - PostgreSQL client
  • "prisma" - Prisma client
  • "drizzle" - Drizzle ORM
  • "clickhouse" - ClickHouse client
  • "sqlite" - SQLite
  • "node-sqlite" - Node SQLite
  • "https" - HTTP/HTTPS endpoint
  • "custom" - Custom client
Example:
events: {
  enabled: true,
  client: prisma,
  clientType: "prisma"
}
include
AuthEventType[]
Whitelist of event types to track. Only these events will be captured.Example:
events: {
  enabled: true,
  include: [
    "user.joined",
    "user.logged_in",
    "user.logged_out"
  ]
}
See Event Types for the complete list.
exclude
AuthEventType[]
Blacklist of event types to ignore. All events except these will be captured.Example:
events: {
  enabled: true,
  exclude: [
    "session.created",
    "user.updated"
  ]
}
See Event Types for the complete list.
batchSize
number
Number of events to batch before flushing to storage.Default: 10Example:
events: {
  enabled: true,
  batchSize: 50 // Flush every 50 events
}
flushInterval
number
Time interval (in milliseconds) to automatically flush events to storage.Default: 5000 (5 seconds)Example:
events: {
  enabled: true,
  flushInterval: 10000 // Flush every 10 seconds
}
retryOnError
boolean
Whether to retry event ingestion on failure.Default: trueExample:
events: {
  enabled: true,
  retryOnError: false
}
liveMarquee
LiveMarqueeConfig
Configuration for the live events marquee display in the Studio UI.Example:
events: {
  enabled: true,
  liveMarquee: {
    enabled: true,
    pollInterval: 3000,
    speed: 1,
    pauseOnHover: true,
    limit: 100,
    sort: "desc",
    timeWindow: { since: "1h" },
    colors: {
      success: "#10B981",
      error: "#EF4444",
      warning: "#F59E0B",
      info: "#3B82F6"
    }
  }
}
onEventIngest
(event: AuthEvent) => void | Promise<void>
Callback function invoked when an event is ingested. Use this for custom event processing, logging, or analytics.Example:
events: {
  enabled: true,
  onEventIngest: async (event) => {
    console.log(`Event captured: ${event.type}`);
    // Send to analytics service
    await analytics.track(event);
  }
}

Event Types

Complete list of available AuthEventType values:

User Events

  • "user.joined" - User registration/sign-up
  • "user.logged_in" - User login
  • "user.logged_out" - User logout
  • "user.updated" - User profile updated
  • "user.password_changed" - Password changed
  • "user.email_verified" - Email verification completed
  • "user.banned" - User banned
  • "user.unbanned" - User unbanned
  • "user.deleted" - User account deleted
  • "user.delete_verification_requested" - Account deletion verification requested

Organization Events

  • "organization.created" - Organization created
  • "organization.updated" - Organization updated
  • "organization.deleted" - Organization deleted
  • "member.added" - Member added to organization
  • "member.removed" - Member removed from organization
  • "member.role_changed" - Member role changed

Team Events

  • "team.created" - Team created
  • "team.updated" - Team updated
  • "team.deleted" - Team deleted
  • "team.member.added" - Member added to team
  • "team.member.removed" - Member removed from team

Session Events

  • "session.created" - New session created
  • "login.failed" - Failed login attempt

Password Events

  • "password.reset_requested" - Password reset requested
  • "password.reset_completed" - Password reset completed
  • "password.reset_requested_otp" - Password reset via OTP requested
  • "password.reset_completed_otp" - Password reset via OTP completed

OAuth Events

  • "oauth.linked" - OAuth account linked
  • "oauth.unlinked" - OAuth account unlinked
  • "oauth.sign_in" - Sign in via OAuth

Invitation Events

  • "invitation.created" - Invitation sent
  • "invitation.accepted" - Invitation accepted
  • "invitation.rejected" - Invitation rejected
  • "invitation.cancelled" - Invitation cancelled

Phone Number Events

  • "phone_number.otp_requested" - Phone number OTP requested
  • "phone_number.verification" - Phone number verified

AuthEvent Interface

export interface AuthEvent {
  id: string;
  type: AuthEventType;
  timestamp: Date;
  status: "success" | "failed";
  userId?: string;
  sessionId?: string;
  organizationId?: string;
  metadata?: Record<string, any>;
  ipAddress?: string;
  userAgent?: string;
  source: "app" | "api";
  display?: {
    message: string;
    severity?: "info" | "success" | "warning" | "failed";
  };
}

Usage Examples

Basic Setup with Adapter

import { defineStudioConfig } from "better-auth-studio";

export const studioConfig = defineStudioConfig({
  auth,
  events: {
    enabled: true,
    tableName: "auth_events",
  },
});

With Prisma Client

import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

export const studioConfig = defineStudioConfig({
  auth,
  events: {
    enabled: true,
    client: prisma,
    clientType: "prisma",
    tableName: "auth_events",
  },
});

Selective Event Tracking

export const studioConfig = defineStudioConfig({
  auth,
  events: {
    enabled: true,
    tableName: "auth_events",
    include: [
      "user.joined",
      "user.logged_in",
      "login.failed",
      "password.reset_requested",
    ],
  },
});

With Custom Event Processing

export const studioConfig = defineStudioConfig({
  auth,
  events: {
    enabled: true,
    tableName: "auth_events",
    batchSize: 100,
    flushInterval: 10000,
    onEventIngest: async (event) => {
      // Send to external analytics
      if (event.type === "login.failed") {
        await securityMonitoring.alert(event);
      }
    },
  },
});

Full Configuration with Live Marquee

export const studioConfig = defineStudioConfig({
  auth,
  events: {
    enabled: true,
    tableName: "auth_events",
    batchSize: 50,
    flushInterval: 5000,
    retryOnError: true,
    exclude: ["session.created"], // Too noisy
    liveMarquee: {
      enabled: true,
      pollInterval: 2000,
      speed: 0.5,
      pauseOnHover: true,
      limit: 100,
      sort: "desc",
      timeWindow: { since: "1h" },
      colors: {
        success: "#10B981",
        error: "#EF4444",
        warning: "#F59E0B",
        info: "#3B82F6",
        failed: "#DC2626",
      },
    },
    onEventIngest: async (event) => {
      console.log(`📊 Event: ${event.type}`, event);
    },
  },
});

Build docs developers (and LLMs) love