Site Config
All site settings are configured within the siteConfig object in your scalar.config.json file.
Example
// scalar.config.json
{
"$schema": "https://registry.scalar.com/@scalar/schemas/config",
"scalar": "2.0.0",
"siteConfig": {
"logo": "https://example.com/logo.svg",
"theme": "default"
}
}Logo#
The logo property defines your site's logo. You can provide a single URL for all modes, or separate logos for light and dark themes.
Where the Logo Appears#
Your logo renders on the first of these surfaces your site has:
- The header, if you declare
navigation.headeror setlayout.headertotrue - The tabs, if you have
navigation.tabsbut no header - The sidebar, if you have neither
To force the logo to go in the header, set layout.header to true. If a page hides all three surfaces through its layout options, the logo does not render on that page.
If you do not set a logo, your project title from info.title renders in the same place instead.
Single Logo#
// scalar.config.json
{
"$schema": "https://registry.scalar.com/@scalar/schemas/config",
"scalar": "2.0.0",
"siteConfig": {
"logo": "https://example.com/logo.svg"
}
}Light and Dark Mode#
For better visibility across themes, provide different logos for light and dark modes:
// scalar.config.json
{
"$schema": "https://registry.scalar.com/@scalar/schemas/config",
"scalar": "2.0.0",
"siteConfig": {
"logo": {
"darkMode": "https://example.com/logo-dark.svg",
"lightMode": "https://example.com/logo-light.svg"
}
}
}Properties#
| Property | Type | Required | Description |
|---|---|---|---|
logo |
string |
No | URL to a single logo for all themes |
logo.darkMode |
string |
No | URL to the logo displayed in dark mode |
logo.lightMode |
string |
No | URL to the logo displayed in light mode |
Theme#
The theme property sets a platform-defined theme for your documentation site.
// scalar.config.json
{
"$schema": "https://registry.scalar.com/@scalar/schemas/config",
"scalar": "2.0.0",
"siteConfig": {
"theme": "purple"
}
}Properties#
| Property | Type | Required | Description |
|---|---|---|---|
theme |
string |
No | Slug for a platform-defined theme |
Color Scheme#
The colorScheme property controls the light/dark mode appearance and toggle behavior for your documentation site.
// scalar.config.json
{
"$schema": "https://registry.scalar.com/@scalar/schemas/config",
"scalar": "2.0.0",
"siteConfig": {
"colorScheme": {
"default": "system",
"showToggle": true
}
}
}Properties#
| Property | Type | Default | Description |
|---|---|---|---|
default |
"light" | "dark" | "system" |
"system" |
Default color scheme on page load |
showToggle |
boolean |
true |
Whether to show the color scheme toggle |
Examples#
Force Light Mode#
Force your documentation to always display in light mode without a toggle:
// scalar.config.json
{
"$schema": "https://registry.scalar.com/@scalar/schemas/config",
"scalar": "2.0.0",
"siteConfig": {
"colorScheme": {
"default": "light",
"showToggle": false
}
}
}Force Dark Mode#
Force your documentation to always display in dark mode without a toggle:
// scalar.config.json
{
"$schema": "https://registry.scalar.com/@scalar/schemas/config",
"scalar": "2.0.0",
"siteConfig": {
"colorScheme": {
"default": "dark",
"showToggle": false
}
}
}System Preference with Toggle#
Respect the user's system preference while allowing them to override it:
// scalar.config.json
{
"$schema": "https://registry.scalar.com/@scalar/schemas/config",
"scalar": "2.0.0",
"siteConfig": {
"colorScheme": {
"default": "system",
"showToggle": true
}
}
}Ask AI#
The agent property controls the appearance of Ask AI on your documentation site: the Ask AI button, its placement in the sidebar, the position of the floating chat widget, and the suggested questions shown in the chat.
// scalar.config.json
{
"$schema": "https://registry.scalar.com/@scalar/schemas/config",
"scalar": "2.0.0",
"siteConfig": {
"agent": {
"position": "right",
"suggestions": ["How do I authenticate?", "What are the rate limits?"]
}
}
}Properties#
| Property | Type | Default | Description |
|---|---|---|---|
enabled |
boolean |
— | Whether the Ask AI button is shown on the site |
buttonText |
string |
"Ask AI" |
Label shown on the Ask AI button |
sidebarPosition |
"below-search" | "default" |
— | Placement of the Ask AI button in the sidebar. "default" renders it next to the search bar; "below-search" renders it on its own row beneath the search bar |
position |
"center" | "right" |
"center" |
Where the floating chat widget anchors at the bottom of the viewport |
suggestions |
string[] |
— | Suggested questions shown as pills above the chat input when it is focused. Two or three short questions work best |
mcp |
object |
— | References an MCP server and installation by slug (serverSlug, installationSlug), resolved on publish |
Layout#
The layout property controls global layout options that apply to all pages unless overridden by a page's own layout options.
// scalar.config.json
{
"$schema": "https://registry.scalar.com/@scalar/schemas/config",
"scalar": "2.0.0",
"siteConfig": {
"layout": {
"toc": true,
"header": true,
"pageTitle": true,
"pageActions": true,
"search": {
"enabled": true,
"position": "header"
}
}
}
}Properties#
| Property | Type | Default | Description |
|---|---|---|---|
toc |
boolean |
true |
Whether to show the table of contents globally |
header |
boolean |
— | Whether to show the header globally. Falls back to whether or not navigation.header is declared |
pageTitle |
boolean |
true |
Whether to show page titles globally |
pageActions |
boolean |
true |
Whether to show page actions globally |
search |
object |
— | Search bar configuration |
Search Configuration#
The search object within layout controls the global search behavior.
| Property | Type | Default | Description |
|---|---|---|---|
enabled |
boolean |
true |
Enable or disable search globally |
position |
"header" | "sidebar" |
"header" |
Where to display the search bar |
Disable Search#
// scalar.config.json
{
"$schema": "https://registry.scalar.com/@scalar/schemas/config",
"scalar": "2.0.0",
"siteConfig": {
"layout": {
"search": {
"enabled": false
}
}
}
}Move Search to Sidebar#
// scalar.config.json
{
"$schema": "https://registry.scalar.com/@scalar/schemas/config",
"scalar": "2.0.0",
"siteConfig": {
"layout": {
"search": {
"position": "sidebar"
}
}
}
}Head#
The head property allows you to inject custom elements into the HTML <head> of your documentation pages. This is useful for adding custom styles, scripts, meta tags, and favicon links.
Example#
// scalar.config.json
{
"$schema": "https://registry.scalar.com/@scalar/schemas/config",
"scalar": "2.0.0",
"siteConfig": {
"head": {
"title": "My Documentation",
"meta": [
{
"name": "description",
"content": "Documentation for my API"
},
{
"property": "og:image",
"content": "https://example.com/og-image.png"
}
],
"styles": [
{
"path": "assets/custom-styles.css"
}
],
"scripts": [
{
"path": "assets/analytics.js"
}
],
"links": [
{
"rel": "icon",
"href": "/favicon.png"
}
]
}
}
}Properties#
| Property | Type | Required | Description |
|---|---|---|---|
title |
string |
No | The page title |
meta |
array | object |
No | Meta tags for SEO and social sharing |
styles |
array |
No | CSS files to include |
scripts |
array |
No | JavaScript files to include |
links |
array |
No | Link elements (favicon, preload, etc.) |
Meta Tags#
Meta tags can be provided as an array of objects or as a key-value object:
Array Format
"meta": [
{
"name": "description",
"content": "My API documentation"
},
{
"property": "og:title",
"content": "My API"
}
]Object Format
"meta": {
"description": "My API documentation",
"og:title": "My API"
}Styles#
Include custom CSS files in your documentation. Each entry loads from either a local path or a remote url:
"styles": [
{
"path": "assets/custom-styles.css",
"tagPosition": "head"
},
{
"url": "https://example.com/theme.css"
}
]| Property | Type | Required | Description |
|---|---|---|---|
path |
string |
Yes* | Relative path to the CSS file |
url |
string |
Yes* | Remote URL to the CSS file |
tagPosition |
"head" | "bodyOpen" | "bodyClose" |
No | Where to inject the style tag |
* Provide either path or url.
Scripts#
Include custom JavaScript files. Each entry loads from either a local path or a remote url:
"scripts": [
{
"path": "assets/analytics.js",
"tagPosition": "bodyClose"
}
]| Property | Type | Required | Description |
|---|---|---|---|
path |
string |
Yes* | Relative path to the JavaScript file |
url |
string |
Yes* | Remote URL to the JavaScript file |
tagPosition |
"head" | "bodyOpen" | "bodyClose" |
No | Where to inject the script tag |
async |
boolean |
No | Load the script without blocking the parser, running it as soon as it arrives |
defer |
boolean |
No | Load the script without blocking the parser, running it after parsing in document order |
type |
string |
No | The script type attribute, for example "module" |
* Provide either path or url.
By default a configured script loads synchronously in the <head> and blocks first render until it has downloaded and run. Set async or defer so non-critical scripts (analytics, consent banners, chat widgets) load without blocking:
"scripts": [
{ "path": "assets/analytics.js" },
{ "url": "https://example.com/widget.js", "defer": true }
]Links#
Add link elements for favicons, preloading resources, or other purposes:
"links": [
{
"rel": "icon",
"type": "image/png",
"href": "/favicon.png"
},
{
"rel": "preconnect",
"href": "https://fonts.googleapis.com"
}
]| Property | Type | Description |
|---|---|---|
rel |
string |
The relationship type (icon, preload) |
href |
string |
The URL or path to the resource |
type |
string |
The MIME type of the resource |
Footer#
The footer property allows you to add a custom footer to your documentation site.
// scalar.config.json
{
"$schema": "https://registry.scalar.com/@scalar/schemas/config",
"scalar": "2.0.0",
"siteConfig": {
"footer": {
"filepath": "docs/footer.html"
}
}
}Properties#
| Property | Type | Description |
|---|---|---|
filepath |
string |
Relative path to a custom HTML footer file |
RSS#
The rss property publishes an RSS feed for your changelog, so readers can subscribe to your releases in a feed reader.
Point path at the route your changelog lives on. The feed is written to rss.xml under that route — a changelog at /changelog publishes its feed at /changelog/rss.xml.
// scalar.config.json
{
"$schema": "https://registry.scalar.com/@scalar/schemas/config",
"scalar": "2.0.0",
"siteConfig": {
"rss": {
"path": "/changelog",
"title": "Scalar Changelog",
"description": "Every Scalar release, as a feed"
}
}
}Properties#
| Property | Type | Required | Description |
|---|---|---|---|
path |
string |
Yes | Route of your changelog, for example /changelog. Must be a plain site route with no .. segments |
title |
string |
No | Title of the feed, shown in feed readers. Defaults to your site title plus Changelog |
description |
string |
No | Description of the feed, shown in feed readers |
entries |
string |
No | How items are found. headings (default) turns each dated heading into an item; pages turns each page under path with a date in its frontmatter into an item |
Multiple Feeds#
To publish more than one feed, set rss to a list. Each entry is a feed with its own path, and each is written to rss.xml under that path — so /changelog and /blog publish /changelog/rss.xml and /blog/rss.xml side by side:
// scalar.config.json
{
"$schema": "https://registry.scalar.com/@scalar/schemas/config",
"scalar": "2.0.0",
"siteConfig": {
"rss": [
{
"path": "/changelog",
"title": "Scalar Changelog",
"description": "Every Scalar release, as a feed"
},
{
"path": "/blog",
"title": "Scalar Blog"
}
]
}
}Every feed takes the same properties as a single one, and each path must be unique. A single feed still works exactly as shown above — the list is only needed when you want more than one.
When a page sits under more than one feed, its header shows a subscribe button for each, with the nearest feed first.
Writing Entries#
Each entry in the feed comes from a heading that carries a date in YYYY-MM-DD form:
## 1.2.0 (2026-07-24)
Added a dark mode toggle to the header.
## 1.1.0 (2026-07-10)
Introduced page actions: copy as Markdown, open in editor, and report an issue.The heading becomes the item title, and the content below it becomes the item description. Only the top-most heading level that carries dates starts entries; any deeper heading folds into the release above it — even one that happens to contain a date — so you can nest subheadings like ### Fixes inside a release without splitting it apart.
If a heading looks dated but the date is not real (## 2.0.0 (2026-13-01)), that release is left out of the feed and the build warns you, since a typo is the only way to get there.
Multiple Products#
A changelog split across several pages works too. Every page at path or beneath it contributes its entries, and the feed merges them newest-first:
/changelog <- index page, lists the products
/changelog/api-client <- entries
/changelog/api-reference <- entries
An index page with no dated headings contributes nothing of its own, which is what you want when it only links to the products.
Hidden pages are skipped. A page kept out of the sidebar and the sitemap stays out of the feed as well.
One Item per Page#
For a blog, where each post is its own page rather than a heading on a shared page, set entries to pages:
// scalar.config.json
{
"$schema": "https://registry.scalar.com/@scalar/schemas/config",
"scalar": "2.0.0",
"siteConfig": {
"rss": {
"path": "/blog",
"title": "Scalar Blog",
"entries": "pages"
}
}
}Now every page under path that carries a date in its frontmatter becomes one feed item, newest first:
---
date: 2026-07-24
---
# Our new dark mode
A short introduction to the post.The page title becomes the item title, its description becomes the item description, and the frontmatter date sets the publish date. Pages without a date — an index page, a draft — are left out, so nothing is syndicated by accident.
Discovery#
Every page on your site advertises the feed in its <head>, so feed readers and browser extensions can find it from any URL:
<link rel="alternate" type="application/rss+xml" href="https://example.com/changelog/rss.xml">Pages at path and beneath it also show a subscribe button in the page header, next to Copy Page — one per feed the page belongs to.
Content Signals#
The contentSignals property declares how search and AI crawlers may use your published documentation. Scalar writes these preferences as a Content-Signal line in the generated robots.txt.
Content Signals are enabled by default. If you omit contentSignals, or omit an individual signal, all unspecified signals default to "yes":
Content-Signal: search=yes, ai-input=yes, ai-train=yesProperties#
Set contentSignals to false to omit the directive, or use an object with these optional properties:
| Property | Type | Default | Description |
|---|---|---|---|
enabled |
boolean |
true |
Whether to emit the directive. Set to false to retain your preferences without publishing them. |
search |
"yes" or "no" |
"yes" |
Building a search index and showing links and short excerpts. |
aiInput |
"yes" or "no" |
"yes" |
Using content as input for AI answers, including retrieval and grounding. |
aiTrain |
"yes" or "no" |
"yes" |
Training or fine-tuning AI models. |
Allow Search and AI Answers, Decline AI Training#
Add the following to your scalar.config.json:
{
"siteConfig": {
"contentSignals": {
"search": "yes",
"aiInput": "yes",
"aiTrain": "no"
}
}
}After publishing, the generated robots.txt includes:
User-agent: *
Content-Signal: search=yes, ai-input=yes, ai-train=no
Allow: /Disable the Directive#
Set contentSignals to false to omit the Content-Signal line entirely:
{
"siteConfig": {
"contentSignals": false
}
}Alternatively, set contentSignals.enabled to false to keep your per-signal preferences for later. Disabling the directive does not declare no for any use. To decline a use explicitly, keep Content Signals enabled and set that signal to "no".
You can also manage these settings in your documentation project's Settings → Content Signals. Publish changes to update the generated file. If your project's assets include a custom robots.txt, Scalar preserves that file instead of generating one; edit its Content Signals directly.
Content Signals are advisory preferences that crawlers may honor. They do not block access or replace authentication. See Privacy for more context.
Routing#
The routing property configures URL redirects and path patterns for your documentation.
Redirects#
Set up redirects to handle URL changes or aliases:
// scalar.config.json
{
"$schema": "https://registry.scalar.com/@scalar/schemas/config",
"scalar": "2.0.0",
"siteConfig": {
"routing": {
"redirects": [
{
"from": "/old-path",
"to": "/new-path"
},
{
"from": "/docs/v1",
"to": "/docs/latest"
}
]
}
}
}Properties#
| Property | Type | Description |
|---|---|---|
redirects |
array |
Array of redirect rules |
guidePathPattern |
string |
URL pattern for guide pages |
referencePathPattern |
string |
URL pattern for API reference pages |
Redirect Object#
| Property | Type | Required | Description |
|---|---|---|---|
from |
string |
Yes | The source path to match |
to |
string |
Yes | The destination path |
Path Patterns#
Customize the URL structure for guides and API references:
"routing": {
"guidePathPattern": "/docs/:slug",
"referencePathPattern": "/api/:slug"
}