Customizing your plugin’s listing on napari hub#
Once your plugin is published to PyPI with the Framework :: napari classifier, it will automatically appear on the napari hub. This guide explains how to customize your plugin’s listing to provide the best experience for potential users.
Overview#
The napari hub displays information about your plugin from three main sources:
PyPI - Core package metadata from your
pyproject.tomlREADME - As defined in your
pyproject.toml, serves as the description on your plugin’s detail page.npe2 manifest - Plugin-specific metadata from your
napari.yamlfile
By understanding how these sources work together, you can ensure your plugin appears with accurate, appealing information on the hub.
Setting package metadata in pyproject.toml#
Most of the information displayed on the napari hub comes from your Python package metadata. The napari hub reads this information from PyPI’s JSON API after you publish your package.
Essential fields#
These fields appear prominently on your plugin’s listing and in search results:
Name#
The package name as it appears on PyPI. This is what users will use to install your plugin.
[project]
name = "napari-example-plugin"
Summary#
A one-line description of your plugin. Keep it concise and descriptive - it appears in plugin listings and search results.
[project]
description = "A plugin for advanced image segmentation using deep learning"
Version#
The current version of your plugin. We strongly recommend using Semantic Versioning (SemVer) or Intended Effort Versioning (EffVer) with Python conventions for pre-releases (PEP 440).
[project]
version = "0.1.0"
Tip
If you’re using dynamic versioning tools like setuptools-scm or hatch-vcs, you can specify:
[project]
dynamic = ["version"]
License#
The license under which your plugin is distributed. Use a valid SPDX identifier or the string "Other". Modern Python packaging uses the license-expression format for specifying licenses.
[project]
license = "BSD-3-Clause"
license-files = ["LICENSE"]
Note
Previously, the valid way to specify license information used the license table with file or text keys and a license trove classifier. This still works for listings on the napari-hub, but is deprecated in favor of license-expression.
[project]
license = {text = "BSD-3-Clause"}
Classifiers#
PyPI Trove classifiers provide structured metadata about your plugin. The Framework :: napari classifier is required for hub visibility.
[project]
classifiers = [
"Development Status :: 4 - Beta",
"Framework :: napari",
"Intended Audience :: Science/Research",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Scientific/Engineering :: Image Processing",
]
Python version requirements#
Additionally, specify the Python versions your plugin supports. If you specify ">=3.10", the hub will tag your plugin as supporting Python 3.10, 3.11, 3.12, etc.
[project]
requires-python = ">=3.10"
Dependencies#
List your plugin’s dependencies. The hub displays these on the detail page.
[project]
dependencies = [
"numpy>=1.21",
"scikit-image>=0.19",
"torch>=2.0",
"qtpy",
]
Warning
Never include Qt backends (PyQt5, PyQt6, PySide2, PySide6) or napari[all] in your base dependencies! See Don’t include napari[all], PySide6, PyQt5 or PyQt6 in your plugin’s default dependencies. for details.
Project URLs#
It is best practice to specify the following URLs in your pyproject.toml file:
[project.urls]
Homepage = "https://github.com/username/napari-example-plugin"
Documentation = "https://napari-example-plugin.readthedocs.io"
"Source Code" = "https://github.com/username/napari-example-plugin"
"Bug Tracker" = "https://github.com/username/napari-example-plugin/issues"
"User Support" = "https://forum.image.sc/tag/napari"
The hub displays your project’s PyPI link (not specified here, created when you publish your package),
and your project’s GitHub link on your plugin details page. The GitHub link will be parsed from
your Homepage or Source Code links under [project.urls], so you can update your Homepage
to a dedicated website if you have one.
Complete example#
Here’s a complete example of a well-configured pyproject.toml:
[project]
name = "napari-example-plugin"
version = "0.1.0"
description = "Advanced image segmentation using deep learning"
readme = "README.md"
license = "BSD-3-Clause"
license-files = ["LICENSE"]
requires-python = ">=3.10"
authors = [
{name = "Jane Doe", email = "jane@example.com"},
]
classifiers = [
"Development Status :: 4 - Beta",
"Framework :: napari",
"Intended Audience :: Science/Research",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Scientific/Engineering :: Image Processing",
]
dependencies = [
"numpy>=1.21",
"scikit-image>=0.19",
"magicgui>=0.8.0",
]
[project.urls]
Homepage = "https://github.com/username/napari-example-plugin"
Documentation = "https://napari-example-plugin.readthedocs.io"
"Bug Tracker" = "https://github.com/username/napari-example-plugin/issues"
"User Support" = "https://forum.image.sc/tag/napari"
[project.entry-points."napari.manifest"]
napari-example-plugin = "napari_example_plugin:napari.yaml"
Plugin Hub Description with README.md#
A detailed description of your plugin. This appears on the plugin’s detail page and is indexed for search. Use your README.md file:
[project]
readme = "README.md"
The hub will render your README with proper Markdown formatting. If you begin with a Level 1 heading, it will be treated as a title and removed from the description.
Writing a quality Readme#
Clear summary: Start with who the plugin is for, what data it works with, and what problems it solves
Quick start example: Include images, GIFs, or videos showing the plugin in action
Relevant keywords: Mention key terms users might search for (e.g., “segmentation”, “3D”, “time series”)
Section headings: Use Level 2 headings (
##) to organize content - these create navigation links in the sidebar
Including images and media#
There are a few ways to include images and other media in your description, but these assets need to be hosted somewhere and accessible via an absolute URL. In other words, relative paths to images in your repository will not work. Images should use the markdown format . Consider how an image located on the main branch at ./resources/image.png in your repository could be hosted:
The raw path to the image, identified with
raw.githubusercontent.com. e.g.. On Github, you can open the image in the repo, open the image in a new tab and copy the address bar url.The raw blob path to the image, with
?raw=trueappended. e.g.. On Github, you can open the image in the repo and right-click the image to copy the link address.The raw path to any image or asset on Github or on any other site, including your own static documentation.
npe2 manifest metadata#
Your plugin’s npe2 manifest (napari.yaml) provides napari-specific metadata that appears on the hub.
Display name#
The display_name, and not the name, appears in plugin listings and the napari plugin manager:
name: napari-example-plugin
display_name: Example Segmentation Plugin
Plugin type indicators#
The hub automatically detects your plugin’s capabilities from your manifest contributions and displays them as Plugin types:
Reader plugins: Detected from
contributions.readersWriter plugins: Detected from
contributions.writersWidget plugins: Detected from
contributions.widgetsSample data: Detected from
contributions.sample_data
Reader and writer file extensions#
The hub displays supported file extensions for readers and writers:
contributions:
readers:
- command: napari-example-plugin.read_tiff
filename_patterns: ["*.tif", "*.tiff"]
- command: napari-example-plugin.read_custom
filename_patterns: ["*.custom"]
writers:
- command: napari-example-plugin.write_tiff
filename_patterns: ["*.tif"]
layer_types: ["image", "labels"]
Visibility control#
Control whether your plugin appears in hub search and listings, and in the napari plugin manager:
name: napari-example-plugin
visibility: public # or "hidden"
public(default): Plugin appears in search and listingshidden: Detail page is accessible via direct link, but plugin doesn’t appear in search. Remains installable via napari plugin manager.
Troubleshooting#
Removing your plugin from napari and the hub#
To completely hide your plugin from all napari-related APIs, workflows and listings, remove the Framework :: napari classifier from your pyproject.toml:
[project]
classifiers = [
# "Framework :: napari", # Remove or comment out this line
"Programming Language :: Python :: 3",
# ... other classifiers
]
Important
You must release a new version for this change to take effect.
After removing the classifier:
Your plugin will still work when manually installed (e.g.
pip install your-plugin)It won’t appear in the napari plugin manager
It won’t appear on the napari hub
It won’t be automatically discovered by napari metadata tools
My changes aren’t showing up on the hub#
The napari hub updates plugin information periodically. After publishing a new version to PyPI:
Wait up to 4 hours for the hub to refresh
Clear your browser cache
Check that your new version appears on PyPI
My plugin doesn’t appear on the hub at all#
Check that:
Your package is published to PyPI
You included the
Framework :: napariclassifierYour plugin’s
visibilityis not set tohidden(or is set topublic)Your package has a valid npe2 manifest (
napari.yaml) with anapari.manifestentry point