Skip to main content
Version: Next

Custom Analytics Providers

CommandKit's analytics system is designed to be extensible, allowing you to create custom analytics providers for your specific needs.

Creating a Custom Provider

To create a custom provider, implement the AnalyticsProvider interface:

import {
AnalyticsProvider,
AnalyticsEvent,
IdentifyEvent,
} from 'commandkit/analytics';

class AnonymousAnalyticsProvider implements AnalyticsProvider {
readonly name = 'anonymous-analytics';

constructor(private readonly analytics: YourAnalyticsService) {}

async track(engine: AnalyticsEngine, event: AnalyticsEvent): Promise<void> {
// Implement your tracking logic here
const { name, data } = event;

// Example: Send anonymous data to your analytics service
await this.analytics.track({
name,
// Only include anonymous data
data: {
...data,
// Add anonymous session info
sessionId: this.generateSessionId(),
timestamp: Date.now(),
},
});
}

async identify(engine: AnalyticsEngine, event: IdentifyEvent): Promise<void> {
// Implement anonymous session identification
await this.analytics.identify({
// Use anonymous session identifiers
sessionId: this.generateSessionId(),
timestamp: Date.now(),
// Include anonymous session properties
properties: {
environment: process.env.NODE_ENV,
version: '1.0.0',
},
});
}

private generateSessionId(): string {
return 'session_' + Math.random().toString(36).substring(7);
}
}

Creating a Plugin

Create a plugin class that extends RuntimePlugin:

import { CommandKitPluginRuntime, RuntimePlugin } from 'commandkit/plugin';
import { AnonymousAnalyticsProvider } from './provider';

export interface AnonymousAnalyticsPluginOptions {
analyticsOptions: {
apiKey: string;
options?: YourAnalyticsOptions;
};
}

export class AnonymousAnalyticsPlugin extends RuntimePlugin<AnonymousAnalyticsPluginOptions> {
public readonly name = 'AnonymousAnalytics';

private provider: AnonymousAnalyticsProvider | null = null;

public async activate(ctx: CommandKitPluginRuntime): Promise<void> {
const analytics = new YourAnalyticsService(
this.options.analyticsOptions.apiKey,
this.options.analyticsOptions.options,
);

this.provider = new AnonymousAnalyticsProvider(analytics);

ctx.commandkit.analytics.registerProvider(this.provider);
}

public async deactivate(ctx: CommandKitPluginRuntime): Promise<void> {
if (!this.provider) return;

// Cleanup if needed
await this.provider.analytics.shutdown?.();

ctx.commandkit.analytics.removeProvider(this.provider);
}
}

Using Your Custom Provider

Add your custom provider to your CommandKit configuration:

import { AnonymousAnalyticsPlugin } from './anonymous-analytics-plugin';

export default defineConfig({
plugins: [
new AnonymousAnalyticsPlugin({
analyticsOptions: {
apiKey: 'YOUR_API_KEY',
options: {
// Your analytics service options
},
},
}),
],
});

Best Practices

  1. Keep your provider implementation focused and single-purpose
  2. Handle errors gracefully and log them appropriately
  3. Implement both track and identify methods if your analytics service supports them
  4. Use TypeScript for better type safety and developer experience
  5. Document your provider's configuration options and requirements
  6. Consider Discord's rate limits when sending data
  7. Only track anonymous, aggregated data
  8. Avoid storing personal information
  9. Use hashed identifiers when necessary
  10. Be transparent about what data you collect

Example: Simple Console Provider

Here's a simple example of a provider that logs anonymous events to the console:

import {
AnalyticsProvider,
AnalyticsEvent,
IdentifyEvent,
} from 'commandkit/analytics';

class ConsoleProvider implements AnalyticsProvider {
readonly name = 'console';

async track(engine: AnalyticsEngine, event: AnalyticsEvent): Promise<void> {
console.log('Analytics Event:', {
name: event.name,
// Only log anonymous data
data: {
...event.data,
timestamp: Date.now(),
},
});
}

async identify(engine: AnalyticsEngine, event: IdentifyEvent): Promise<void> {
console.log('Session Identified:', {
sessionId: 'session_' + Math.random().toString(36).substring(7),
timestamp: Date.now(),
environment: process.env.NODE_ENV,
});
}
}

// Plugin implementation
export class ConsoleAnalyticsPlugin extends RuntimePlugin {
public readonly name = 'ConsoleAnalytics';

private provider: ConsoleProvider | null = null;

public async activate(ctx: CommandKitPluginRuntime): Promise<void> {
this.provider = new ConsoleProvider();
ctx.commandkit.analytics.registerProvider(this.provider);
}

public async deactivate(ctx: CommandKitPluginRuntime): Promise<void> {
if (!this.provider) return;
ctx.commandkit.analytics.removeProvider(this.provider);
}
}

Next Steps