This guide explains how to use the CreativeEditor SDK (CE.SDK) Engine in headless mode within a Nuxt.js application. This setup is perfect for creating a fully custom editing experience or for automating design workflows entirely through code—without relying on the built-in visual editor.
Who Is This Guide For?
This guide is intended for developers who:
- Want to create a custom user interface instead of using the default CE.SDK editor.
- Need to integrate CE.SDK into client-side automation workflows without displaying a visual editor.
- Have already completed the “Getting Started with CE.SDK in Nuxt.js” tutorial and are ready to dive into more advanced use cases.
What You’ll Achieve
- Initialize the CE.SDK headless engine within a client-side Nuxt.js component.
- Programmatically create and modify a scene—including a custom button that reduces the opacity of a sample image by 20% each time it’s clicked.
- (Optional) Render the CE.SDK canvas for visual feedback while maintaining full control via your custom UI.
Prerequisites
Before you begin, make sure you have the following:
- A working Nuxt.js 3 project.
- The “Getting Started with CE.SDK in Nuxt.js” tutorial completed.
- A valid CE.SDK license key (start a free trial to get yours).
Step 1: Install CE.SDK Engine
To use CE.SDK in headless mode within your Nuxt.js project, install the SDK via the @cesdk/engine
npm package:
npm install @cesdk/engine
Step 2: Define a Custom Component for Your Headless CE.SDK Integration
Inside the /components
folder of your Nuxt.js project (or wherever you store your components), create a new file named CustomEditor.vue
defining the following component:
<template> <div style="width: 100vw; height: 100vh; position: relative"> <div ref="canvasRef" style="width: 100%; height: 100%"></div> <div class="button-overlay"> <div style="position: absolute; top: 20px; left: 20px"> <button @click="changeOpacity">Reduce Opacity</button> </div> </div> </div></template>
<script setup> import { ref, onMounted } from 'vue'; import CreativeEngine from '@cesdk/engine';
// DOM reference to hold the CE.SDK canvas const canvasRef = ref(null); // to keep track of the ID of the added image block let imageBlockId = null; // to keep track of the CreativeEngine instance let engine = null;
onMounted(async () => { // CE.SDK configuration const config = { license: '<YOUR_CE_SDK_LICENSE>', // replace with your actual license key };
// initialize CreativeEngine in headless mode engine = await CreativeEngine.init(config);
// attach CE.SDK canvas to the DOM (optional) if (canvasRef.value) { canvasRef.value.appendChild(engine.element); }
// get or create a new scene let scene = engine.scene.get(); if (!scene) { scene = engine.scene.create(); const page = engine.block.create('page'); engine.block.appendChild(scene, page); }
// get the first page block const [page] = engine.block.findByType('page');
// create a graphic block and set its shape imageBlockId = engine.block.create('graphic'); engine.block.setShape(imageBlockId, engine.block.createShape('rect'));
// fill the graphic block with a public image const imageFill = engine.block.createFill('image'); engine.block.setSourceSet(imageFill, 'fill/image/sourceSet', [ { uri: 'https://img.ly/static/ubq_samples/sample_1_1024x683.jpg', width: 1024, height: 683, }, ]); engine.block.setFill(imageBlockId, imageFill); engine.block.appendChild(page, imageBlockId);
// zoom to fit the page in the canvas engine.scene.zoomToBlock(page); });
// reduce the image opacity by 20% each click function changeOpacity() { if (engine && imageBlockId != null) { // get the current opacity value on the image const currentOpacity = engine.block.getOpacity(imageBlockId); // reduce the image opacity by 20% engine.block.setOpacity(imageBlockId, currentOpacity * 0.8); } }</script>
Once the CreativeEngine is initialized, you gain full programmatic control over your scene. In this example, a sample image is added to the canvas, and a button is included that reduces its opacity by 20% each time it’s clicked.
In detail, the changeOpacity()
function demonstrates how to interact with CE.SDK’s headless block
API. With that, you retrieve the current opacity of the image block and update it dynamically in the code.
Note: Attaching the CE.SDK canvas to the DOM is completely optional. You can use the engine entirely in headless mode—modifying scenes and assets directly in memory without rendering a visual interface. For instance, you could adjust image properties like opacity or dimensions in the browser, trigger a file download, and never display a UI at all.
From here, you’re ready to tailor the editor’s behavior and appearance to fit your exact needs. For example, you can style your custom editor with:
<style scoped> .editor-container { width: 100vw; height: 100vh; position: relative; }
.canvas-container { width: 100%; height: 100%; }
.button-overlay { position: absolute; top: 20px; left: 20px; }
.button-overlay button { border-radius: 8px; border: 1px solid #ccc; padding: 0.6em 0.6em; font-size: 1em; font-weight: 500; font-family: inherit; background-color: #ffffff; color: #1a1a1a; cursor: pointer; transition: border-color 0.25s, box-shadow 0.25s; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); width: 150px; }
.button-overlay button:hover { border-color: #646cff; box-shadow: 0 4px 10px rgba(100, 108, 255, 0.2); }
.button-overlay button:focus, .button-overlay button:focus-visible { outline: 2px solid #646cff; outline-offset: 2px; }</style>
Step 3: Create a Client-Side Editor Component
The CreativeEngine relies on browser-specific features like document
—and it performs dynamic DOM manipulation when attaching to the canvas. Because of that, the CustomEditor
component must run only on the client side. In other words, it should never be server-side rendered (SSR).
To enforce client-only rendering, you can wrap CustomEditor
with Nuxt’s <ClientOnly>
component. To avoid repeating this logic wherever you want to render the editor, create a wrapper component called CustomEditorNoSSR.vue
in your components/
directory:
<template> <ClientOnly> <CustomEditor /> </ClientOnly></template>
This wrapper ensures that the CustomEditor
component is rendered exclusively on the client.
Note: As an alternative, you can simply rename CustomEditor.vue
to CustomEditor.client.vue
. Nuxt automatically recognizes the .client.vue
suffix and guarantees that the component is rendered only on the client—making it ideal for auto-import scenarios without extra boilerplate.
Step 4: Use the Creative Editor Component
You can use your non-SSR editor component like this:
<CustomEditorNoSSR />
Or, if you renamed the file to CustomEditor.client.vue
:
<CustomEditor />
Once your Nuxt.js app is running, navigate to the page where the editor is rendered. You’ll see a sample image on the canvas and a “Reduce Opacity” button. Each time you click the button, the image’s opacity is reduced by 20%.
Use Cases
Congratulations! You’ve just laid the groundwork for more advanced use cases, such as:
- Building fully customized UIs using Nuxt.js components alongside the CE.SDK canvas.
- Automating the creation of graphics or marketing materials directly in the browser.
- Integrating CE.SDK into rich, multi-step creative browser workflows using programmatic logic.
- Adding server-side image or video processing features with
@cesdk/node
—as shown in our “Getting Started with CE.SDK in Node.js” guide.
Troubleshooting & Common Errors
❌ Error: document is not defined
- This error occurs when the CE.SDK Engine attempts to access the
document
object on the server side. To resolve that, check that theCustomEditor
component is rendered as a client-only component. Wrap it with<ClientOnly>y
or rename it as.client.vue
.
❌ Error: CE.SDK canvas doesn’t render
- Ensure that you’re appending
engine.element
to a valid DOM element. Double-check that the Vue.js ref is correct and that the element is properly attached to the DOM.
❌ Error: Failed to resolve import "@cesdk/engine" from "components/CustomEditor.vue". Does the file exist?
- Make sure that you’ve successfully installed the CE.SDK Engine by running the command
npm install @cesdk/engine
.
❌ Error: Editor engine could not be loaded: The License Key (API Key) you are using to access CE.SDK is invalid
- Confirm that your license key is valid, hasn’t expired, and is correctly configured in
config
.
❌ The component doesn’t behave as expected
- Verify that your component paths and imports are accurate.
- Review the browser console for any specific errors.
Next Steps
This guide sets the groundwork for:
- Developing a fully custom UI with Nuxt.js
- Exporting scenes programmatically
-
Batch processing graphics or templated content