Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
holoviz
GitHub Repository: holoviz/panel
Path: blob/main/doc/how_to/desktop_or_mobile/pywebview.md
3390 views

Create Desktop Apps with pywebview

Convert Panel applications into standalone desktop executables using pywebview and package them for distribution.

Install Dependencies

pip install panel pywebview pyinstaller

:::{note} Linux requires additional GTK dependencies. See pywebview installation guide. :::

Create Your Panel Application

We'll build a simple Panel application with optional exit functionality:

  • a slider to choose a number

  • a corresponding row of ⭐ characters

  • an Exit button that terminates the desktop application

The full implementation of this Panel app (via a create_app() function) is shown in the complete app.py example in the next section.

Wrap with pywebview

Create app.py to wrap your Panel application:

import webview import panel as pn import threading import time import os import socket class PanelDesktop: """Serve Panel apps as desktop applications using webview.""" def __init__(self, title="Panel Desktop App", width: int=600, height: int=600): self.title = title self.width = width self.height = height @staticmethod def _find_free_port(): """Find a free port on localhost.""" with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind(('', 0)) s.listen(1) port = s.getsockname()[1] return port def serve(self, func_or_path, port: int=0): """Serve a Panel function or file in a desktop window.""" if not port: port = self._find_free_port() # Start Panel server in daemon thread server_thread = threading.Thread( target=lambda: pn.serve(func_or_path, port=port, show=False, autoreload=False), daemon=True ) server_thread.start() # Create and start webview webview.create_window( self.title, f'http://localhost:{port}', resizable=True, fullscreen=False, width=self.width, height=self.height, text_select=True) webview.start() def create_app(): """Example Panel app with exit functionality.""" pn.extension(design="material") pn.pane.Markdown.disable_anchors = True slider = pn.widgets.IntSlider(value=3, start=1, end=5) stars = pn.bind(lambda n: "⭐" * n, slider) def exit_app(event): """Exit the desktop application.""" os._exit(0) # an alternative way: # import webview # webview.windows[0].destroy() exit_btn = pn.widgets.Button(name="Exit", on_click=exit_app, button_type="primary") return pn.Column( "# Desktop Panel Application", "This is a Panel app running in a native window!", slider, stars, exit_btn ) if __name__ == "__main__": desktop = PanelDesktop("My Panel App") desktop.serve(create_app)

:::{note} You can serve an external file instead of a function:

desktop.serve("my_panel_app.py")

:::

Test the Application

Run:

python app.py

The app should look like:

Panel Desktop PyWebView

Verify all functionality works before packaging.

Package for Distribution

Packaging frameworks by desktop platform:

See the pywebview freezing guide for complete platform-specific instructions.

Package for Windows

Build with PyInstaller:

pyinstaller app.py

The executable will be in the dist folder.

Options:

  • --debug all - Enable debugging

  • --icon=favicon.ico - Add custom icon (download Panel icon)

  • --noconsole - Hide console window

  • --onefile - Create single executable (makes the loading of the application slow)

Package for MacOS

On OSX you will need py2app instead of pyinstaller. Begin by generating a setup.py for your application with

py2applet --make-setup app.py

Next build it with:

python setup.py py2app

:::note py2app bundles your local environment, since conda uses features not supported in a packaged application you cannot use a conda environment as your build environment. :::

Troubleshooting

Blank window or errors:

  • Add hidden imports: --hidden-import=panel --hidden-import=bokeh

  • Run without --noconsole to see error messages

Create installer for Windows

For professional distribution, create an installer using InstallForge, NSIS, or Inno Setup.

Alternative: Distribute as UV Tool

A simple alternative to PyInstaller, would be to distribute the app as a uv tool.