Publishing in the Store
How to list your Kimai plugin, app or client in the Marketplace
If you built a plugin, mobile app, desktop client, or another integration around Kimai and want it listed in the Store or Apps & Integrations page, this guide explains the current repository structure.
Due to the multi-lingual structure of the website, its not enough to add just one store entry but it needs a few files:
- developer metadata
- product metadata
- one shared content partial (for all language versions)
- one wrapper page per store locale (you only need to create the
en/version) - translated title and intro texts (again, you only need
en/but more are always better) - optional screenshots, compatibility data, and changelog files
If you follow the steps below and keep the same slug everywhere, the structure becomes straightforward.
Before you start
Pick two identifiers first:
Developer ID- your company or personal ID in_data/developer.ymlSlug- the Store item ID used in filenames, translation keys, and data files
Example:
- Developer ID:
acme - Slug:
acme-foo(should always include your developer ID as prefix) - In case its a Plugin, the bundle class:
FooBundle
Use the slug consistently in every place. Filename, translation key, include name, and store data file must match.
What a Store entry consists of
For a typical plugin entry, you will usually touch these files:
_data/developer.yml_data/store/acme-foo.yml_includes/store/acme-foo.mdcollections/_store/en/acme-foo.md_data/en/store.yml
Optional files:
collections/_store/<locale>/acme-foo.mdfor additional locales (usescripts/translate-pages.phpto generate all)_data/<locale>/store.ymlfor additional translations_data/screenshots.yml_data/store/releases/FooBundle.yaml_includes/store/changelog/FooBundle.md- image files in
images/marketplace/
Step 1: Add the developer entry
Add yourself or your company to _data/developer.yml.
Minimal example:
acme:
name: Acme GmbH
description: Kimai plugin and integration vendor
image: https://example.com/logo.webp
homepage: https://example.com
github: https://github.com/acme
email: hello@example.com
Important notes:
name,description, andimageshould be treated as required for Store entriesimagecan be a local image path like/images/...or a full remote URLhomepage,github,email,twitter,mastodon, andyoutubeare optional- paid items can also define
purchase_details, but that is optional and mainly used for the FAQ section on the detail page
Step 2: Add the product metadata
Create _data/store/acme-foo.yml.
This file controls pricing, buttons, screenshots, documentation links, plugin installation tabs, and badges.
Example for a plugin:
developer: acme
icon: fas fa-puzzle-piece
price: 0
documentation: plugin-foo
tags: [plugin]
bundle:
name: "FooBundle"
clone: "https://github.com/acme/FooBundle.git"
Example for a paid plugin:
developer: acme
icon: fas fa-puzzle-piece
subscription: 49 €
shop: "https://example.com/buy/foo"
documentation: plugin-foo
changelog: true
demo: true
tags: [plugin, cloud]
bundle:
name: "FooBundle"
Common keys in _data/store/<slug>.yml
developer- your developer ID from_data/developer.ymlicon- icon class shown in the listing and fallback areastags- badges such asplugin,app,desktop,client,cloud,featuredprice- one-time price, or0for free itemssubscription- recurring price label like49 €subscription_period- optional. default: annual payment, allowed values:monthshop- checkout URL for paid itemsdownload- download URL for free downloadsgithub- repository URL; if no explicitdownloadexists, the page links to GitHub releasesemail- contact fallback if there is no direct download or checkoutplay-store- Android store linkapp-store- Apple App Store linkdocumentation- slug of a documentation page undercollections/_documentation/demo- set totrueto show the demo tabchangelog- set totrueto show a changelog tabscreenshots- screenshot IDs from_data/screenshots.ymlscreenshot- direct image URLs, usually only used for simple casesnew- legacy field that may be used for temporary highlighting
Plugin-specific bundle block
If your item is a Kimai plugin and should show installation instructions, add a bundle section:
bundle:
name: "FooBundle"
clone: "https://github.com/acme/FooBundle.git"
command: "kimai:bundle:foo:install"
assets: true
Available keys:
name- bundle directory and class name, for exampleFooBundleclone- optional Git clone URL shown in the installation tabcommand- optional install or migration command shown in the installation tabassets- set totruewhenbin/console assets:installis required
Important:
- compatibility versions are no longer stored here
- do not put
titleorintrointo this file, they belong in the locale translation files - the old
bundle.versionsstructure is obsolete - legacy top-level flags like
cloudshould not be used for new entries; use badges intagsinstead
Step 3: Add the shared content partial
Create _includes/store/acme-foo.md.
This file contains the actual Store description and is reused by every locale wrapper page.
Minimal example:
FooBundle adds feature X, Y, and Z to Kimai.
## Features
- First important feature
- Second important feature
- Third important feature
If your item already has a dedicated plugin documentation page, the Store description can stay short and link to that page.
Step 4: Add the Store page wrapper
Create the English wrapper page at collections/_store/en/acme-foo.md.
Example:
---
title: Foo
type: plugin
---
{% include store/acme-foo.md %}
The wrapper page is intentionally tiny.
The frontmatter now only contains:
title- mostly a fallback titletype- controls where the item appears
Current type values used in the repository:
plugin- normal plugin listingfeatured- featured plugin listing on the main store pageapp- mobile appsdesktop- desktop applicationsclient- other clients and integrations
If you are unsure, use plugin for Kimai plugins.
Important:
- featured placement is currently controlled by
type: featured - a
featured: trueflag inside_data/store/<slug>.ymlis not enough on its own
Step 5: Add translated list texts
The title and short intro shown in listings and headers come from _data/<locale>/store.yml, not from the markdown frontmatter.
At minimum, add the English entry to _data/en/store.yml:
items:
acme-foo:
title: Foo
intro: Short summary of your item in one sentence.
If you also want the item to show up with localized text in German, add the same key to _data/de/store.yml.
Current repository reality:
- Store translation files exist for many locales
- every Store locale currently also has its own wrapper page under
collections/_store/<locale>/ - for external contributors, English is the minimum sensible starting point
If you want your item to appear in additional locales immediately, create the matching wrapper pages and add the translated title and intro to the corresponding _data/<locale>/store.yml files.
Step 6: Add locale wrapper pages when needed
All existing Store items currently have wrapper pages for all active Store locales.
Each wrapper page looks the same except for the path, for example:
collections/_store/de/acme-foo.mdcollections/_store/fr/acme-foo.mdcollections/_store/zh_Hans/acme-foo.md
The content can stay identical:
---
title: Foo
type: plugin
---
{% include store/acme-foo.md %}
The localized title and intro still come from _data/<locale>/store.yml.
Step 7: Add screenshots
If your item has screenshots, there are two parts:
- add image files, preferably in
images/marketplace/ - register the screenshot IDs in
_data/screenshots.yml
Example:
acme-foo0:
src: "/images/marketplace/acme/foo-0.webp"
acme-foo1:
src: "/images/marketplace/acme/foo-1.webp"
Then reference them in _data/store/acme-foo.yml:
screenshots:
- acme-foo0
- acme-foo1
Optional localized captions are stored in _data/<locale>/store.yml:
screenshots:
acme-foo0:
description: Main dashboard of FooBundle
acme-foo1:
description: Configuration screen
Step 8: Add compatibility and changelog data
If your plugin should display compatibility information or a changelog tab, add release metadata.
Compatibility file:
_data/store/releases/FooBundle.yaml
Example:
versions:
- [1.2.0, 2.54.0]
- [1.1.0, 2.50.0]
Optional changelog include:
_includes/store/changelog/FooBundle.md
Then enable the tab in _data/store/acme-foo.yml:
changelog: true
bundle:
name: "FooBundle"
Notes:
- the old
bundle.versionskey is no longer used - compatibility data lives in
_data/store/releases/ - changelog content lives in
_includes/store/changelog/ - some Kimai-maintained plugins update this data through
scripts/update-bundles.php
Full example
For a new free plugin called acme-foo, the minimal useful file set is:
_data/developer.yml
_data/store/acme-foo.yml
_data/en/store.yml
_includes/store/acme-foo.md
collections/_store/en/acme-foo.md
A more complete Store entry usually also includes:
collections/_store/de/acme-foo.md
_data/de/store.yml
_data/screenshots.yml
images/marketplace/acme/foo-0.webp
_data/store/releases/FooBundle.yaml
_includes/store/changelog/FooBundle.md
What changed compared to the old workflow
The following parts of older instructions are no longer correct:
- product metadata is not stored in markdown frontmatter anymore
- wrapper pages now only contain
title,type, and the include call titleandintrocome from_data/<locale>/store.yml- compatibility versions no longer belong in
_data/store/<slug>.yml bundle.versionshas been replaced by_data/store/releases/<Bundle>.yaml- screenshots are now typically managed via
_data/screenshots.yml - one shared include in
_includes/store/<slug>.mdis the central place for the long description - Store entries are now spread across data files, include files, locale files, and optional release metadata
Tips for first-time contributors
- start with English first
- copy an existing item with a similar type, then rename all occurrences of the slug
- keep the same slug everywhere
- prefer
webpfor new local images - if you add a plugin, include the
bundle.nameso the installation tab can be generated - if you do not want to add translations for all locales yourself, mention that in the pull request
If you are unsure which existing entry is closest to your case, use one of these as a template:
- free plugin:
keleo-importer-bundle - paid plugin:
task-management-bundle - desktop client:
owlysk-codetimer - mobile app:
drthomasentner-timai - saas:
kloudshift-klockshift