ScreenshotNeo

BlogEngineering

Events Emitted by Embedded Design Editors

A complete guide to Adobe Embedded Design Editor callbacks, payloads, host actions, publish handling, errors, and integration patterns.

By the ScreenshotNeo team30 September 20268 min read

Events Emitted by Embedded Design Editors

Embedded design editors communicate with the host application through callbacks. In Adobe’s Embedded Design Editor (EDE), the host can observe loading, cancellation, publishing, errors, generic host events, and workflow intent changes through the CC Everywhere Callbacks interface. All callbacks are optional, so implement only the lifecycle events your application needs.

The callbacks most hosts implement are:

  • onLoadInit and onLoadStart for loading indicators and timing.
  • onLoad to enable controls after the editor is ready.
  • onCancel to close the editor and record how cancellation happened.
  • onPublishStart and onPublish to track and process exports.
  • onError to show an actionable failure and capture diagnostics.
  • onEvent for supported information-style host events.
  • onIntentChange for transitions between design workflows, although Adobe documents this callback as not currently operational for EDE workflows.

How the Embedded Design Editor fits into a host application

EDE is a configurable creation surface embedded in another application. The two documented module workflows are module.createDesign(), which starts from a template or blank canvas, and module.editDesign(), which reopens an existing document. Both workflows use appConfig, exportConfig, and containerConfig. The edit workflow also receives docConfig describing the document to preload.

Callbacks are supplied as part of the module configuration. A host normally uses them to synchronize its own UI, telemetry, persistence layer, and export pipeline with the editor lifecycle. The editor remains responsible for the design surface; the host responds to state changes.

Complete callback reference

Callback When it runs Payload or return value Typical host action
onLoadInit May run when the target application begins loading and its spinner starts. LoadInitCallback payload. Show the initial loading state.
onLoadStart May run when target application loading starts. LoadStartCallback. Start a timer or telemetry span.
onLoad May run after target application loading finishes. LoadCallback. Enable controls that require a ready editor.
onCancel May run when the user cancels the workflow. isEscapePressed: boolean. Close host state and distinguish Escape from another cancel action.
onPublishStart May run when the user starts export by clicking a save button. Optional exportButtonId: string. Mark export as active and identify the selected export action.
onPublish May run after export finishes. (intent, publishParams); may return void or Promise<PublishStatus>. Store the document ID, process the asset, and acknowledge or deny the save.
onError May run for an editor error. error: CCEverywhereError; returns void. Display a useful message and log diagnostics.
onEvent May run for information-style host events. message: HostEventData; returns void. Consume supported host event messages.
onIntentChange Runs when a user moves from one design intent to another, such as Quick action to Express. (oldIntent, newIntent); may return IntentChangeConfig. Adapt app, export, or container configuration when supported.
The host application reacts to separate lifecycle callbacks from the embedded editor.
The host application reacts to separate lifecycle callbacks from the embedded editor.

Load lifecycle events

onLoadInit

Use onLoadInit for the earliest loading state. The callback may occur when the target application starts loading and the editor spinner begins. This is a good place to display a host-level skeleton, disable duplicate launch buttons, and create a correlation ID for logs.

onLoadStart

onLoadStart indicates that target application loading has started. Start a timer here if you want to measure the interval until onLoad. Keep this measurement separate from the time required to export a design; they represent different operations.

onLoad

Use onLoad as the readiness boundary for host controls that depend on the editor. For example, you can enable a surrounding “Continue” button, stop a loading timer, or mark the embedded surface ready in telemetry. Do not assume that a host page being mounted means the editor is ready; use the callback supplied by the integration.

const callbacks = {
  onLoadInit() {
    setEditorState('loading');
    telemetry('editor_load_init');
  },
  onLoadStart() {
    loadStartedAt = performance.now();
    telemetry('editor_load_start');
  },
  onLoad() {
    const elapsed = performance.now() - loadStartedAt;
    setEditorState('ready');
    telemetry('editor_load_complete', { elapsedMs: elapsed });
  }
};

Cancellation events

onCancel runs when the user cancels the workflow. Its payload contains isEscapePressed, a Boolean that tells you whether Escape caused the cancellation. Use this to close a modal, release temporary state, and record the user’s exit path. Cancellation is not a publish failure: do not show an error message or retry an export when this callback fires.

onCancel({ isEscapePressed }) {
  closeEditorPanel();
  discardUnsavedHostDraft();
  telemetry('editor_cancel', { method: isEscapePressed ? 'escape' : 'control' });
}

Publish lifecycle and returned data

onPublishStart

This callback may run when the user starts an export by clicking a save button. The optional exportButtonId identifies the selected export action. Set a host-side “publishing” state here, disable duplicate submission, and show progress. Always clear that state in both success and error paths.

A publish callback can persist the document ID and process an optional preview.
A publish callback can persist the document ID and process an optional preview.

onPublish

When export finishes, EDE calls onPublish with intent and publishParams. The callback can return nothing or a promise resolving to a PublishStatus. Adobe’s tutorial demonstrates returning { status: "SUCCESS" } to acknowledge the save.

The tutorial also stores publishParams.documentId. Persisting that identifier lets the host reopen the same design later with module.editDesign({ docId }). For a preview, the tutorial reads publishParams.assetPreview[0].data. Treat that preview as a display payload; your production asset workflow should separately decide how full-resolution output is stored or delivered.

