postMessage API

Open audiocutter.online/import/ as a popup — or embed it in an <iframe> — from your website and hand off an audio file to the editor via window.postMessage. The user lands in the editor with the file already loaded — no upload step, no roundtrip to your server.

This is the lightest integration path. You can also get the edited audio back into the same window — no server, no callback URL. If you need a pre-filled multi-fragment project, branded UI, or a server-side submit-back callback, use Hosted Sessions instead — see Which method should I use?.


Quick start

// 1. Open the import page as a popup
const popup = window.open('https://audiocutter.online/import/')

// 2. Listen for the ready signal
window.addEventListener('message', (event) => {
  if (event.data?.source === 'audiocutter' && event.data.type === 'ready') {
    // 3. Send the audio file
    popup.postMessage({
      type: 'audio',
      file: file // File object
    }, 'https://audiocutter.online')
  }
})

That's the entire contract. After the file is received, the popup stores it in IndexedDB and navigates to /, where the editor opens with the file loaded.


Message protocol

Editor → host: ready signal

Once the import page loads, it posts a single ready signal to its host — window.opener for a popup or window.parent for an iframe — with target origin *:

{ source: 'audiocutter', type: 'ready' }

Always check both event.data.source === 'audiocutter' and event.data.type === 'ready' before responding — your listener will see every postMessage the page receives.

Host → editor: audio file

Send back a single message containing the audio file:

{
  type: 'audio',
  file: File   // a File or File-like Blob from <input type="file"> or drag-and-drop
}

Always specify the target origin as 'https://audiocutter.online' on the postMessage call. Using '*' would leak the file to whatever origin happens to occupy the popup if the user navigates away mid-handshake.

Only one audio file per session. To replace it, send another message — the popup overwrites the IndexedDB entry and redirects again.

Legacy alias

For backwards compatibility, the popup also accepts { type: 'audio', audio: Blob } (the field is audio, the value is a Blob instead of a File). It is wrapped into a File named imported-audio. New integrations should use the file field with a real File object so the filename and MIME type are preserved.


Getting the edited audio back

The single-file handoff above is one-way. To receive the edited audio back in the same window — no server, no callback URL — send a session message instead of an audio message, with an output of mode: 'postmessage'. When the user clicks Submit, the editor renders the audio and posts it straight back to your host window (window.opener or window.parent):

window.addEventListener('message', (event) => {
  if (event.data?.source !== 'audiocutter') return

  if (event.data.type === 'ready') {
    popup.postMessage({
      type: 'session',
      manifest: {
        version: 2,
        project: {
          files: [{ id: 'clip', file: file }],          // File object
          fragments: [{ id: 'f1', fileId: 'clip' }],
        },
        session: {
          // Post the rendered result back here instead of to a server.
          output: { mode: 'postmessage', format: 'mp3', targetOrigin: location.origin },
        },
      },
    }, 'https://audiocutter.online')
  }

  // Arrives when the user clicks Submit in the editor.
  if (event.data.type === 'result') {
    const { audio, filename, mimeType, manifest } = event.data
    // audio is a Blob — save it, upload it, or play it.
    const url = URL.createObjectURL(audio)
  }
})

The result message has this shape:

{
  source: 'audiocutter',
  type: 'result',
  audio: Blob,        // rendered audio in the chosen format
  filename: string,   // e.g. 'session.mp3'
  extension: string,  // e.g. 'mp3'
  mimeType: string,   // e.g. 'audio/mpeg'
  manifest: object    // the edited project manifest (same schema)
}

output.targetOrigin is optional (defaults to '*') but recommended — set it to your origin so only your page can receive the audio. The full manifest shape (multiple files, fragments, volumes, fades, branding) is documented under Hosted Sessions; mode: 'postmessage' is just one of its output modes — the only one that needs no server.


Timeout

The popup waits 30 seconds for the audio message. If nothing arrives in that window, it falls back to showing the integration guide as a static page. Send the file promptly after receiving ready.


Browsers only allow window.open from a user gesture (click, keypress, etc.). Call it directly inside the event handler — do not wait for an async operation first:

// ❌ Popup blocked — async work runs first
button.addEventListener('click', async () => {
  await fetch('/api/draft')                  // gesture is lost here
  window.open('https://audiocutter.online/import/')
})

// ✅ Open synchronously, then do async work
button.addEventListener('click', () => {
  const popup = window.open('https://audiocutter.online/import/')
  fetchAndSend(popup)
})

Embed inline (iframe)

Prefer to keep the user on your page instead of opening a popup? Embed /import/ in an <iframe>. The protocol is identical — the only difference is that the editor talks to window.parent instead of window.opener. The import page detects whichever host exists, so the same messages work in both modes; you post to the frame instead of the popup:

const iframe = document.querySelector('iframe')  // src="https://audiocutter.online/import/"

window.addEventListener('message', (event) => {
  if (event.origin !== 'https://audiocutter.online') return
  if (event.data?.source !== 'audiocutter') return

  if (event.data.type === 'ready') {
    iframe.contentWindow.postMessage({
      type: 'audio',
      file: file // File object
    }, 'https://audiocutter.online')
  }

  // 'result' / 'error' arrive here exactly as in the popup flow.
})

A few things to keep in mind when embedding:


Headers on your side

Nothing special needed. Open the popup (or embed the iframe) and call postMessage over plain HTTPS — no extra headers on your site. The host reference (window.opener for a popup, window.parent for an iframe) stays available for the whole session, so the editor can message you back too.


Which method should I use?

NeedUse
Drop one audio file into the editor for the user to edit.postMessage API (this page)
Pre-fill a multi-fragment project, set volumes/fades/compression/filter.Hosted Sessions
Brand the editor with a partner logo / accent color / banner.Hosted Sessions
Receive the edited audio back in the browser, no server.postMessage API (this page)
Receive the edited audio back at a server callback URL.Hosted Sessions
AI pipeline / partner workflow with HITL refinement step.Hosted Sessions

When in doubt: if your host page stays open and can receive the result directly, the postMessage API covers the whole round-trip. Reach for hosted sessions when you need a server-side callback, a project loaded from a URL, or partner branding.


Questions?

Have a question or need help with the integration? and we’ll get back to you.