Plugins for 3.x

Updated 6 months ago

    Not to be confused with Musescore 4's VST and VSTi feature
    This chapter is for MuseScore 3 plugin developers. For other versions, visit Plugin development. To fork the main program, visit the main sections in Developers' handbook.
    For info on what plugins are, how to install and use them, visit Musescore 3 handbook plugin section.


    This chapter aims to provide knowledge, code snippets and work-arounds for better understanding and programming of MuseScore plugin system. Anyone working on plugins are welcomed to document their learnings and experiences. To add your input, register a account and login, click the ⠇ to the right of the title, choose Edit. For discussion about this chapter itself visit this forum thread.

    The desktop program MuseScore is mostly written in C++ utilizing Qt framework 5.9.9, developers expose a minimal collection of frequently used functions and data as API to allow plugin development beyond MuseScore's built-in features.


    Web devs might not need to learn QML (Windows only), use this boilerplate plus html, css and js code to create your plugin. demo plugin

    Plugins use the QML language of Qt framework, which is a declarative language that provide visual user interfaces, along with the Qt JavaScript host environment it allows interaction programming with a restricted version of javascript

    Plugin creation does not require C++ knowledge

    Capability and limitation

    Dev also often utilize the poorly documented non-API cmd().

    • Examples of basic functionality (non-exclusive list):
      • Change a note's property such as pitch, color
      • Add or remove score elements such as notes, rests, symbol, text
      • Read or save tags in File > Score Properties
      • Play the audio of a score or part of score
      • Create a new staff (Cannot change its name afterwards)
      • Create/update text and symbols eg dynamics, lyrics etc
      • Create/update tempo
      • Change playback speed (cmd('playback-speed-increase'))
      • Mute or change volume of an instrument
      • Create/update MIDI Play Event
      • Conversion of a different score format to and from MuseScore
      • Send and receive score data through internet
      • Opens a local or online webpage inside MuseScore
      • Save or load a score or any file
      • Start another program on your Windows/iOS outside MuseScore
    • Seems unachievable ( Please share if you find workaround, for example a suitable cmd() command )

    Alternatives to plugin

    Where to begin

    MuseScore Plugin writing is not rocket science, you may be suprised how easily things are done. You do not need to install anything additional, just open Musescore:

    Workflow and external editors

    Try out Makeshift REPL plugin function tester plugin.

    QML files are plaintext. You can use any external text editor, eg Sublime Text, Notepad++ etc, to edit a .qml file. After you modified and saved, you need to either:

    • Load (and reload) it inside Plugin Creator then press Run, or
    • Restart Musescore and run from the plugin menu.

    NOTE: Script running from plugin menu has its version freezed at the moment of Musescore startup.

    Hot reloading (auto build) and auto-complete are absent in Plugin Creator. The developers of Musescore 4 are aware of its flaws and plan to replace it in later releases. While waiting for upgrades, to edit in external editor and reload and test in Plugin Creator:

    • Inside the Plugin Creator, open an existing .qml file
    • In the external text editor, edit the .qml file and save
    • Press refresh in the Plugin Creator
    • Press run

    The best options for auto complete (QML syntax only, not auto reference or API auto complete)

    Quickstart boilerplates, snippets and use cases

    This section gathers reusable code snippets and boilerplates to help beginners get things done without a hassle. To alleviate QML frustration see QML boilerplates. Copy and paste to your plugin, tweak it to your liking. Also check out specific use cases and notes. Feel free to add your clever codes.

    Learn more

    Useful Resource

    Source code

    MuseScore 3.6.2 Backend mainly under /libmscore
    API 3.5 (for Musescore 3.6) under /mscore/plugin/api
    * An online code search enabled clone of MuseScore 3.6.2 src (Online code search on the official repo always returns results based on current master src ie MuseScore 4 up-to-date version)
    * An essential collection is also shown on the doxygen website.

    Latest MuseScore 4 code:
    MuseScore 4 Backend is rewritten and separated into two layers, under /src/engraving/libmscore and various /*/internal
    API (3.5, not yet updated for MuseScore4, as of Nov2022) under /src/plugins/api
    * Official src

    Enumerations and element types


    Also try log type enum string snippet and Makeshift REPL plugin function tester plugin for enum and keyword autocompletion.

    Namespace/enum list
    Base Class/Component

    All elements has a .name property to provide understandable info of its type.
    To match and compare reliably, use .type property. It is Enum, it uses a integer number internally. These enums can be referenced from various properties of the Base Class/Component
    eg  Accidental.FLAT

    eg how-to  Element.NOTE
    find NOTE under ElementType in the Namespace/enum list,
    use Element because Base Class/Component says Element Contains Ms::ElementType enumeration values.

    Plugin API doxygen documentation

    The Plugin API Documentation is automatically generated (in Doxygen format) whenever MuseScore developers build the main program. It is normal for beginners to be startled by its complexity.Use the search on the top right, instead of menu navigation.
    Notes on API written by fellow users, feel free to pitch in
    List of all API object types

    To build UI

    1. Use the QML

    Also see QML boilerplates
    Note: search sometimes returns an unexpected outdated page, eg QtQuick 1 Button instead of current QtQuick 2 Button.
    Qt Quick Controls, the anchors and Qt Quick Layouts may suffice. Using Qt Widgets from QML may be overkill not worth your time.
    List of all QML components for Qt 5.9
    Customizing Qt Quick Controls 2 Please note that style are unsupported though.
    Anchors enum
    Keys enum list eg Qt.Key_Space
    Mouse button enum list eg Qt.LeftButton, more on mouse see this notes
    QtQuick Type properties for disabled, qmlssed, checked, checkable, focused, highlighted, flat, mirrored, hovered etc.
    Settings{ } for persistence (save to OS, eg registry in windows)
    Get the theme status with  SystemPalette { } users' notes on QML and snippets


    2. Use a WebEngine plus html, css and javascript

    Windows only, see QML notes

    Use the two boilerplates, which utilize a hybrid view built with html, css and standard javascript thru a 100% width and height WebEngine.
    Standard set of javascript is used, for tech compatibility check on (find Chrome v56), eg css display:grid is unsupported. This js set should not be confused with the other restricted set in QML functions, more info in Caution section

    The following javascript inside WebEngine works:

    • Arrow function
    • template-literals ie `string${var}`
    • DOMParser().parseFromString("html")

    The following css works:

    • Flex

    The following css will not work:

    • Gap
    • Grid

    Visit WebEngine community notes

    Technical info on WebEngineView, WebChannel, WebView:
    WebEngineView fetches url, search data on html and runs javascript from QML side only, its version in MuseScore 3 (Qt 5.9) is based on Chromium version 56.0.2924.122.
    To communicate bidirectionally between QML and webpage use it with WebChannel.
    WebView 1.1 is an older component and use a different engine which does not offer simple WebChannel support, try WebSocket.

    Bundled resource

    A list of every qrc:/// built-in musescore.qrc (src ref)
    Icons, symbols and fonts (not soundfont) see this snippet
    MuseScore dev team designs and uses its own two sets of styles, their details are not exposed as API yet, find them in github repo (then plz share link here).

    import QML Module Versions

    Musescore 3.6.2 use Qt 5.9.9, for latest version of common modules use:

    import MuseScore 3.0
    import QtQuick 2.9
    import QtQuick.Controls 2.2
    import QtQuick.Layouts 1.2
    import QtQuick.Dialogs 1.2
    import Qt.labs.settings 1.0
    import FileIO 3.0
    import QtWebEngine 1.5 // web modules are Windows only
    import QtWebChannel 1.0 // web modules are Windows only

    The powerful non API method

    Developers of MuseScore do not have resource to maintain and expose every function and data as API, some functionalities of Musescore the main program are yet to be available as plugin API.
    Try out cmd() to run program sequence that you've seen in musescore and think may exist as coroutine. Actions that can be assigned to keyboard shortcuts are possible cmd(). These commands are poorly documented, and often cause prog crash (save your qml before Run). Study main C++ repo to understand more.


    Don't reinvent the wheel

    • Search plugins on, someone may have already made one in Musescore 2 or Musescore 1(Change search filter to find them), remember you can always try to use an old version of MuseScore.
    • Search plugins on github
    • Study their source code, sometimes all you need to do is a few tweak.
    • Seek help from the author via a comment under the repo or ask in the plugins forum.
    • Try Element Analyser plugin which aims to provide a reusable library

    API inheritance versus Score Structure

    Beginners into programming may get confused with API Class Inheritance Hierarchy and Musescore runtime internal score structure hierarchy, read up on inheritance object oriented programming, also try out the debugger

    Javascript issues

    A different non-QML javascript API was used in MuseScore 1.x. While one can still learn a lot reading those files, they use the old API and will not work with current one. One way to spot the old API is presence of new Cursor(curScore) . The current QML system use curScore.newCursor()

    The QML functions use a restricted version of javascript, the following will not work:

    • Arrow function
    • Spread syntax
    • Array.fill

    To write modular codes, QML has import .js

    Inside QML WebEngine, a different, standard version of javascript runs on outdated Chromium v56 engine, more info in UI section

    Class/Object inheritance, composition and .prototype

    You cannot edit class/object as you would with .prototype in javascript, see component creation if it suits your need.
    Object.assign() (and spread function) also does not work, as opposed to stated on Qt webpage. This probably happens when Qt company add dynamically typed javascript scripting to the strong typed C++ based env. Instead create your own shallow copy with a for loop and then some spaghetti code.

    QML list and javascript array

    QML property declaration:

    A list can only store QML objects:

    Item {
        property list aList: [ ]
        aList2: [ ] //shorthand of above

    A list is an object: typeof list == 'object'

    An array is a variant:

    Item {
        property var anArray: [ ]

    inside QML functions:
    same syntax as in standard javascript

    Item {    
        function a(){
            var anArray=[ ]

    UI Styles

    Qt Quick Controls style eg import QtQuick.Controls.Material unsupported, see reasons
    MuseScore dev team designs and uses its own two sets of styles, get the theme status with QML  SystemPalette , see source post. Their color and metric details are not exposed as API yet, find them in github repo (then plz share link here).
    Above concerns UI component styles, not engraving style

    The Plugin Base Component Musescore { }

    • Component.onCompleted
      Run once, right after the plugin component is created, before console.log() is functional
    • You should not use Qt.quit() in your plugins, see this post on why, and possible different approaches. Qt.quit() crashes Musescore 4.0 plugins.
    • Set pluginType: "dock" for normal behavior eg stay on top; "dialog" is quite outdated.
    • Create plugin as an action instead of a persistent object with prop and methods, because when the user close and reopen the plugin window, it may cause unwanted behavior.
      • This post explains the nature of onRun() and Qt.quit(). The code Qt.quit() may not work the way you expect.
      • The plugin window onClosing Event is not accessable from QML. The [Plugin API base] is in a QQuickView in a QWidget window docked inside a QDockWidget , see code.
      • No way to detect plugin's open or closed.
      • After plugin window is closed, listeners will continue to run, eg experimental onScoreStateChanged Handler
      • Workaround palette-like plugin
      • use Qt Labs Settings to save data across sessions
      • other tips also check out the snippets and notes page

    Placement of objects, cursor track and tick

    cursor.rewindToTick(x) will only work correctly if there is a segment at x. Otherwise it will put the cursor at the next available segment (in the current track) after x, see

    Troubleshooting with help from community

    If you are having difficulty, try

    • Identify whether the problem is related to QML, or javascript, or the MuseScore plugin API. If it is QML or javascript, you can seek help from sites like stackoverflow and in addition to
    • Use google and the forum search before posting new questions.

    • Ask politely in the plugins forum, provide a Minimal, Reproducible Example if possible, the community is usually more than happy to help.

    • Enclose qml codes between <qml> and </qml> to get better layout and to avoid auto escaping eg to show & instead of &amp;
    • Come back and help others by adding your valuable discovery to this handbook.


    see Internationalization
    one solution to folder structure

    Share your plugin

    Plugin could be posted as a project on without any github knowledge. Chat with other dev at the plugin forum.
    Fill out the API compatibility 3.x or else your plugin with remain hidden to most users.


    Following is not written by a lawyer, consult a real one if you are concerned with licensing.
    You do not need Qt licensing, as it does not affect QML scripts solely on the basis that they are written in the QML language per se, more info consult Qt dual licensing.
    You do not need to follow MuseScore's GPL licensing as long as your plugin does not use MuseScore code base. MuseScore 3 use GPL which is copyleft, derivative work using MuseScore code base, once conveyed, must follow. This matter is debatable.


    API 3.5 thanks to
    and many others

    Reference footnote

    import API FileIO module version
    import module version at Qt
    import module version at wikipedia
    import WebChannel module version