Plugins
Build custom plugins to extend the functionality of your API reference.
Using a Plugin
import { MyCustomPlugin } from './my-custom-plugin.ts'
const configuration = {
url: 'https://registry.scalar.com/@scalar/apis/galaxy?format=json',
plugins: [
MyCustomPlugin(),
],
}
Creating a Plugin
Specification Extensions
The OpenAPI specification allows to extend the format.
You can add custom properties. They are always prefixed with a x-, here is an example:
openapi: 3.1.1
+x-defaultPlanet: 'earth'
info:
title: Hello World
version: 1.0
paths: {}
Render with Vue
import type { ApiReferencePlugin } from '@scalar/types/api-reference'
import CustomVueComponent from './components/CustomVueComponent.vue'
export const XCustomExtensionPlugin = (): ApiReferencePlugin => {
return () => {
return {
name: 'my-custom-plugin',
extensions: [
// Vue
{
name: 'x-defaultPlanet',
component: CustomVueComponent,
},
],
}
}
}
Render with React
npm install @scalar/react-renderer react react-dom
import { ReactRenderer } from '@scalar/react-renderer'
import type { ApiReferencePlugin } from '@scalar/types/api-reference'
import { CustomReactComponent } from './components/CustomReactComponent'
export const XCustomExtensionPlugin = (): ApiReferencePlugin => {
return () => {
return {
name: 'my-custom-plugin',
extensions: [
// React
{
name: 'x-defaultPlanet',
/** This is a React component. 🤯 */
component: CustomReactComponent,
/** Pass a custom renderer to make it work. */
renderer: ReactRenderer,
},
],
}
}
}
Lifecycle Hooks
Plugins can hook into the API Reference lifecycle to run code at specific points.
Available Hooks
onInit({ config, auth })— Called when the API Reference is initialized. Receives the resolved configuration and the authentication state.onConfigChange({ config, auth })— Called when the API Reference configuration changes.onDestroy()— Called when the API Reference is destroyed. Use for cleanup.
Example
import type { ApiReferencePlugin } from '@scalar/types/api-reference'
export const AnalyticsPlugin = (): ApiReferencePlugin => {
return () => {
return {
name: 'analytics-plugin',
extensions: [],
hooks: {
onInit({ config }) {
console.log('API Reference initialized', config)
},
onConfigChange({ config }) {
console.log('Configuration changed', config)
},
onDestroy() {
console.log('API Reference destroyed')
},
},
}
}
}
Reading the Authentication State
Plugins can read the global authentication state — the secrets the user has entered (tokens, API keys, OAuth credentials) and the selected security schemes. This is read-only; plugins cannot mutate auth.
The auth accessor exposes three methods:
| Method | Description |
|---|---|
export() |
Returns a snapshot of the entire authentication state, keyed by document name. |
getAuthSecrets(documentName, schemeName) |
Returns the stored secrets for a security scheme within a document, or undefined. |
getAuthSelectedSchemas(payload) |
Returns the selected security for a document ({ type: 'document', documentName }) or operation ({ type: 'operation', documentName, path, method }), or undefined. |
From lifecycle hooks
The auth accessor is passed to onInit and onConfigChange alongside config:
import type { ApiReferencePlugin } from '@scalar/types/api-reference'
export const AuthAwarePlugin = (): ApiReferencePlugin => {
return () => {
return {
name: 'auth-aware-plugin',
extensions: [],
hooks: {
onConfigChange({ auth }) {
// Read the secrets the user entered for a specific scheme
const secrets = auth.getAuthSecrets('my-document', 'bearerAuth')
console.log('Current bearer token', secrets?.token)
// Or grab a full snapshot of every document's auth state
console.log('All auth state', auth.export())
},
},
}
}
}
From a view component
View components can reach the same accessor through the plugin manager:
import { usePluginManager } from '@scalar/api-reference/plugins'
const pluginManager = usePluginManager()
const auth = pluginManager.getAuthState()
const selected = auth.getAuthSelectedSchemas({ type: 'document', documentName: 'my-document' })
Additional Components
Plugins can inject components at specific locations in the API Reference using views.
Available Views
content.start- Before the Introduction/Info sectioncontent.end- After the Models section
Sidebar Visibility
View components can optionally appear in the sidebar. Add a sidebar configuration to control this. Clicking the entry scrolls to the component, and the entry highlights as it scrolls into view, just like the built-in sections.
{
component: CustomComponent,
sidebar: {
show: true, // true = visible in sidebar, false/omitted = hidden
label: 'My Page', // Display text in the sidebar
},
}
Example
import type { ApiReferencePlugin } from '@scalar/types/api-reference'
import CustomComponent from './components/CustomComponent.vue'
export const FeedbackPlugin = (): ApiReferencePlugin => {
return () => {
return {
name: 'feedback-plugin',
extensions: [],
views: {
'content.start': [
{
component: CustomComponent,
// Show in sidebar
sidebar: {
show: true,
label: 'Getting Started',
},
},
],
'content.end': [
{
component: CustomComponent,
// Not shown in sidebar (omitted)
},
],
},
}
}
}
Component Props
View components receive:
options- API Reference configuration options
Using React Components
import { ReactRenderer } from '@scalar/react-renderer'
import { CustomComponent } from './components/CustomComponent'
export const FeedbackPlugin = (): ApiReferencePlugin => {
return () => {
return {
name: 'feedback-plugin',
extensions: [],
views: {
'content.end': [
{
component: CustomComponent,
renderer: ReactRenderer,
},
],
},
}
}
}
With sidebar visibility:
import { ReactRenderer } from '@scalar/react-renderer'
import { CustomComponent } from './components/CustomComponent'
export const FeedbackPlugin = (): ApiReferencePlugin => {
return () => {
return {
name: 'feedback-plugin',
extensions: [],
views: {
'content.start': [
{
component: CustomComponent,
renderer: ReactRenderer,
sidebar: {
show: true,
label: 'Support',
},
},
],
},
}
}
}
API Client Plugins
The API Reference uses the API Client to test requests. The API Client has its own plugin API and you can't pass a API Client plugin directly, to the API Reference, but you can wrap it in a API Reference plugin.
API Client Plugins can add lifecycle hooks, custom UI components, and custom response body handlers for content types the client does not natively support.
Using a Plugin
Pass plugins when creating the API Client:
import { createApiClientApp } from '@scalar/api-client/app'
import type { ClientPlugin } from '@scalar/oas-utils/helpers'
const myPlugin: ClientPlugin = {
// ...
}
createApiClientApp(el, {
layout: 'web',
plugins: [myPlugin],
})
Example: Custom Response Body Handling
When your API returns a content type the client does not natively support (for example, MessagePack), you can register a responseBody handler to decode and display it:
import { createApiReference } from '@scalar/api-reference'
import type { ClientPlugin } from '@scalar/oas-utils/helpers'
import type { ApiReferencePlugin } from '@scalar/types/api-reference'
/** Msgpack API Client Plugin */
const MsgpackApiClientPlugin: ClientPlugin = {
responseBody: [
{
mimeTypes: ['application/msgpack', 'application/x-msgpack'],
decode: async (buffer) => {
const { decode } = await import('@msgpack/msgpack')
const decoded = decode(new Uint8Array(buffer))
return JSON.stringify(decoded, null, 2)
},
language: 'json',
},
],
}
/** Wrapped in an API Reference Plugin */
const MsgpackPlugin = (): ApiReferencePlugin => {
return () => ({
name: 'msgpack',
extensions: [],
apiClientPlugins: [MsgpackApiClientPlugin],
})
}
/** Creating a new API Reference */
createApiReference(el, {
url: 'https://registry.scalar.com/@scalar/apis/galaxy?format=json',
plugins: [MsgpackPlugin],
})
Each handler in responseBody supports:
| Property | Description |
|---|---|
mimeTypes |
MIME type patterns to match (exact or wildcard like application/vnd.*+json). |
decode |
Transforms the raw ArrayBuffer into a string or Blob for display. |
language |
CodeMirror language hint for the built-in raw renderer (for example, json). Mutually exclusive with rawComponent. |
rawComponent |
A custom Vue component for the raw view. Mutually exclusive with language. |
previewComponent |
A custom Vue component for the preview view. |
Lifecycle Hooks
Plugins can hook into the request lifecycle:
const loggingPlugin: ClientPlugin = {
hooks: {
beforeRequest: ({ requestBuilder }) => {
requestBuilder.headers.set('X-Custom-Header', 'value')
},
responseReceived: ({ response }) => {
console.log('Response status:', response.status)
},
},
}