It's been a while

Our last dedicated Embed update post was in 2020. That doesn't mean we stopped working on it. We've shipped over 30 releases since then, rewrote the SDK in TypeScript, added dozens of new API methods, and completely overhauled the documentation. This post catches you up on everything.

Music notation embed SDK v2: TypeScript-first

The biggest milestone was v2.0, released in September 2024. The embed client was fully rewritten in TypeScript, and the npm package now ships with complete type definitions out of the box. You get full autocompletion and type safety across all 60+ methods and events, with no @types package needed.

We also dropped the legacy jQuery constructor support in v2.0 (migration is a one-liner: just pass container[0]) and started shipping separate ES and UMD builds, so bundlers like Vite and Webpack 5 work correctly without any special configuration.

import Embed from 'flat-embed';

const embed = new Embed(container, {
  score: 'SCORE_ID',
  embedParams: {
    appId: 'YOUR_APP_ID',
    mode: 'view', // TypeScript knows valid modes
  },
});

// Full type checking and autocompletion
const parts = await embed.getParts();

New developer documentation

A few months ago, we restructured the entire embed documentation. The JavaScript and TypeScript SDK reference is now organized into focused sections:

We also made the docs AI coding tool-friendly. Each page ships a Markdown version (add .md to any docs URL), and we publish a llms.txt index covering the entire developer documentation. Useful if you're building your integration with Claude, Codex, Copilot, or Cursor.

Export music notation as PDF, MP3, and WAV

The three most-requested export features are now available directly from the Score Management API.

// Export as PDF
const pdfBlob = await embed.getPDF();

// Export as MP3 or WAV
const mp3Blob = await embed.getMP3();
const wavBlob = await embed.getWAV();

// Track export progress
embed.on('exportProgress', ({ progress }) => {
  console.log(`Exporting: ${Math.round(progress * 100)}%`);
});

This makes it straightforward to add download buttons or server-side export pipelines from your embedded score. See getPDF(), getMP3(), getWAV() and the exportProgress event in the docs.

Load music notation from any format

The SDK supports loading music notation from multiple formats on the fly via the Score Management API. This includes the formats you already know and several new ones:

Deeper music notation introspection

We've added a full set of methods for querying the structure of a loaded score, useful for building synchronized UIs, custom cursors, or analytics. These are available in the Score Data & Structure and Parts & Instruments sections:

Audio and video track sync

If you want to synchronize an external audio recording or video with the music notation, the Tracks API lets you do that programmatically. Use setTrack(), useTrack(), and seekTrackTo() to attach and control external media in sync with the score's playback cursor.

Playback and mixer controls

The Playback API gives you per-part volume, mute, solo, and reverb controls, useful for building interactive music notation experiences:

await embed.setMasterVolume(90);
await embed.setPartVolume(partUuid, 75);
await embed.mutePart(partUuid);
await embed.setPartSoloMode(partUuid);
await embed.setPartReverb(partUuid, 30);
await embed.setPlaybackSpeed(0.75);
await embed.setMetronomeMode(1);

See setMasterVolume(), setPartVolume(), mutePart(), setPartSoloMode(), setPartReverb(), setPlaybackSpeed(), and setMetronomeMode() in the docs.

New locales and interface options

The embed now supports 20+ locales, with 10 added in v2.6 including Danish, Finnish, Filipino, Hindi, Indonesian, Malay, Norwegian Bokmål, French Canadian, and Traditional Chinese (Hong Kong and Taiwan). Locales are set via the locale URL parameter.

The editorInterface parameter lets you explicitly set whether the embed shows the desktop or mobile editor UI, useful for responsive layouts where you want to control the experience rather than rely on auto-detection.

Accurate user tracking

By default, unique users are tracked by IP address, which means the same user accessing your site from different networks in the same month can be counted multiple times. To get accurate counts, pass your own opaque user identifier via userId:

embedParams: {
  appId: 'YOUR_APP_ID',
  userId: 'your-internal-user-id', // not an email address
}

We recommend using a non-descriptive ID from your database. We hash these identifiers internally, so no personal data is stored on our end.

What's next

We'll be posting more focused updates on specific features, starting with export (PDF, MP3, WAV) and ABC notation loading. In the meantime, the best place to start is the updated documentation. The full release history is available on the Embed changelog.

Questions or feedback? Reach out at developers@flat.io.