Skip to content

Plugins

Every event the SDK produces — track calls, $autocapture, $pageview, $identify — flows through a plugin pipeline before it reaches the send queue:

track()/identify()/$autocapture/... → before → enrichment → after → send queue
import type { KildenPlugin } from '@kilden/sdk';
const scrubEmails: KildenPlugin = {
name: 'scrub-emails',
stage: 'before',
process(event) {
if (typeof event.properties.email === 'string') {
const { email, ...rest } = event.properties;
return { ...event, properties: rest };
}
return event;
},
};
kilden.use(scrubEmails);
interface KildenPlugin {
name: string;
stage: 'before' | 'enrichment' | 'after';
setup?(client: KildenClient): void;
process?(event: EventPayload): EventPayload | null; // null = drop
teardown?(): void;
}
Stage Can transform Can drop (return null) Typical use
before yes yes filters, sampling, PII scrubbing
enrichment yes shouldn’t — dropping here is a design smell adding properties
after no no observation only; the return value is ignored

Within a stage, plugins run in registration order.

  • process is synchronous. Do async work in setup, or in an after plugin with its own queue.
  • use(plugin) with an existing name replaces that plugin (same slot in the order).
  • removePlugin(name) calls the plugin’s teardown() if it has one.
  • use() before init queues like any pre-init call.
  • A plugin that throws is isolated: the error is caught (logged only with debug: true) and the event continues with the previous stage’s result. The public API never throws because of a plugin.

InitOptions.beforeSend registers an anonymous before plugin under the hood — observable behavior is identical to writing the plugin yourself. It’s the quickest way to transform or drop everything, including automatic events:

kilden.init('YOUR_WRITE_KEY', {
beforeSend(event) {
if (event.event === '$autocapture') return null; // drop
return event;
},
});

Sessions ($session_id), context properties, $utm_* parsing and autocapture are implemented as internal plugins on this same pipeline. Autocapture registers itself late, when its lazy chunk finishes loading — plugins you register are never blocked by it.