Sections

Plugins

The design of Frontdoor's plugin host, its manifest and module contracts, and the packages it accepts. Currently locked off.

On this page

The plugin platform is locked off in current releases: plugin routes answer 404 and the server keeps the plugin setting off. This page describes the design.

Frontdoor can load plugins at runtime through a lightweight host. Plugins run in the page origin, so only reviewed, owner-approved code should ever be enabled.

Loader inputs

Set one or more of these variables before building or deploying:

Variable Value
VITE_FRONTDOOR_PLUGIN_MANIFESTS Manifest URLs, as a comma-separated or newline-separated list
VITE_FRONTDOOR_PLUGIN_MODULES Module URLs, as a comma-separated or newline-separated list
VITE_FRONTDOOR_ENABLE_SAMPLE_PLUGIN Boolean flag that loads the built-in ticket example

Manifest contract

{
  "id": "ticket-plugin",
  "name": "Ticket Plugin",
  "version": "1.0.0",
  "description": "Adds a ticket creation action, route and surface",
  "entry": "https://cdn.example.com/ticket-plugin/index.js",
  "permissions": ["actions.write", "routes.write"],
  "roles": ["owner", "admin"],
  "backend": {
    "enabled": true,
    "url": "https://plugins.example.com/frontdoor-webhook",
    "eventSubscriptions": ["auth.login", "app.access"]
  }
}

Module contract

A module exports a register(api) function. The SDK also offers definePlugin() and definePluginManifest() helpers for canonical metadata and plugin definitions.

import { definePlugin, definePluginManifest } from '../pluginHost/sdk.js';

export const manifest = definePluginManifest({
  id: 'ticket-plugin',
  name: 'Ticket Plugin',
  version: '1.0.0',
});

export function register(api) {
  api.registerAction({
    id: 'create-ticket',
    label: 'Create Ticket',
    surface: 'layout.accountMenu',
    order: 20,
    onClick: () => api.notify({ type: 'success', message: 'Ticket flow opened' }),
  });
}

export default definePlugin({
  manifest,
  register,
});

Runtime API

The plugin host exposes:

  • getCurrentUser()
  • getBranding()
  • getLanguage()
  • getUiStrings()
  • navigate()
  • notify()
  • openExternalUrl()
  • registerAction()
  • registerSurface()
  • registerRoute()
  • registerNavigationItem()

Surfaces

Built-in surfaces where a plugin can add content:

  • layout.nav.desktop
  • layout.nav.mobile
  • layout.accountMenu
  • home.hero.after
  • home.controls.after
  • home.catalog.after
  • admin.header.actions
  • admin.page.top
  • admin.page.bottom
  • customization.page.top
  • customization.page.bottom

Server registry

Frontdoor can store plugin metadata in SQLite and expose it through /api/plugins. The runtime loader reads /api/plugins/runtime and loads every enabled plugin that has a frontend entry. The admin page shows the server registry separately from the in-memory runtime snapshot.

Install and approve

From the admin page you can install a plugin by filling in the manifest fields, pasting a module source, uploading a single JSON package, or pointing to an external entry URL. New installs are pending until an owner approves them.

The same page can export the current draft as a JSON package and open a validation wizard before installation or approval. The wizard shows the package's risk level, the permissions it requires, its backend webhook exposure and the raw package.

Backend events

A plugin can receive backend events by declaring backend.url and backend.eventSubscriptions. Events are dispatched only to plugins that are both enabled and approved.

Package formats

JSON package

A single JSON file with a manifest object and an optional moduleSource string. The module source must be self-contained and export register(api) directly.

{
  "manifest": {
    "id": "ticket-plugin",
    "name": "Ticket Plugin",
    "version": "1.0.0",
    "permissions": ["actions.write", "routes.write", "surfaces.write"],
    "roles": ["owner", "admin"]
  },
  "moduleSource": "export function register(api) { api.registerRoute({ id: 'ticket-plugin.route', path: '/plugins/ticket-center', label: 'Ticket Center' }); } export default { register };"
}

ZIP package

A ZIP archive with this structure, suited to third-party plugins distributed as a single bundle:

my-plugin-1.0.0/
  manifest.json
  module.mjs

The admin page can import and export plugins in this format.

Audit trail

Plugin approvals and revocations are recorded in the audit log with target type plugin, so owners can review who approved or rejected a package. The dedicated view is at /admin/plugins/audit.