Export configuration can expose PDF and PNG publish actions. Full-resolution output may be returned as a URL or blob, while an optional preview may be returned as base64. These are software payload choices, so the host should select the representation that fits its storage and transport path.

const callbacks = {
  async onPublish(intent, publishParams) {
    setPublishing(false);

    const documentId = publishParams.documentId;
    await saveDocumentReference({ documentId, intent });

    const preview = publishParams.assetPreview?.[0]?.data;
    if (preview) {
      showPreview(preview);
    }

    return { status: 'SUCCESS' };
  },

  onPublishStart({ exportButtonId }) {
    setPublishing(true);
    telemetry('editor_publish_start', { exportButtonId });
  }
};

Error handling

onError receives a CCEverywhereError and returns void. Show a message that tells the user what they can do next, while logging the structured error for diagnosis. Avoid exposing raw internal details as the only user-facing message.

onError(error) {
  setPublishing(false);
  setEditorState('error');

  logError('embedded_editor_error', {
    name: error?.name,
    message: error?.message,
    details: error
  });

  showError('The editor could not complete that action. Please try again.');
}

Generic events and intent changes

onEvent

onEvent receives HostEventData for information-style host events. The cited callback type reference does not provide a complete event-name catalog, so do not build behavior around undocumented message names. Log the received message during integration, then handle only event types documented for the version you deploy.

onIntentChange

This callback receives oldIntent and newIntent when a user navigates between design workflows. It may return an IntentChangeConfig that updates application, export, or container configuration. Adobe’s EDE guide currently says this callback is not operational for EDE workflows, so treat it as a forward-compatible hook rather than a required part of today’s EDE control flow.

onIntentChange(oldIntent, newIntent) {
  telemetry('editor_intent_change', { oldIntent, newIntent });

  // Keep this defensive until the callback is operational for your EDE flow.
  if (newIntent === 'supported-host-flow') {
    return {
      appConfig: getAppConfigFor(newIntent),
      exportConfig: getExportConfigFor(newIntent),
      containerConfig: getContainerConfigFor(newIntent)
    };
  }
}

A practical host integration pattern

  1. Create a host state machine with idle, loading, ready, publishing, canceled, and error states.
  2. Set loading state in onLoadInit or onLoadStart; mark the editor ready only in onLoad.
  3. Disable duplicate publish controls in onPublishStart.
  4. Persist documentId in onPublish before acknowledging the save.
  5. Use the returned publish status to decide whether the host closes the editor or keeps it open.
  6. Clear temporary state on both onCancel and onError.
  7. Include an integration or request ID in telemetry so load and publish records can be correlated.

Troubleshooting common callback problems

Symptom Likely cause Fix
The host enables controls too early. Readiness is inferred from iframe mounting. Enable dependent controls from onLoad.
Publish appears stuck. The host never clears its publishing state on an error. Reset the state in both onPublish and onError.
A canceled design is treated as a failure. onCancel is routed through error handling. Handle cancellation separately and inspect isEscapePressed.
The same document cannot be reopened. publishParams.documentId was not persisted. Store the document ID during onPublish and pass it to editDesign.
Preview rendering fails. The host assumes every publish includes a preview. Check assetPreview and its first item before reading data.
Intent-specific configuration never changes. onIntentChange is not operational for the current EDE workflow. Configure the supported workflow up front and do not depend on this callback.
Unknown event names break the host. Undocumented onEvent messages are treated as stable API. Log unknown messages and handle only documented event types.

Performance, reliability, and cost considerations

Measure editor load and export separately. A slow load can come from initialization, authentication, or host configuration; a slow publish can come from export processing or asset transfer. Keep callbacks short and move network writes, image processing, and analytics batching to asynchronous tasks.

Make publish handling idempotent. A retry or duplicate user action should not create conflicting host records for the same documentId. Persist the document reference before starting nonessential preview work, and record the export intent and button identifier when available.

Do not assume every callback fires exactly once or that optional callbacks always run. Design cleanup paths so the host can recover if a user closes the surrounding modal, the embedding page unmounts, or an error interrupts the normal sequence.

Or skip the browser setup

If your goal is to capture the editor or any published page rather than embed an editor yourself, ScreenshotNeo provides a single screenshot API request. It accepts the cookie or consent banner like a visitor, removes more than 60 known consent platforms plus newsletter popups and chat widgets, and bills only clean shots. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, with the result identified by X-Page-Verdict and X-Billed headers. Its MCP server also gives Claude, Cursor, and other MCP clients take_screenshot, get_page_info, and capture_pdf tools.

cURL:

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://stripe.com \
  -o shot.webp

Python:

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
open("shot.webp", "wb").write(r.content)

Node.js:

const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://stripe.com'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

See the ScreenshotNeo API documentation for the request options. 1,000 screenshots each month are free with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

FAQ

Are all callbacks required?

No. Every callback in the CC Everywhere Callbacks interface is optional.

Can onPublish be asynchronous?

Yes. It may return void or a promise resolving to PublishStatus.

What identifies the saved design?

Use publishParams.documentId, then pass that ID to module.editDesign({ docId }) when reopening it.

Does onEvent have a complete public event catalog?

The cited type reference defines the payload but does not provide a complete event-name catalog. Handle documented messages for the version you use.

Should a cancellation be retried?

No. Cancellation is a user decision. Offer a new launch action instead of treating it as an export failure.