IFrame Embed
The IFrame Embed integration allows video platforms and web applications to embed the full Closed Caption Creator editor directly within their own interface using a standard HTML <iframe> tag. Instead of building a caption editing tool from scratch, development teams can embed a professional-grade editor with support for over 30 subtitle formats, frame-accurate playback, real-time QC, and multilingual workflows — all accessible without ever leaving the host platform.
Communication between the parent application and the embedded editor is handled by PenPal JS, a lightweight cross-window messaging library. Through this connection, the parent page can programmatically load media, import subtitle files, configure project settings, run quality control checks, and retrieve edited content — making it possible to build tightly integrated captioning workflows tailored to any platform's requirements.
Getting Started
Before embedding the editor, ensure your application includes PenPal JS. The library is available via CDN and should be loaded in the parent page:
<script src="https://unpkg.com/penpal@^7/dist/penpal.min.js"></script>
Next, add an <iframe> element to your page pointing to the Closed Caption Creator IFrame demo URL. The allow attribute must include clipboard-write, clipboard-read, and encrypted-media for the editor to function correctly:
<div class="iframe-container">
<iframe
id="editor"
src="https://iframe-demo.closedcaptioncreator.com/"
style="width: 100%; height: 90vh;"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; clipboard-read; encrypted-media"
allowfullscreen>
</iframe>
</div>
Once the iframe is in place, use PenPal to establish a connection when the frame loads. The connection.promise resolves to a remote object containing all of the methods exposed by the editor. All calls to these methods are asynchronous and should be awaited:
iframe.addEventListener('load', async () => {
const messenger = new Penpal.WindowMessenger({
remoteWindow: iframe.contentWindow,
allowedOrigins: ['https://iframe-demo.closedcaptioncreator.com']
});
const connection = Penpal.connect({ messenger, methods: {} });
const remote = await connection.promise;
// Optional: apply chrome theme before loading content
// await remote.setTheme({ primary: '#408fe0', bodyBg: '#181c24' });
// await remote.loadCustomStyles('[data-bs-theme="dark"] { --bs-primary: #408fe0; }');
// Configure and load the project
await remote.setProjectName("My Project");
await remote.setProjectFrameRate(29.97);
await remote.setProjectDropFrame(true);
await remote.importMedia(mediaUrl);
await remote.importSubtitle(subtitleUrl, "subRip");
});
Key Functions
The following table describes the primary categories of methods available on the remote object. For a complete function reference including all parameters and return values, visit the IFrame Remote Documentation on the Closed Caption Creator website.
| Category | Representative Methods | Description |
|---|---|---|
| Project configuration | setProjectName, setProjectFrameRate, setProjectDropFrame, setProjectIncode, setProjectDescription, setAdLicense | Set project-level metadata before or after loading content. Use setAdLicense(true) to enable Audio Description license mode. |
| Media | importMedia, setPoster, setMediaPeaksPath, setMediaPeaksData, toggleTimeline | Load a video or audio file, set a thumbnail, and configure the audio waveform display. |
| Subtitle import/export | importSubtitle, exportSubtitle | Load a subtitle file from a URL or retrieve the edited captions in any supported output format. |
| App theme / branding | setTheme, loadCustomStyles, clearTheme | Customize UI chrome colors, fonts, and borders at runtime. Call immediately after connection.promise resolves so the editor is not briefly unthemed. Build-time customer themes may also ship via assets/css/themes/{system}.css. Does not recolor the Konva timeline. |
| Watermark | setWatermark | Draw a visual watermark (date/time, viewer email, IP address, custom line) over the media player, beneath the caption preview. The host resolves each value and passes it as a string, or null to omit that field. See Watermarking. |
| UI control | toggleStatusModal, updateModalStatus, updateModalTitle, alertUser, completeImport, failImport | Control the progress modal and display alerts to the user during loading sequences. |
| Locking & navigation | enableVideoLock, enableCaptionLock, enablePreviewLock, scrollToEventById, selectEventByIndex | Control synchronisation between the video player and the caption list. |
| Quality control | loadStyleGuide, qcEventGroup, getStyleGuides | Load a custom style guide and run validation checks against an Event Group. |
| Data retrieval | getProjectData, loadProjectData, getHistory, hasUnsavedChanges, getMarkers, setMarkers, getEventGroupInfo, getSelectedEventGroupId, getSelectedEvents | Retrieve or inject full project data, markers, and event selections. getEventGroupInfo and getSelectedEventGroupId include each group's BCP-47 language (default en-US) and letter tracks. Use getHistory for a lightweight undo stack summary and hasUnsavedChanges to detect edits since the last clean load/save (compares the undo stack position to the saved baseline; undoing back to that baseline clears the dirty state). |
| Auto tools | autoFormat, autoCorrectReadingSpeed, fixEventOverlap, insertBlankFrames, setProjectFrameGap | Programmatically apply formatting and timing corrections to caption tracks. |
| Audio Description (parent methods) | getVoices, renderAudio | When setAdLicense(true) is set, the iframe routes AD voice listing and TTS through the parent. Expose these methods on the parent's Penpal methods object: getVoices() and renderAudio({ text, voice?, speed?, format?, eventId? }). |
| Toolbar actions | setParentToolbarActions, configureSecondaryToolbar, parent exportSubtitle / cancel | Close and Save in the top-right toolbar are off by default (parentCancel / parentExportSubtitle in envStore). Call the child method setParentToolbarActions({ exportSubtitle?: boolean, cancel?: boolean }) after connection.promise to show them. Clicks invoke the matching parent-side Penpal methods (exportSubtitle() / cancel()); the parent decides what each action does. This is separate from the child exportSubtitle API used to encode/retrieve captions from the iframe. Use configureSecondaryToolbar({ left, center, right }) to choose which secondary-toolbar icons appear, in what order, and in which slot. Omit the call (or pass null) to keep the default iframe layout. |
Secondary toolbar
The secondary toolbar (Undo, Redo, alignment, split/merge, and other caption tools) can be customized after the PenPal connection resolves. The payload is a full layout for customizable icons: only listed IDs appear, in array order, in the given slot. Omitted slot keys are treated as empty.
await remote.configureSecondaryToolbar({
left: ['undo', 'redo', 'shortcuts'],
center: ['addEvent', 'removeEvent', 'split', 'merge'],
right: ['alignLeft', 'alignCenter', 'alignRight', 'copy', 'cut', 'paste']
});
Pass null (or call the method with no argument) to restore the default iframe layout: Undo, Redo, and Keyboard Shortcuts on the left, and the full caption-editing group on the right.
These icons cannot be shown, hidden, or moved via this method: Open, Save, Media Import, Automatic Transcription, Automatic Translation, and Settings. They stay hidden in iframe mode, matching the existing iframe toolbar. Keyboard shortcuts remain available when an icon is hidden.
Watermarking
A visual watermark can be drawn over the media player to deter screen capture of pre-release material. It is an overlay only — it is never burned into the media file or into any subtitle, audio, or video export. Team admins configure the overlay in the editor; see Video Watermarking for the Options workflow.
There are two ways to configure it:
- Teams: a team admin enables and configures it in Edit → Options → Watermark. The settings are stored on the team and applied for every member of that team, who cannot turn it off. Available fields are the current date and time, the signed-in user's email, their IP address, and a custom line of text, plus vertical alignment and text/shadow opacity.
- IFrame hosts: call the
setWatermark(settings)remote method. Host settings take precedence over any team configuration for the rest of the session. Edit → Options is hidden in iframe mode, so hosts must use this API.
The host resolves every display value itself, so the date/time, email, and IP address are supplied as strings (or null when that field should be omitted):
await remote.setWatermark({
enabled: true,
showDateTime: true,
dateTime: "2026-09-14 07:22:43", // "YYYY-MM-DD HH:mm:ss" in the viewer's local time
email: "user@example.com",
ipAddress: "203.0.113.10",
customText: "CONFIDENTIAL",
alignment: "bottom", // "top" | "center" | "bottom"
textOpacity: 100, // 0-100
shadowOpacity: 100 // 0-100
});
The timestamp is static once applied, so call setWatermark again on an interval if the watermark should track the current time. Pass enabled: false to remove the overlay.
Custom Themes
Dedicated offline iframe builds can match a host platform's look by shipping a customer theme stylesheet and logos keyed to the system slug, and/or by calling runtime remote methods from the parent page:
- Build-time:
assets/css/themes/{system}.cssloads automatically for non-demosystems (same slug pattern as{system}.pnglogos). - Runtime:
setTheme(tokens),loadCustomStyles(cssText), andclearTheme()customize chrome colors, fonts, and borders after PenPal connects. Call theme methods before importing media when possible.
These APIs affect UI chrome only (toolbar, panels, buttons, inputs, borders). They do not recolor the Konva timeline. Caption QC style guides (loadStyleGuide) and preview fonts (setPreviewFontFamily) remain separate.
For the full token contract, CSS examples, and customer-build checklist, see IFrame Theming.
Importing and Exporting Subtitles
The importSubtitle method loads a subtitle file from a URL into the editor. It accepts the file URL, a source profile identifying the format (for example "subRip" for SRT or "webVtt" for VTT), optional decode options specific to the format, and an optional Event Group options object for configuring real-time validation rules such as maxChars, maxLines, maxCps, and overlap. A complete list of supported source profiles is available at https://api.closedcaptionconverter.com/help/profiles/source.
By default importSubtitle creates a new Event Group. To import into an existing group instead, pass a target object as the seventh argument: { eventGroupId, importOption, track }. importOption accepts "replace" (default — swaps the group's events for the imported ones) or "merge" (appends the imported events to the group). When merging, the optional track value ("A"–"D") assigns every imported event to that track — useful for building multi-track groups such as dual-language or speaker-separated captions. For example, merging an SRT onto track B of an existing group:
await remote.importSubtitle(subtitleUrl, "subRip", null, {}, {}, false, {
eventGroupId: groupId,
importOption: "merge",
track: "B",
});
The exportSubtitle method encodes captions into a target format. It accepts a target profile, optional encode options, a saveAsFile boolean, an optional forcedOption, an optional eventGroupId, and an optional exportTracks array. When eventGroupId is omitted, the currently selected Event Group is exported. exportTracks (default ["none", "A", "B", "C", "D"]) limits the export to events on the listed tracks, where "none" matches events without a track assignment — pass ["B"], for example, to export only track B. Use getEventGroupInfo or getSelectedEventGroupId to discover which tracks a group uses via their tracks field, and which BCP-47 language tag to stamp on published files. When saveAsFile is false, the method returns the encoded file contents as a string so the parent application can handle delivery — for example, uploading the result to cloud storage or posting it to an API. When saveAsFile is true, a browser file download is triggered instead.
The mergeEventGroups method combines multiple Event Groups into a new group. Its optional fourth argument, groupTracks, maps source group IDs to track letters (for example { [groupAId]: "A", [groupBId]: "B" }) so each source group's events land on a dedicated track in the merged result.
Quality Control Workflows
Custom style guides can be loaded into the editor programmatically using loadStyleGuide, which accepts a style guide configuration object defining rules such as maximum characters per second, maximum duration, minimum event gap, and a range of text formatting checks. Once a style guide is loaded, qcEventGroup runs validation against a specified Event Group and returns all errors found, including error counts and the relevant event data. This enables the parent application to gate the publish action — preventing delivery until caption quality meets the configured standard — and to surface specific errors to the editor using the status modal functions.
Troubleshooting
The most common setup issue is an allowedOrigins mismatch. In production, the allowedOrigins array in the Penpal.WindowMessenger configuration must specify the exact origin of the IFrame — https://iframe-demo.closedcaptioncreator.com — rather than the wildcard '*' used in development. Using '*' in a production environment is a security risk and may also cause connection failures in certain browsers.
If the editor does not respond to method calls after the connection is established, confirm that the allow="clipboard-write; clipboard-read; encrypted-media" attribute is present on the <iframe> tag. Missing permissions prevent certain editor features from functioning and can cause the initialisation sequence to stall.
If the PenPal connection times out before your setup code runs, ensure that connectToIframe is called inside a load event listener on the iframe element rather than immediately after the iframe is added to the DOM. The connection should only be initiated once the iframe's content window is fully loaded.
For developer support and integration assistance, visit the Contact Page to connect with the Closed Caption Creator team.