Skip to main content
UI plugins allow you to add custom interface elements to Binary Ninja, including sidebar panels, global areas, custom views, and menu actions.
UI plugins require Qt 6.8.2 and are only supported in the GUI edition of Binary Ninja.

UI plugin types

Sidebar widgets

Add panels to the left/right sidebar (like Symbols, Cross References)

Global areas

Add bottom panels (like Log, Console, Scripting)

Pane widgets

Add new main view types (like Graph, Linear, Hex)

Context menus

Add right-click menu actions

Building UI plugins

UI plugins require Qt and must be compiled with the correct Qt version:
cmake -S . -B build -DBN_API_BUILD_EXAMPLES=ON
cmake --build build -j8
Binary Ninja uses a custom Qt 6.8.2 build. Use the official build configuration or the official Qt installer.

Example: Triage plugin

The Triage plugin is a complete UI plugin that demonstrates all major features:
triage.cpp
#include "binaryninjaapi.h"
#include "ui/uicontext.h"
#include <QWidget>
#include <QVBoxLayout>
#include <QTableWidget>

using namespace BinaryNinja;
using namespace UIContext;

class TriageView : public QWidget, public ViewInterface {
    Q_OBJECT

private:
    ViewFrame* m_viewFrame;
    BinaryViewRef m_data;
    QTableWidget* m_table;

public:
    TriageView(QWidget* parent, BinaryViewRef data) : QWidget(parent) {
        m_data = data;

        QVBoxLayout* layout = new QVBoxLayout();
        layout->setContentsMargins(0, 0, 0, 0);

        // Create table
        m_table = new QTableWidget();
        m_table->setColumnCount(3);
        m_table->setHorizontalHeaderLabels({"Address", "Type", "Name"});

        // Populate with functions
        auto functions = data->GetAnalysisFunctionList();
        m_table->setRowCount(functions.size());

        for (size_t i = 0; i < functions.size(); i++) {
            auto func = functions[i];
            m_table->setItem(i, 0, 
                new QTableWidgetItem(QString::number(func->GetStart(), 16)));
            m_table->setItem(i, 1, 
                new QTableWidgetItem("Function"));
            m_table->setItem(i, 2, 
                new QTableWidgetItem(QString::fromStdString(
                    func->GetSymbol()->GetFullName())));
        }

        layout->addWidget(m_table);
        setLayout(layout);
    }

    virtual BinaryViewRef getData() override { return m_data; }
    virtual uint64_t getCurrentOffset() override { return 0; }
    virtual void setCurrentOffset(uint64_t offset) override {}
};

class TriageViewType : public ViewType {
public:
    TriageViewType() : ViewType("Triage", "Triage View") {}

    virtual ViewInterface* create(BinaryViewRef data, ViewFrame* frame) override {
        return new TriageView(frame, data);
    }
};

extern "C" {
    BN_DECLARE_CORE_ABI_VERSION
    BINARYNINJAPLUGIN void UIPluginInit() {
        ViewType::registerType(new TriageViewType());
    }
}
From examples/triage/
UI plugins use UIPluginInit() instead of CorePluginInit().

Creating sidebar widgets

Sidebar widgets appear in the left or right sidebar:
hello_sidebar.py
from binaryninjaui import SidebarWidget, SidebarWidgetType, Sidebar
from PySide6.QtWidgets import QWidget, QVBoxLayout, QLabel

class MySidebarWidget(SidebarWidget):
    def __init__(self, name, frame, data):
        SidebarWidget.__init__(self, name)
        self.data = data

        # Create UI
        container = QWidget()
        layout = QVBoxLayout()

        self.label = QLabel(f"Binary: {data.file.filename}")
        layout.addWidget(self.label)

        container.setLayout(layout)
        self.setWidget(container)

class MySidebarWidgetType(SidebarWidgetType):
    def __init__(self):
        icon = QImage(16, 16, QImage.Format_RGB32)
        icon.fill(0)

        SidebarWidgetType.__init__(self, icon, "My Sidebar")

    def createWidget(self, frame, data):
        return MySidebarWidget("My Sidebar", frame, data)

