Skip to main content

Dashboard

A pre-built dashboard can be installed separately that runs inside your Strapi admin panel. See usage information like DAU, manage sessions, disable 2FA and much more.

Installation

The additional dashboard plugin requires you to have the Better Auth plugin already installed and configured.

Packages

npm install @better-auth/infra @strapi-community/plugin-better-auth-dashboard
# or
yarn add @better-auth/infra @strapi-community/plugin-better-auth-dashboard
# or
pnpm add @better-auth/infra @strapi-community/plugin-better-auth-dashboard

Configuration

warning

This plugin only works if you have not changed the basePath of Better Auth. It needs to be the default /api/auth path.

In order to run this plugin you need to configure the dash() and jwt() plugins from Better Auth.

src/lib/auth.ts
import { dash } from "@better-auth/infra";
import { betterAuth } from 'better-auth';
import { jwt } from 'better-auth/plugins';
import { strapiAdapter } from '@strapi-community/plugin-better-auth';

export const auth = betterAuth({
database: strapiAdapter(),
trustedOrigins: ['http://localhost:3000'],
plugins: [
jwt(),
dash({
apiUrl: process.env.STRAPI_URL || "http://localhost:1337",
apiKey:
process.env.BETTER_AUTH_DASHBOARD_SECRET ||
"strapi-internal-dashboard-key",
}),
],
advanced: {
database: {
generateId: 'serial',
},
},
emailAndPassword: {
enabled: true,
},
});

Start Strapi

pnpm develop

The dashboard is now available in the Strapi admin panel.

Adaptive UI

The dashboard detects which Better Auth plugins you have enabled and adapts its interface automatically:

Better Auth pluginDashboard effect
admin (ban users)Enables the Ban action on users and bulk ban in the Users page
organizationAdds the Organizations page to the navigation
twoFactorShows 2FA enrollment status in the user detail drawer
emailVerificationShows email verification status and exposes a resend action

Edit view panel API

The dashboard exposes an API that lets other Strapi plugins inject custom sidebar panels into the user detail drawer and the organization detail view. Use it to display extra context — subscriptions, audit logs, feature flags, or anything else — right alongside the built-in fields.

Registering a panel

Call addEditViewSidePanel in the bootstrap function of your Strapi admin plugin:

my-plugin/admin/src/index.ts
import MyPanel from "./components/MyPanel";

export default {
register() {},

bootstrap(app: { getPlugin: (id: string) => { apis: Record<string, unknown> } }) {
const dashboardPlugin = app.getPlugin("better-auth-dashboard");
if (!dashboardPlugin) return; // dashboard not installed

const { addEditViewSidePanel } = dashboardPlugin.apis as {
addEditViewSidePanel: (config: EditViewPanelConfig) => void;
};

addEditViewSidePanel({
id: "my-plugin.subscription-info",
title: "Subscription",
model: "plugin::better-auth.user",
Component: MyPanel,
});
},
};

Config reference

PropertyTypeRequiredDescription
idstringUnique identifier for the panel. Use "my-plugin.panel-name" to avoid collisions.
titlestringHeading rendered above the panel content.
modelstring | string[]Restrict the panel to one or more content-type UIDs. Omit to show the panel in every edit view.
ComponentReact.ComponentType<EditViewPanelProps>The React component to render inside the panel.

EditViewPanelProps

Your component receives these props:

PropTypeDescription
modelstringContent-type UID of the open record (e.g. "plugin::better-auth.user").
documentIdstring | undefinedStrapi documentId of the record. Use this to fetch related data.
documentRecord<string, unknown> | undefinedFull Strapi document object. Contains all fields loaded by the detail view.

Available model values

Model UIDEdit view
plugin::better-auth.userUser detail drawer
plugin::better-auth.organizationOrganization detail view

Example component

my-plugin/admin/src/components/MyPanel.tsx
import { useQuery } from "react-query";

interface Props {
model: string;
documentId?: string;
document?: Record<string, unknown>;
}

export default function SubscriptionPanel({ documentId }: Props) {
const { data, isLoading } = useQuery(
["subscription", documentId],
() => fetch(`/api/subscriptions?userId=${documentId}`).then((r) => r.json()),
{ enabled: !!documentId },
);

if (isLoading) return <p>Loading…</p>;
if (!data) return null;

return <p>Plan: {data.plan}</p>;
}
tip

documentId is the Strapi document identifier, not the Better Auth userId. If you need the Better Auth user ID, read it from the document prop (e.g. document?.id).