Skip to content

Extensions SDK cheatsheet

A practical map of the Ableton Extensions SDK calls a context-menu extension uses, grouped by what they do. It is a guide to the shape, not a copy of Ableton’s reference.

  • initialize(context, '1.0.0') returns the API for your target version.
  • api.commands.registerCommand(id, handler) binds a command id to a function.
  • api.ui.registerContextMenuAction(scope, label, commandId) puts the command in the right-click menu for a scope (for example a MIDI clip, a clip slot selection, an audio track). Keep the returned unregister function.

Reads are synchronous getters off the song graph: tempo, the root note and scale intervals, the grid, the track list, a track’s clip slots and devices, a clip’s notes. Read what you need into plain data, then leave the SDK behind for the logic.

Every write goes inside one transaction so it is one undo step:

context.withinTransaction(() => {
// your writes
});

Two facts make this work, and getting them wrong is the most common mistake:

  • The transaction callback is synchronous. Property setters (a clip’s notes, a track’s name, a clip’s color) are synchronous, so they run inline.
  • Only create, delete, duplicate, and parameter get/set are async. To group async operations into one undo, return Promise.all([...]) from the synchronous callback. Never await inside the callback.

So a pure-setter edit (snap notes to scale) is a plain synchronous transaction, while an edit that creates clips returns a Promise.all of the creates. That one distinction shapes every write an extension makes.

For anything slow (rendering audio, a large batch write), wrap it in a progress dialog and honor the abort signal:

await context.ui.withinProgressDialog('Working…', { progress }, async (update, signal) => {
// call update(...) as you go; bail when signal.aborted
});

A modal webview returns its result to the host by posting { method: "close_and_send", params: [resultString] } to the webview bridge. Windows and macOS expose that bridge under different globals, so ship both code paths. The Webview UI page covers this.