Consenti

Plugin System

Plugins extend the Consenti backend with custom lifecycle hooks. They run server-side, are instantiated once per createConsenti() call, and can access the full storage adapter.

Plugin contract

ts
import { ConsentiServerPlugin } from '@consenti/api'
import type { ConsentDbRecord, CreateConsentInput, PluginContext } from '@consenti/api'

export class MyPlugin extends ConsentiServerPlugin {
  name = 'my-plugin'

  async initialize(ctx: PluginContext): Promise<void> {
    // Called once after storage.connect() resolves.
    // ctx.storage gives you the full StorageAdapter.
    // ctx.config gives you the server config.
  }

  async destroy(): Promise<void> {
    // Called on graceful shutdown — close connections, clear timers.
  }

  // ── Optional hooks ──────────────────────────────────────────────────────────

  async beforeConsentSave(data: CreateConsentInput): Promise<CreateConsentInput> {
    return data  // mutate or validate before DB write
  }

  async afterConsentSave(record: ConsentDbRecord): Promise<void> {
    // fires after consent is persisted — perfect for webhooks, analytics
  }

  async afterConsentUpdate(record: ConsentDbRecord): Promise<void> {
    // fires after PUT /consent/:visitorId
  }
}

Registering plugins

ts
import { createConsenti } from '@consenti/api'
import { WebhookPlugin } from '@consenti-plugin-webhook'
import { SlackPlugin } from '@consenti-plugin-slack'

const app = createConsenti({
  storage: { driver: 'sqlite', path: './consenti.db' },
  auth: { mode: 'local', adminEmail: '[email protected]', adminPassword: 'secret' },
  plugins: [
    new WebhookPlugin('https://your-endpoint.example.com/hook'),
    new SlackPlugin({ webhookUrl: process.env.SLACK_WEBHOOK }),
  ],
})

Available hooks

HookWhen it fires
initialize(ctx)After storage.connect() resolves — once at startup
destroy()On graceful shutdown
beforeConsentSave(data)Before a new consent record is written — can mutate the payload
afterConsentSave(record)After a new consent record is persisted
beforeConsentUpdate(data)Before an existing consent record is updated
afterConsentUpdate(record)After an existing consent record is updated
beforeProfileFetch(id)Before a profile is fetched — can redirect to a different profile ID
afterProfileFetch(profile)After a profile is fetched — can mutate the profile
beforeUserCreate(data)Before an admin user is created
afterUserCreate(user)After an admin user is created

Error handling

If a plugin throws in any hook, Consenti logs the error with console.warn and continues — a broken plugin never blocks consent from being recorded.

Official plugins

Community plugins

Publish your own under any package name. The only requirement is extending ConsentiServerPluginand declaring @consenti/api as a peer dependency.

package.json
json
{
  "name": "@your-scope/consenti-plugin-custom",
  "peerDependencies": {
    "@consenti/api": ">=0.1.0"
  }
}