Bundle custom functionality into reusable plugins for CE.SDK.

Plugins provide a structured way to package UI components, event handlers, actions, and configuration into a single unit. While you can customize CE.SDK without plugins by calling APIs directly after initialization, plugins help organize code for sharing across projects or publishing for others to use.
This guide covers creating plugins with the factory function pattern, registering custom components during initialization, and letting integrators control where your plugin’s UI elements appear.
Plugin Types#
Two plugin interfaces exist: EditorPlugin for full editor integration and EnginePlugin for headless engine use. Editor plugins receive both cesdk and engine in their context; engine plugins receive only engine. Structure your plugins to handle both contexts for maximum flexibility.
Creating a Plugin#
The Plugin Interface#
Plugins implement an interface with name, version, and initialize properties. The initialize method executes when you call cesdk.addPlugin() or engine.addPlugin(). Return a promise from initialize for async setup operations.
const CustomFeaturePlugin = ( userConfig: CustomFeaturePluginConfig = {}): EditorPlugin => { // Merge user config with defaults const config: CustomFeaturePluginConfig = { ...DEFAULT_CONFIG, ui: { ...DEFAULT_CONFIG.ui, ...userConfig.ui } };
return { name: 'CustomFeaturePlugin', version: '1.0.0',
async initialize({ cesdk, engine }: EditorPluginContext): Promise<void> {Adding a Plugin to the Editor#
Call cesdk.addPlugin() after creating the editor instance. Pass a plugin object directly or call a factory function that returns one.
// Add the plugin with configurationawait cesdk.addPlugin( CustomFeaturePlugin({ ui: { locations: ['canvasMenu'] } }));Making Plugins Configurable#
The Factory Function Pattern#
Export a function that returns the plugin object rather than the object directly. This allows integrators to pass configuration options. Even without current configuration needs, this pattern prevents breaking changes when adding options later.
interface CustomFeaturePluginConfig { ui?: { locations?: ('canvasMenu' | 'inspectorBar')[]; };}
const DEFAULT_CONFIG: CustomFeaturePluginConfig = { ui: { locations: [] }};The factory function merges user-provided configuration with sensible defaults. Document available options so integrators understand how to customize behavior.
Plugin Initialization#
Registering Components#
Use cesdk.ui.registerComponent() to add custom UI components. Components become available for placement in canvas menus, inspector bars, and other locations. The builder API creates buttons, inputs, and other controls.
// Register a custom button componentcesdk.ui.registerComponent( 'customFeaturePlugin.action.canvasMenu', (context) => { context.builder.Button('custom-action', { label: 'Custom Action', icon: '@imgly/Apps', onClick: () => { cesdk.ui.showNotification({ message: 'Custom action triggered!', type: 'success', duration: 'short' }); console.log('Custom action executed'); } }); });Subscribing to Events#
Use engine.event.subscribe() to react to block changes. Store the unsubscribe function for cleanup when needed. Event subscriptions set up reactive behavior without executing immediate actions.
// Subscribe to block events for demonstrationconst unsubscribe = engine.event.subscribe([], (events) => { events.forEach((event) => { if (event.type === 'Created') { console.log(`Block created: ${event.block}`); } });});
// Store unsubscribe for potential cleanup(window as any).unsubscribeCustomFeature = unsubscribe;Controlling Component Placement#
Offer a configuration option for default locations. Check this option during initialization and only modify order when explicitly requested by the integrator.
// Only add to canvas menu if configuredconst locations = config.ui?.locations ?? [];if (locations.includes('canvasMenu')) { const currentOrder = cesdk.ui.getCanvasMenuOrder(); cesdk.ui.setCanvasMenuOrder([ 'customFeaturePlugin.action.canvasMenu', ...currentOrder ]); console.log('Custom action added to canvas menu');}This approach lets integrators decide whether to use default placement or handle positioning themselves.
Troubleshooting#
Plugin Not Initializing#
Verify addPlugin() is called after the editor or engine is created. Check for errors thrown during initialize - exceptions prevent plugin setup. Ensure async initialize functions return promises properly.
Components Not Appearing#
Confirm components are registered with unique IDs. Check that component IDs match exactly when setting order. Verify the location is configured in the plugin options if using optional placement.
Context Arguments Missing#
For editor plugins, cesdk is undefined when added via engine.addPlugin(). Always check if cesdk exists before calling editor-specific APIs. Structure code to work with engine-only contexts when needed.
Configuration Not Applied#
Verify the factory function pattern is used and called with parentheses: MyPlugin() not MyPlugin. Check that configuration is passed to the factory: MyPlugin({ option: value }).
API Reference#
| Method | Purpose |
|---|---|
cesdk.addPlugin() | Add and initialize a plugin to the editor |
engine.addPlugin() | Add and initialize a plugin to the engine |
cesdk.ui.registerComponent() | Register a custom UI component |
cesdk.ui.setCanvasMenuOrder() | Set component order in canvas menu |
cesdk.ui.getCanvasMenuOrder() | Get current canvas menu component order |
engine.event.subscribe() | Subscribe to block lifecycle events |
Next Steps#
- Register New Component — Learn component registration in detail
- Customize UI Behavior — React to events and control UI programmatically
- Create Custom Panel — Build custom panels for your plugin
- Disable or Enable Features — Control feature availability