A free, open source app to control Ableton Live from any device on your local network via a browser.
- 🎵 Setlist from cue points — automatically parses Ableton locators into a setlist
- 🎛️ Web control — open on any phone, tablet, or computer on the same WiFi
▶️ Transport — play, stop, continue, next/prev cue- 🔀 Song jumping — tap any song to jump to it in Ableton
- 📋 Sections — expand songs to see and jump to sub-sections
- 🛑 Song end markers —
[STOP]ends the song, stops playback, and parks the playhead on the next song so Play starts it; the previous section runs up to that marker - 🔁 Section loops — use the loop button or add
+LOOP/+LOOPFULLto a section cue; LiveControl draws and enables Ableton's own loop brackets - 🎤 Performance mode — a large, second-device-friendly now-playing view with shared loop feedback
- 🎤 Synchronized lyrics — a separate
/lyricspage that follows the playhead (see below) - 🎨 Song colors — color-code your setlist
- 📝 Song notes — add notes, chords, or instructions per song
↕️ Reorder — drag setlist songs with a mouse or touch; order survives reloads, including duplicate titles- 🔇 Track mute/solo — control any track from the Tracks tab
- ⌨️ Keyboard shortcuts — Space (play/stop), ←→ (prev/next cue)
- 📷 QR device syncing — scan a QR code (QR button in the header, or the Mac app's menu bar) to open LiveControl on a phone or tablet
- 📱 Fully responsive — works great on iPhone, iPad, and desktop
Open LiveControl.app to run LiveControl from the menu bar. Click the LC menu bar icon to see that LiveControl is running, scan the QR code to open it on a phone or tablet on your Wi-Fi, or copy the phone / tablet and local URLs. The gear in that panel lets you show/hide the LiveControl window or quit. The app starts and stops its local Ableton bridge automatically. Setlist notes, colors, and ordering are stored in ~/Library/Application Support/LiveControl.
The app bundle includes Node.js and all server dependencies. You do not need to use Terminal or install Node.js. Ableton Live must have the AbletonJS control surface enabled under Settings → Link, Tempo & MIDI → Control Surface. The Remote Script is bundled inside the app at Contents/Resources/LiveControl/node_modules/ableton-js/midi-script; copy its AbletonJS folder into Ableton's User Library/Remote Scripts folder if it is not already installed, then restart Live.
To rebuild the Mac app from this source project, run npm install and npm run build:app.
Copy the MIDI script into Ableton's Remote Scripts folder:
macOS:
cp -r node_modules/ableton-js/midi-script ~/Music/Ableton/User\ Library/Remote\ Scripts/AbletonJSWindows:
Copy node_modules\ableton-js\midi-script to:
C:\Users\[YourName]\Documents\Ableton\User Library\Remote Scripts\AbletonJS
- Open Ableton Live
- Go to Preferences → Link, Tempo & MIDI
- Under Control Surfaces, add AbletonJS as a control surface
- No input/output assignment needed
npm install
npm start- This machine: http://localhost:3000
- Other devices: http://[your-ip]:3000
The server prints your local IP on startup.
LiveControl reads cue point names from your Ableton arrangement view:
| Cue point name | Effect |
|---|---|
Song Title |
Creates a song entry |
[Song Title] |
Creates a song entry (bracket notation) |
> Verse |
Section within the current song |
> Chorus +LOOP |
Loops from this section cue to the next cue |
> Chorus +LOOPFULL |
Marks a full section loop |
> Chorus |
Another section |
[NEXTMARKER] |
Real starting point of the song — jumping to the song jumps here instead, skipping lead-in silence |
[STOP] or --- STOP --- |
End of the song; playback stops at this marker |
// comment |
Ignored |
Example arrangement:
1.1.1 Intro
3.1.1 [NEXTMARKER] ← song actually starts here; jumping skips the lead-in
33.1.1 > Verse 1
65.1.1 > Chorus +LOOP
97.1.1 [STOP]
97.1.1 Second Song
97.1.1 > Drop
161.1.1 [STOP]
Ableton reports locator and playhead positions in beats. LiveControl converts them to minutes and seconds using the current tempo.
After editing cue points in Ableton, click the ↺ button in LiveControl to reload.
Open Lyrics in the header (or go to http://[your-ip]:3000/lyrics on any device). Create a MIDI track named Vocals +LYRICS with one clip per lyric line; the clip name is the text and its start/end define when the line is active. Press ↺ after editing clips.
- Lines, section headers (from
>cues /+SECTIONSclips) and the song title scroll with playback; long gaps show a 4-dot countdown. - Tap a line to jump there, a section header to jump to the section, the title to jump to the song. The lock button disables taps.
- Several
+LYRICStracks: pick one from the selector (remembered per device), or open/lyrics?track=Lead%20Vocals. - Track-name flags:
[blue](any AbleSet colour)[large|small|tiny][left|center][mono][nofade][nozoom][nosections][linemarker][progress][top]/[top+2][+150ms]/[-200ms]/[+1n](delay, only while playing)+CLIPCOLORS/+CC - Line attributes at the start of a clip name:
[blue],[large],[left],[mono],[<]/[>](force a line before/after a section header the clip crosses). Use**bold**,*italic*, and\for a line break within one clip. - Not yet supported: ChordPro chords/transposition, images,
[allsongs].
Tests: npm test.
All endpoints return { ok: true, ... } or { ok: false, error: "..." }.
| Method | Path | Body | Description |
|---|---|---|---|
| POST | /api/play |
— | Start playback |
| POST | /api/stop |
— | Stop playback |
| GET | /api/connect |
— | LAN addresses other devices can use |
| GET | /api/connect/qr.svg?i=0 |
— | QR code (SVG) for a LAN address |
| POST | /api/continue |
— | Continue from current position |
| POST | /api/next-cue |
— | Jump to next cue point |
| POST | /api/prev-cue |
— | Jump to previous cue point |
| POST | /api/tempo |
{ bpm: 120 } |
Set tempo |
| Method | Path | Body | Description |
|---|---|---|---|
| GET | /api/state |
— | Full current state |
| POST | /api/reload |
— | Re-read cue points from Ableton |
| POST | /api/jump/song/:id |
— | Jump to song |
| POST | /api/jump/section/:songId/:sectionId |
— | Jump to section |
| POST | /api/jump/time |
{ beat: 32 } |
Move the playhead to a beat position (used by lyrics taps) |
| POST | /api/loop |
{ songId, sectionId } or { active: false } |
Enable or clear the shared loop |
| POST | /api/setlist/reorder |
{ order: [id, ...] } |
Reorder songs |
| Method | Path | Body | Description |
|---|---|---|---|
| POST | /api/song/:id/notes |
{ notes: "..." } |
Save notes |
| POST | /api/song/:id/color |
{ color: "red" } |
Set color |
| POST | /api/song/:id/exclude |
{ excluded: true } |
Skip song in setlist |
Set the PORT environment variable to change the port (default: 3000):
PORT=8080 npm startAbleton Live
↕ UDP (localhost only)
ableton-js MIDI script
↕
Node.js server (server.js)
├── Express HTTP → serves static files + REST API
└── WebSocket → real-time state push (`state`) and lyrics (`lyrics`, sent on connect/reload)
Browser (any device on local network)
├── Fetches UI from http://[server-ip]:3000
└── WebSocket connection for live updates
ableton-js— Ableton Live bridge (MIT)express— HTTP serverws— WebSocket server- Vanilla HTML/CSS/JS frontend (no build step)