# Register the sidebar
Sidebar.addSidebarWidgetType(MySidebarWidgetType())
From python/examples/hellosidebar.py

Creating global areas

Global areas appear at the bottom (like Log, Console):
hello_globalarea.py
from binaryninjaui import GlobalArea, GlobalAreaWidget
from PySide6.QtWidgets import QWidget, QVBoxLayout, QTextEdit

class MyGlobalArea(GlobalAreaWidget):
    def __init__(self, name):
        GlobalAreaWidget.__init__(self, name)

        # Create UI
        container = QWidget()
        layout = QVBoxLayout()

        self.text = QTextEdit()
        self.text.setReadOnly(True)
        self.text.setText("Custom global area content")

        layout.addWidget(self.text)
        container.setLayout(layout)
        self.setWidget(container)

# Register the global area
my_area = MyGlobalArea("My Area")
GlobalArea.addWidget("My Area", my_area)
From python/examples/helloglobalarea.py

Adding menu actions

Add items to context menus:
from binaryninjaui import UIAction, UIActionHandler, Menu

def my_action(context):
    print(f"Action triggered for {context.binaryView.file.filename}")

# Register action
UIAction.registerAction("My Plugin\\My Action")
UIActionHandler.globalActions().bindAction(
    "My Plugin\\My Action",
    UIAction(my_action)
)

# Add to menu
Menu.mainMenu("Plugins").addAction("My Plugin\\My Action", "My Group")

Custom notifications

Receive UI notifications:
from binaryninjaui import UIContext

class MyUINotification:
    def OnViewChange(self, context, frame, type):
        print(f"View changed to {type}")

    def OnAddressChange(self, context, frame, view, location):
        print(f"Address changed to {hex(location.getOffset())}")

# Register notification
notification = MyUINotification()
UIContext.registerNotification(notification)
From python/examples/ui_notification_callbacks.py

Settings and preferences

UI plugins can add settings to preferences:
from binaryninja import Settings
from binaryninjaui import SettingsUIGroup

# Register setting
Settings().register_group("myplugin", "My Plugin")
Settings().register_setting(
    "myplugin.show_details",
    '''{
        "title": "Show Details",
        "type": "boolean",
        "default": true,
        "description": "Show detailed information"
    }'''
)

# Create UI for settings (optional)
group = SettingsUIGroup()
group.addBoolSetting("myplugin.show_details", "Show Details")

Theming and styling

UI plugins should respect the user’s theme:
from binaryninjaui import getThemeColor

# Get theme colors
bg_color = getThemeColor(ThemeColor.BackgroundColor)
fg_color = getThemeColor(ThemeColor.ForegroundColor)
highlight_color = getThemeColor(ThemeColor.HighlightColor)

# Apply to widget
widget.setStyleSheet(f"""
    QWidget {{
        background-color: {bg_color.name()};
        color: {fg_color.name()};
    }}
""")

Best practices

Never block the UI thread with long operations:
from binaryninja import BackgroundTaskThread

class AnalysisTask(BackgroundTaskThread):
    def __init__(self, widget):
        BackgroundTaskThread.__init__(self, "Analyzing", True)
        self.widget = widget

    def run(self):
        # Long operation
        result = perform_analysis()

        # Update UI in main thread
        execute_on_main_thread(lambda: self.widget.update(result))

task = AnalysisTask(my_widget)
task.start()
Override __del__ or closeEvent to clean up:
def __del__(self):
    # Unregister notifications
    UIContext.unregisterNotification(self.notification)

    # Cancel background tasks
    if self.task:
        self.task.cancel()
Update your UI when the view changes:
def OnViewChange(self, context, frame, type):
    if self.frame == frame:
        self.updateContent()

Example plugins

Next steps

Workflow plugins

Modify analysis pipeline

Architecture plugins

Add CPU architecture support

Build docs developers (and LLMs) love