Discover how to integrate IMG.LY’s video editor into your Vue.js application.

Users who trim and caption clips every day in TikTok or CapCut expect to do the same inside your product. When they cannot, they export, edit somewhere else, and upload again. That round trip is where people drop out of the workflow and where your assets stop being yours to template or version.

This guide covers adding a video editor to a Vue.js app with CreativeEditor SDK (CE.SDK): the component, the timeline and export APIs underneath it, and the customization points that come up once it runs.

Check browser support before you scope the work

CE.SDK’s video mode encodes and decodes in the browser through the WebCodecs API. That is what makes client-side MP4 export possible without a render backend, and it is also the constraint. Video mode requires a recent Chromium browser: Chrome, Edge, Opera, Arc, and Brave all work. Safari and Firefox do not currently support video editing.

Design and photo editing run everywhere, so this only limits the video path. If a large share of your traffic is on Safari, plan a fallback message now rather than during QA.

Why put the editor inside the app

YouTube Shorts passes 70 billion daily views and TikTok reports more than a billion monthly active users. Those numbers matter here for one reason: they set the baseline for how easy people think video editing should be.

Two things follow. Users expect filters, overlays, audio, and text within a few clicks, and they expect it where they already are. Vue’s single-file components suit this well, because the editor becomes one component you mount with a config object and an init hook.

How to integrate a video editor in Vue.js

Requirements

If you need a project, scaffold one and answer the prompts however you like. Selecting “No” throughout is fine for following along:

npm create vue@latest my-vue-video-editor
cd my-vue-video-editor

Step 1: Install CE.SDK

npm install @cesdk/cesdk-js

Step 2: Create the editor component

CE.SDK ships a Vue component, so you do not manage the editor instance or its teardown yourself. Import it from the /vue entry point and give it a config object and an init function.

Create src/components/VideoEditor.vue:

<!-- src/components/VideoEditor.vue -->
<template>
  <CreativeEditor :config="config" :init="init" width="100vw" height="100vh" />
</template>

<script setup>
import CreativeEditor from '@cesdk/cesdk-js/vue';

const config = {
  license: 'YOUR_LICENSE_KEY', // replace with your key
  userId: 'YOUR_USER_ID', // optional, for MAU tracking across devices
};

const init = async (cesdk) => {
  await Promise.all([
    cesdk.addDefaultAssetSources(),
    cesdk.addDemoAssetSources({
      sceneMode: 'Video',
      withUploadAssetSources: true,
    }),
  ]);

  await cesdk.createVideoScene();
};
</script>

sceneMode: 'Video' loads the video and audio demo libraries instead of the design ones, so the asset panel holds clips and music. In production you swap these for your own sources, whether that is your backend or a third-party library such as Unsplash.

createVideoScene() is what gives you the timeline. Calling createDesignScene() instead produces the design editor with no time dimension, which is the usual reason a first integration loads without a timeline.

Step 3: Use the component

<!-- src/App.vue -->
<template>
  <VideoEditor />
</template>

<script setup>
import VideoEditor from './components/VideoEditor.vue';
</script>

Run npm run dev. You should get a full editor with a timeline: trimming, splitting, text overlays, audio tracks, and filters.

Name your wrapper something other than CreativeEditor, or it will collide with the imported component.

Gotchas worth knowing up front

init fails silently. If a line inside init throws, the rest is skipped and nothing reaches the console. You get a half-built scene with no error. Wrap it while developing:

const init = async (cesdk) => {
  try {
    await cesdk.addDefaultAssetSources();
    await cesdk.createVideoScene();
  } catch (error) {
    console.error('[CE.SDK init] failed:', error);
  }
};

Relative asset URLs resolve against the CDN. CE.SDK resolves relative URIs against config.baseURL, which points at the IMG.LY CDN, so /videos/intro.mp4 will not hit your origin. Make local paths absolute before passing them to the engine.

Trim calls need loaded media. setTrimOffset and setTrimLength depend on duration metadata. Call await engine.block.forceLoadAVResource(fill) first or they quietly do nothing.

Nuxt needs a client-only boundary. The editor is browser-only, so server-side rendering will break it. Wrap it in <ClientOnly> or use a .client.vue component.

Let an agent do the integration

If you work in an AI-assisted editor, Agent Skills for CE.SDK load the current documentation and conventions into Claude Code, Cursor, and similar tools, so the generated integration matches the current API rather than a remembered one. There is also an MCP server for live doc lookup during a session. We wrote about the reasoning in Introducing IMG.LY Agent Skills.

Building compositions in code

The default UI handles user-facing editing. For templates, automation, or a custom interface, work through cesdk.engine.

