Learn how to integrate IMG.LY’s video editor for Angular into your web application.

People who trim and caption clips daily in TikTok or CapCut expect the same inside your product. When they cannot, they export, edit elsewhere, and upload again. Each round trip is a chance to abandon the task, and every asset that leaves your system stops being one you can template or keep on brand.

This guide covers adding a video editor to an Angular app with CreativeEditor SDK (CE.SDK): the component wiring, the timeline and export APIs underneath, and the customization points you will reach for 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 have no such limit. If a meaningful share of your users are on Safari, plan a fallback now rather than in QA.

How to set up a video editor in Angular

Unlike React and Vue, Angular has no first-class CE.SDK component. You create the editor yourself in ngAfterViewInit and dispose of it in ngOnDestroy. That is a few more lines, but it is explicit and it gives you a clear place to hold the instance.

Requirements

  • Node.js 20+ and npm 10+. Download Node.js if needed.
  • An Angular project. Create one with ng new my-angular-video-editor if you do not have one.
  • A CE.SDK license key. Start a free trial to get one.

Step 1: Install CE.SDK

npm install @cesdk/cesdk-js

Step 2: Generate the component

ng generate component video-editor

Step 3: Wire up the editor

Open src/app/video-editor/video-editor.component.ts. The editor mounts into a <div> you reference with @ViewChild, created after the view initializes and disposed when the component goes away.

// src/app/video-editor/video-editor.component.ts
import {
  AfterViewInit,
  Component,
  ElementRef,
  OnDestroy,
  ViewChild,
} from '@angular/core';
import CreativeEditorSDK, { Configuration } from '@cesdk/cesdk-js';

@Component({
  selector: 'app-video-editor',
  standalone: true,
  templateUrl: './video-editor.component.html',
  styleUrl: './video-editor.component.css',
})
export class VideoEditorComponent implements AfterViewInit, OnDestroy {
  @ViewChild('cesdk_container') containerRef!: ElementRef;

  private cesdk?: CreativeEditorSDK;

  async ngAfterViewInit(): Promise<void> {
    const config: Configuration = {
      license: 'YOUR_LICENSE_KEY', // replace with your key
      userId: 'YOUR_USER_ID', // optional, for MAU tracking
      baseURL: `https://cdn.img.ly/packages/imgly/cesdk-js/${CreativeEditorSDK.version}/assets`,
      callbacks: { onUpload: 'local' },
    };

    const instance = await CreativeEditorSDK.create(
      this.containerRef.nativeElement,
      config
    );

    this.cesdk = instance;

    await Promise.all([
      instance.addDefaultAssetSources(),
      instance.addDemoAssetSources({
        sceneMode: 'Video',
        withUploadAssetSources: true,
      }),
    ]);

    await instance.createVideoScene();
  }

  ngOnDestroy(): void {
    this.cesdk?.dispose();
    this.cesdk = undefined;
  }
}

Three details are easy to get wrong here.

createVideoScene() is what produces the timeline. createDesignScene() gives you the design editor with no time dimension, which is the most common reason a video integration comes up without a timeline.

ngOnDestroy matters more in Angular than the equivalent does elsewhere. The engine holds WebAssembly memory and worker threads, and navigating away without calling dispose() leaks both. Route between two views a few times without it and you will watch memory climb.

The baseURL line pins asset loading to the CDN build matching your installed version, which avoids version skew between the JavaScript and the assets it fetches.

Then define the template at video-editor.component.html:

<div #cesdk_container [style.height.vh]="100" [style.width.vw]="100"></div>

Step 4: Use the component

// src/app/app.component.ts
import { Component } from '@angular/core';
import { VideoEditorComponent } from './video-editor/video-editor.component';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [VideoEditorComponent],
  templateUrl: './app.component.html',
  styleUrl: './app.component.css',
})
export class AppComponent {}

And in app.component.html:

<app-video-editor></app-video-editor>

Run ng serve. You should get a full editor with a timeline: trimming, splitting, text overlays, audio tracks, and filters. Compare against the interactive demo.

Two more things that bite

Relative asset URLs resolve against the CDN. Because baseURL points at IMG.LY’s CDN, a relative URI like /videos/intro.mp4 resolves there rather than against your own origin. Make local asset paths absolute before handing them to the engine.

Angular Universal needs a guard. The editor is browser-only. If you server-side render, keep the component behind an isPlatformBrowser check or it will fail during SSR.

Let an agent do the integration

If you work in an AI-assisted editor, Agent Skills for CE.SDK load CE.SDK’s current documentation and conventions into Claude Code, Cursor, and similar tools, so the code you get back matches the current API instead of a remembered one. There is also an MCP server for live lookup during a session. Background in Introducing IMG.LY Agent Skills.

Building compositions in code

The default UI covers user-facing editing. For templates, automation, or a custom interface, go through this.cesdk.engine.

Scene and page

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

const engine = instance.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

Clips and tracks

Video is not its own block type. A graphic block with a video fill gets you the same positioning and animation APIs as any other element. A track keeps children playing back to back and recalculates offsets when durations change.

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);

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

Size the children rather than the track. A track takes its dimensions from what it holds.

Trim and audio

Blocks default to 5 seconds. Longer clips get cut off, shorter ones loop. Trim APIs need duration metadata, so load the resource first.

await engine.block.forceLoadAVResource(fill);
engine.block.setTrimOffset(fill, 1);
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);

Skipping forceLoadAVResource is a common bug: the trim calls fail quietly and the clip plays in full.

Export to MP4

Encoding runs in a background worker, so the editor stays responsive. The scene freezes at the start of the export, so later edits will not appear in the output.

const page = engine.scene.getCurrentPage();

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

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

Bind progress to your template and you have a progress bar. Encoding a long composition takes time, and an unexplained wait reads as a hang.

engine.block.exportAudio(page, { mimeType: 'audio/wav' }) extracts just the audio, which is useful for transcription and captioning. On that note, caption presets and transitions are both worth exploring 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 such as 'ly.img.dock', 'ly.img.canvas.menu', and 'ly.img.inspector.bar'.
  • Roles. CE.SDK supports roles, which bundle global settings and scopes. Switching role applies that role’s defaults, and you can define custom roles for specific workflows.
  • Theming. cesdk.ui.setTheme() for light, dark, or system, or build one with the theme generator. See the theming demo.
  • Export options. Control which formats users can export, plus quality and dimensions.
  • Asset libraries. Serve media from your own backend or connect a third-party source.
  • Localization. Override and extend every string with full i18n support.

Package reusable customizations as a plugin. Background removal and vectorization ship that way.

Where an Angular video editor pays off

Marketing outreach. Personalized video at volume beats a cold email, and text variables plus localization make per-recipient variants a data problem rather than an editing 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.

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

E-commerce. Short product videos raise conversion, and Amazon’s own seller guidance points at meaningful lifts. Templates plus product data generate variations at catalogue scale without a designer per SKU.

Creative automation. Define templates once, then feed them from your data to produce campaign variants. Combined with A/B testing, teams ship several cuts and keep the one that performs.

Next steps

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

Building the same thing elsewhere? We have equivalent guides for React and Vue.js, plus a broader JavaScript video editing guide on the underlying browser technology. Still comparing options? See our breakdown of the leading video editing SDKs.

Questions about your use case? Talk to us.