Create a scene and a page

In video mode a page owns a timeline, and its duration is the duration of the export.

const engine = cesdk.engine;

const scene = engine.scene.createVideo();

const page = engine.block.create('page');
engine.block.appendChild(scene, page);
engine.block.setWidth(page, 1280);
engine.block.setHeight(page, 720);
engine.block.setDuration(page, 20); // seconds

Add clips

Video is not a block type of its own. You create a graphic block and attach a video fill, so the same positioning and animation APIs apply to video as to anything else.

const clip = engine.block.create('graphic');
engine.block.setShape(clip, engine.block.createShape('rect'));

const fill = engine.block.createFill('video');
engine.block.setString(
  fill,
  'fill/video/fileURI',
  'https://cdn.img.ly/assets/demo/v3/ly.img.video/videos/pexels-drone-footage-of-a-surfer-barrelling-a-wave-12715991.mp4'
);
engine.block.setFill(clip, fill);

Sequence with a track

A track keeps its children playing back to back and recalculates offsets when a duration changes, so you do not position clips by hand.

const track = engine.block.create('track');
engine.block.appendChild(page, track);
engine.block.appendChild(track, clip1);
engine.block.appendChild(track, clip2);
engine.block.fillParent(track);

engine.block.setDuration(clip1, 15); // track shifts clip2 automatically

Size the children, not the track. A track derives its dimensions from what it contains.

Trim and audio

Blocks default to 5 seconds. A longer clip gets cut off, a shorter one loops.

await engine.block.forceLoadAVResource(fill);
engine.block.setTrimOffset(fill, 1); // skip the first second
engine.block.setTrimLength(fill, 10);
engine.block.setMuted(fill, true);

const audio = engine.block.create('audio');
engine.block.appendChild(page, audio);
engine.block.setString(
  audio,
  'audio/fileURI',
  'https://cdn.img.ly/assets/demo/v3/ly.img.audio/audios/far_from_home.m4a'
);
engine.block.setVolume(audio, 0.7);
engine.block.setTimeOffset(audio, 2);

Export to MP4

Encoding runs in a background worker, so the editor stays usable. The scene freezes when the export starts, so later edits will not show up in the file.

const page = engine.scene.getCurrentPage();

const blob = await engine.block.exportVideo(page, {
  mimeType: 'video/mp4',
  onProgress: (rendered, encoded, total) => {
    progress.value = Math.round((encoded / total) * 100);
  },
});

const anchor = document.createElement('a');
anchor.href = URL.createObjectURL(blob);
anchor.download = 'export.mp4';
anchor.click();

Bind onProgress to a ref and you have a progress bar. Long compositions take a while to encode, and silence reads as a hang.

You can also extract just the audio with engine.block.exportAudio(page, { mimeType: 'audio/wav' }), which is handy for transcription and caption pipelines. Speaking of which, caption presets and transitions between clips are both worth a look once the basics work.

Full reference: the create and edit videos guide and the timeline editor docs.

Customizing the editor

  • Component order. Add, remove, and reorder UI elements with setComponentOrder({ in: location }, order) across locations like 'ly.img.dock', 'ly.img.canvas.menu', and 'ly.img.inspector.bar'.
  • Theming. cesdk.ui.setTheme() for light, dark, or system, or build one with the theme generator. See the theming demo.
  • Asset libraries. Serve media from your own backend or connect third-party sources. Users can browse and search both from inside the editor.
  • Feature API. Show and hide functionality by context, which is how you reflect backend permissions in the UI.
  • Localization. Override and extend every string with full i18n support.

Reusable customizations belong in a plugin. Background removal and vectorization ship that way.

Where a Vue video editor pays off

Marketing automation. Generate campaign variants from one template with text variables, and push template edits across every asset built on it. Bulk import of PSD files turns existing design work into editable scenes. This is mostly an engine job rather than a UI one.

E-learning. Instructors record, trim, and caption in the browser and build a template library instead of one-off files. Plugins can add quizzes and polls.

Sales outreach. Personalized video at volume, with localization for teams selling into several markets.

Social publishing. Templates, an audio library, and configurable animations, then export per platform aspect ratio.

Digital asset management. Teams adapt approved footage centrally. CE.SDK has no built-in role model, so permissions live in your backend and surface through the Feature API.

Next steps

Start from the Vue video editor starter kit, which is a working project rather than a snippet, or try the demo first.

On a different framework? We have the same guide for React and Angular, plus a broader JavaScript video editing guide on the underlying browser tech. Still comparing vendors? See our breakdown of the leading video editing SDKs.

Questions about your use case? Talk to us.