Customize Portal Content
The Enterprise Portal is Beta. Features described on this page are subject to change.
This topic describes how to customize the content in the new Enterprise Portal, including the content template structure, table of contents configuration, MDX components, template variables, visibility rules, and downloadable assets.
For branding and theme customization, see Customize Portal Branding. To serve different content for different release versions, see Manage Content Versions.
Content template structure
The default content template (replicatedhq/enterprise-portal-content) provides a working portal out of the box with the following structure:
your-content-repo/
├── pages/
│ ├── home.md
│ ├── installation/
│ │ ├── release-history.md
│ │ ├── linux.md
│ │ ├── kurl.md
│ │ ├── helm.md
│ │ └── kots.md
│ ├── updates/
│ │ └── instances.md
│ ├── security.md
│ ├── support/
│ │ ├── bundles.md
│ │ ├── faq.md
│ │ └── contact.md
│ └── automation/
│ ├── api-reference.md
│ └── workflow-guide.md
├── toc.yaml
└── theme.yaml
The template's toc.yaml organizes content into Installation, Instances & Updates, Security, Support, and Automation. Install method pages are entitlement-gated. Existing Cluster (KOTS) is gated on isKotsInstallEnabled only. Linux (kURL) is gated on isKurlInstallEnabled and isAirgapSupported because the default kURL page is still downloads-only for air gap.
navigation:
- title: Installation
items:
- title: Release History
page: pages/installation/release-history.md
- title: Linux (Embedded Cluster)
page: pages/installation/linux.md
visible_when:
entitlements:
- isEmbeddedClusterDownloadEnabled
- title: Linux (kURL)
page: pages/installation/kurl.md
visible_when:
entitlements:
- isKurlInstallEnabled
- isAirgapSupported
- title: Existing Cluster (Helm)
page: pages/installation/helm.md
visible_when:
entitlements:
- isHelmInstallEnabled
- title: Existing Cluster (KOTS)
page: pages/installation/kots.md
visible_when:
entitlements:
- isKotsInstallEnabled
- title: Instances & Updates
page: pages/updates/instances.md
- title: Security
page: pages/security.md
visible_when:
entitlements:
- canViewSecurity
- title: Support
items:
- title: Support Bundles
page: pages/support/bundles.md
- title: FAQ
page: pages/support/faq.md
- title: Contact Support
page: pages/support/contact.md
- title: Automation
items:
- title: API Reference
page: pages/automation/api-reference.md
- title: Workflow Guide
page: pages/automation/workflow-guide.md
overrides:
home: pages/home.md
The template pages use built-in MDX components (see MDX Components) to render interactive installation instructions, version selectors, support bundle uploads, and more. You can customize any page by editing the markdown and MDX, or replace the entire structure with your own.
Table of contents
The toc.yaml file at the root of your repo defines the sidebar navigation. Each navigation item has a title and one of the following content types:
| Key | What it does |
|---|---|
page | Renders a markdown file from your repo (e.g. pages/getting-started.md) |
link | Opens an external URL in a new tab instead of a page (see External links) |
terraform_module | Generates docs from a Terraform module source URI (see Terraform Modules) |
helm_chart | Generates reference docs from a Helm chart in your promoted release (see Helm Reference Docs) |
items | Nests child navigation items to create expandable sections. Items can nest to any depth, with each child following the same structure |
Every item also supports icon and visible_when (see Visibility below).
The toc.yaml acts as an allowlist: pages that exist in your repo but are not listed in toc.yaml are not reachable through the portal navigation or direct URL. Omitting a page from toc.yaml hides it entirely. To keep the page in the repo and listed in the TOC without publishing it, set hidden: true in the page frontmatter. See Hide unpublished pages.
The overrides.home page bypasses the TOC allowlist and remains accessible even if it is not listed in toc.yaml. To hide the home landing page, set hidden: true or visible_when in its frontmatter. overrides.home cannot restore a hidden page or a child of a hidden parent.
Supported icon values: rocket, download, cloud, settings, wrench, life-buoy, file-text, star, book, shield, package, refresh-cw, database, key. If omitted, defaults to book.
Complete example
Here's a toc.yaml showing all content types together:
navigation:
- title: Getting Started
icon: rocket
page: pages/getting-started.md
- title: Installation
icon: download
items:
- title: Requirements
page: pages/installation/requirements.md
- title: Helm Installation
page: pages/installation/helm.md
visible_when:
entitlements:
- isHelmInstallEnabled
- title: Air Gap Installation
page: pages/installation/airgap.md
visible_when:
entitlements:
- isAirgapSupported
- title: Infrastructure
icon: database
items:
- title: AWS Module
terraform_module: github.com/your-org/your-terraform//modules/aws?ref=v1.0.0
visible_when:
entitlements:
- isAWSEnabled
- title: Reference
icon: book
items:
- title: My App Chart
helm_chart:
name: my-app
overrides:
home: pages/getting-started.md
Nested navigation
Navigation items can nest to any depth. Each child item follows the same structure and can contain its own items array:
navigation:
- title: Configuration
icon: settings
items:
- title: Required Values
page: pages/configuration/required-values.md
items:
- title: Authentication
page: pages/configuration/auth.md
- title: Networking
page: pages/configuration/networking.md
- title: Optional Values
page: pages/configuration/optional-values.md
In this example, Configuration expands to show Required Values and Optional Values. Required Values further expands to show Authentication and Networking. Each level is collapsible in the sidebar.
Any item with items can also have its own page, visible_when, and icon. If all children of a parent are hidden by visible_when, the parent is also hidden automatically.
If a TOC node has a page with hidden: true, the portal drops that node and its subtree, including nested helm_chart and terraform_module items. A section that is only a title (no page) cannot use hidden. For more information, see Hide unpublished pages.
External links
Use link to add a navigation item that opens an external URL in a new tab instead of rendering a page from your content repo:
- title: Support
icon: life-buoy
items:
- title: Submit a Support Request
link: https://support.example.com
- title: Support Bundles
page: pages/support/bundles.md
Supported link values:
- Fully-qualified
http://orhttps://URLs mailto:links, including query parameters (for example,mailto:support@example.com?subject=Help)- Bare external hostnames (for example,
support.example.comorwww.google.com/search?q=replicated), which the portal treats ashttps://automatically
A link value must be a static URL. Template variables (\{\{ \}\}) and other dynamic values are not supported, and validation rejects relative or internal-looking paths. If a navigation item's link value fails validation, content sync (and local preview) fails with an error that names the offending item.
If an item specifies both link and page, link takes priority.
MDX components
Enterprise Portal content supports MDX, which is markdown with embedded React components. These components render interactive UI elements that adapt to each customer's license, entitlements, and instance state.
Layout and callouts
<Note>: Informational callout box.
<Note title="Before You Begin">
Run `kubectl get sc` to confirm a default StorageClass is available.
</Note>
<Tip>: Highlighted tip or best practice.
<Tip title="New to this portal?">
Start with the Installation Guide for your deployment method.
</Tip>
<Warning>: Warning callout for important caveats.
<Warning title="Back Up Before Updating">
Always create a backup before applying updates.
</Warning>
<Tabs> / <Tab>: Tabbed content sections.
<Tabs>
<Tab title="Linux">
Linux-specific instructions here...
</Tab>
<Tab title="Helm">
Helm-specific instructions here...
</Tab>
</Tabs>
Props: <Tabs> accepts defaultActiveTab. <Tab> requires title.
<Accordion>: Collapsible content section.
<Accordion title="Advanced Configuration" defaultOpen={false}>
Detailed configuration options...
</Accordion>
Props: title (required), defaultOpen (optional, defaults to false).
<OptionSelector> / <Option>: Persistent option picker that remembers the customer's selection across page loads.
<OptionSelector label="Install Method" defaultOption="Linux" storageKey="install-method">
<Option value="Linux">
- [Linux Installation](/installation/linux)
- [Linux Support Bundles](/operations/bundles/linux)
</Option>
<Option value="Helm">
- [Helm Installation](/installation/helm)
- [Helm Support Bundles](/operations/bundles/helm)
</Option>
</OptionSelector>
Props: label (display label), defaultOption (pre-selected value), storageKey (key for persisting selection in browser storage).
Display
<CodeBlock>: Syntax-highlighted code block.
<CodeBlock language="yaml" title="values.yaml">
replicaCount: 3
image:
repository: myapp
</CodeBlock>
Props: language, title.
<CommandBlock>: Styled terminal command with copy button.
<CommandBlock>
kubectl get pods -A
</CommandBlock>
Props: command, label, encoded.
<ContentLink>: Internal navigation links. Standard markdown links ([text](path)) are automatically converted to use client-side navigation, so you don't need to use this component directly.
Link paths resolve relative to the current page's URL, and the portal injects the customer's selected version into the resolved route. Because resolution is relative, a bare section/page path resolves correctly only from a top-level page. From a page inside a subdirectory, the same path resolves against that subdirectory. For example, [Configure values](installation/values) authored on the installation/helm page resolves to installation/installation/values, which does not exist.
To link reliably from any page, use a leading-slash absolute path. Absolute paths resolve from the content root, and the portal still injects the selected version:
See [Configure values](/installation/values).
From any page, this path resolves to /<version>/installation/values.
Installation components
These components render dynamic, customer-specific installation instructions based on the customer's license entitlements, selected install method, and instance state.
<PendingInstallSelector>: Shows a list of in-progress installations scoped to a specific install method. Customers select an installation to populate the commands below with that installation's credentials.
<PendingInstallSelector method="linux" />
Props: method ("linux", "helm", "kots", or "kurl", required), network ("online" or "airgap", optional filter), title (optional, defaults to "Installations in progress"), emptyText (optional), initialVisible (optional, number of items to show before "Show all").
<NewInstall>: Button to start a new installation. Creates a service account and generates credentials, which populate the install commands on the page.
<NewInstall method="helm" />
Props: method ("linux", "helm", "kots", or "kurl", required), network ("online" or "airgap", optional), label (optional, defaults to "New installation").
If you omit network, the default depends on the page's network selection: "airgap" for air gap, or "online" otherwise.
The install commands on the page are personalized to the selected installation. If you switch installations or rename your instance, the commands update automatically.
<NetworkAvailability>: Selector for online, proxy, or air gap installation mode. The air gap option is shown only when the customer's license supports air gap. Proxy selection also shows a Proxy URL field.
<NetworkAvailability installType="linux" />
Props: installType (optional, "linux", "helm", "kots", or "kurl"). Pass it so the air gap radio is gated on the correct entitlement. Without it, the air gap option is hidden.
<VersionSelector>: Dropdown for selecting which release version to install.
<VersionSelector installType="helm" />
Props: installType ("linux", "helm", "kots", or "kurl").
<KubernetesDistribution />: Selector for the target Kubernetes distribution (EKS, GKE, AKS, etc.). No props.
<RegistryAccess />: Selects registry access settings and accepts a private registry hostname. Props: installType ("linux", "helm", "kots", or "kurl", optional, defaults to "helm"). For Helm, KOTS, and kURL, the component appears only when the page's network selection is air gap.
<LinuxInstallAssets />: Renders the full Linux/Embedded Cluster installation command sequence. Adapts to the customer's selected version and network availability. For air gap installations, includes an optional toggle for private registry image relocation. When enabled, the customer enters their registry hostname and the commands update to include image pull, tag, and push steps targeting that registry. Props: stepNumber (optional, starting step number).
<HelmInstallAssets />: Renders the full Helm installation command sequence. Props: stepNumber (optional), charts (optional, comma-separated list of chart names to include), exclude (optional, comma-separated list of chart names to hide).
When a customer selects limited or no registry access, <HelmInstallAssets /> automatically includes browser download links for the Helm chart tarballs needed for their install. A download link for the preflight plugin binary is always included, regardless of registry access settings. No additional configuration is required.
<LinuxAirgapInstallAssets />: Linux air gap installation commands. Shows an unavailable notice if the air gap bundle is not yet built. Props: stepNumber.
<HelmAirgapInstallAssets />: Helm air gap installation commands. Props: stepNumber, registryAvailability, charts (optional), exclude (optional).
When a customer selects limited or no registry access, <HelmAirgapInstallAssets /> automatically includes browser download links for Helm chart tarballs. These links are also shown in the update flow for customers in the same registry mode.
<KotsInstallAssets />: Renders the full online or proxy KOTS existing-cluster installation command sequence. Generated commands can include:
--license-file ./license.yaml--app-version-label--namespacewith the application slug when the slug is 63 characters or fewer- On non-stable channels, the install positional
appSlug/channelSlug - When proxy is selected,
--http-proxy/--https-proxy/--no-proxyon the install line, andcurl -x <proxy>on the CLI download
--shared-password is omitted so KOTS prompts for the Admin Console password instead of printing a secret on the page.
Props: stepNumber (optional, starting step number).
<KurlInstallAssets />: Renders the full online or proxy kURL installation command sequence. When proxy is selected, the generated command uses curl -x <proxy> for the installer download and prefixes HTTP_PROXY/HTTPS_PROXY onto the sudo bash. Props: stepNumber (optional, starting step number).
<KotsAirgapInstallAssets />: Renders KOTS air gap download steps for the selected release. This component does not generate push-images or kots install --kotsadm-registry commands with customer registry credentials. The default KOTS page documents that air gap procedure in markdown instead. Props: stepNumber.
<KurlAirgapInstallAssets />: Renders kURL air gap installation steps. The first step includes artifact download links. The following step extracts the installer and runs install.sh airgap. Props: stepNumber.
<KotsInstallStep>: Renders one online KOTS install step by name. Props: step (required), stepNumber (optional). Use step="install_kots".
<KurlInstallStep>: Renders one online kURL install step by name. Props: step (required), stepNumber (optional). Use step="install_kurl".
<KotsAirgapInstallStep>: Renders one KOTS air gap download step by name. Props: step (required), stepNumber (optional). Use step="download_assets". step="download" is an alias for download_assets.
<KurlAirgapInstallStep>: Renders one kURL air gap install step by name. Props: step (required), stepNumber (optional). Use step="download_assets" or step="install_kurl".
For <KotsInstallStep>, <KurlInstallStep>, and <KurlAirgapInstallStep>, step="install" selects install_kots or install_kurl. <KotsAirgapInstallStep> only has download_assets, so step="install" has no target there.
<KotsDownloadAssets />: Renders a KOTS downloads section with a version picker for the selected release. Available when the customer's license has the KOTS install type. The KOTS CLI and optional Preflight and Support Bundle CLIs appear even when air gap is disabled. The Admin Console bundle and the application air gap bundle appear only when air gap is enabled, and only when cliOnly is not set. This component does not render install commands. Do not move the air gap mount out of <WhenNetwork mode="airgap"> to put CLIs on the online branch. A customer who has air gap on the license but selected online would then see those bundles as required. Use a second mount with cliOnly={true} on the online/proxy branch instead (the default KOTS page does this). Props: stepNumber, cliOnly (optional).
<KurlDownloadAssets />: Renders a kURL downloads section with a version picker for the selected release. Available when the customer's license has the kURL install type. Optional KOTS, Preflight, and Support Bundle CLIs appear even when air gap is disabled. The kURL installer bundle (air gap tarball) and the application air gap bundle appear only when air gap is enabled, and only when cliOnly is not set. This component does not render install commands. Props: stepNumber, cliOnly (optional).
<WhenNetwork>: Shows or hides child content based on the customer's Network Availability selection. Use this to keep online generated commands and air gap documentation on the same page. Accepted mode tokens are online, proxy, and airgap (comma-separated). With no <NetworkAvailability/> on the page the selection stays "online", so mode="airgap" content never appears. Unrecognized tokens such as "Airgap" or "air-gap" are ignored; in content preview the portal shows an authoring warning listing the accepted modes. Props: mode (required), children.
<InstanceName />: Prompts the customer to name their instance after installation. Renaming updates the service account name and refreshes the install commands on the page.
<InstanceName />
Props: title (optional, defaults to "Name Your Instance"), method (optional, "linux", "helm", "kots", or "kurl").
<AdminConsoleUrl />: Displays the admin console URL for Embedded Cluster installations. No props.
<HelmReleaseImages />: Lists all container images included in a Helm release for the selected version. Includes a copy button for the full image list. Props: title (optional, defaults to "Helm images"), emptyText (optional, message when no images are found).
Filtering charts in install instructions
For applications with multiple Helm charts, you can control which charts appear in generated install and update instructions using the charts and exclude props. This lets you create separate install pages or sections for different charts, or hide optional addon charts from the default instructions.
\{/* Only show instructions for specific charts */\}
<HelmInstallAssets charts="core-app, worker" />
\{/* Show all charts except optional addons */\}
<HelmInstallAssets exclude="optional-addon" />
\{/* Chart filtering also works on air gap and update components */\}
<HelmAirgapInstallAssets charts="core-app" />
<HelmUpdateAssets exclude="optional-addon" />
The charts and exclude props accept comma-separated chart names. Use charts to include only the listed charts, or exclude to show all charts except the listed ones.
<InstallStep>: Wraps content in a numbered step container.
<InstallStep stepNumber={1} title="Download the installer">
Run the following command to download...
</InstallStep>
Props: stepNumber, title, optional (boolean).
<Prerequisites>: Styled prerequisites section.
<Prerequisites title="Before You Begin">
- Kubernetes 1.26+
- Helm 3.x
</Prerequisites>
KOTS and kURL installer pages
KOTS and kURL instances already appear on the Instances & Updates page with no setup. Embedded Cluster and Helm instances can expand into generated CLI upgrade steps. KOTS and kURL upgrades are performed in the Admin Console. The <InstancesAndUpdates /> component in the default template renders this page.
The default content template also ships dedicated install pages, already listed in toc.yaml:
- Embedded Cluster:
pages/installation/linux.md - Helm:
pages/installation/helm.md - KOTS existing cluster:
pages/installation/kots.md - kURL:
pages/installation/kurl.md
You do not need to author a KOTS page from scratch. Start from the template page and customize it.
What the default KOTS page contains
pages/installation/kots.md is gated on isKotsInstallEnabled. It includes:
- An installation selector (
<PendingInstallSelector>,<NewInstall>,<InstanceName>) <NetworkAvailability installType="kots" />and<VersionSelector installType="kots" /><LicenseDownload />for every network mode (online and proxy generatedkubectl kots installcommands require--license-file ./license.yaml)- Online and proxy installs: generated commands from
<KotsInstallAssets />, then workstation CLIs from<KotsDownloadAssets cliOnly={true} />, wrapped in<WhenNetwork mode="online,proxy"> - Air gap installs: a documentation-style procedure wrapped in
<WhenNetwork mode="airgap">, including:- Requirements for a private registry and two registry accounts (read-write for
push-images, read-only forkots install). These are the customer's registry credentials, not portal or license credentials. <KotsDownloadAssets />- Installing the downloaded KOTS CLI (not
curl https://kots.io/install) - Example
push-imagesandkots install --kotsadm-registrycommands with documentation placeholders such asREGISTRY_HOST,RW_USERNAME, andRO_USERNAME - Admin Console steps to upload the license and
.airgapbundle
- Requirements for a private registry and two registry accounts (read-write for
The portal generates a command only when every value is something it knows (license, app slug, channel, version, artifact URL). It does not interpolate customer registry hostnames or passwords into generated KOTS air gap commands.
What to customize on the default KOTS page
Common vendor edits:
- Branding and product naming: Replace generic wording with your product name and support contact.
- Admin Console URL: The default air gap procedure uses the port-forward URL (
http://localhost:8800orkubectl kots admin-console). If customers reach the Admin Console through an ingress or load balancer, replace that step with your URL. - Registry conventions: Document your registry hostname or host/namespace pattern, account naming, and any required prep (for example, creating the registry namespace before push).
- Content around
<KotsDownloadAssets />: Put your own steps above and below the download component. PassstepNumberwhen you want the component to own the numbered step chrome, or wrap it in<InstallStep>and omitstepNumberso your surrounding copy owns the numbering. Do not do both. - Online CLI downloads: The default page already mounts
<KotsDownloadAssets cliOnly={true} />on the online/proxy branch. Lead that copy with Preflight and Support Bundle (not curl-dependent). Then cover the fallback. If the customer cannot runcurl https://kots.io/install, they download the KOTS CLI, extract it, renamekotstokubectl-kots, put it on PATH, and run thekubectl kots installline from step 2. Do not enable air gap on the license only to get the KOTS CLI. Do not move the air gap<KotsDownloadAssets />out of<WhenNetwork mode="airgap">. The default KOTS air gap procedure is unchanged.
<InstallStep stepNumber={1} title="Your network and registry rules">
Harbor project, jump host, support contact, …
</InstallStep>
<InstallStep stepNumber={2} title="Download the installation assets">
<KotsDownloadAssets />
</InstallStep>
<InstallStep stepNumber={3} title="Push Admin Console images">
Your REGISTRY_HOST convention, then the docs-style command.
</InstallStep>
kURL installer page
The default pages/installation/kurl.md page provides downloads for entitled air gap customers. Its frontmatter and toc.yaml entry are gated on both isKurlInstallEnabled and isAirgapSupported. For generated online or air gap install commands, add <NetworkAvailability installType="kurl" />, <VersionSelector installType="kurl" />, and <KurlInstallAssets /> (which adapts when Network Availability changes) or a separate <KurlAirgapInstallAssets /> branch, the same way Helm and Embedded Cluster pages use generated install assets. If you ship generated online kURL commands to online-only customers, drop isAirgapSupported from both the page frontmatter visible_when and the toc.yaml entry. The default kURL page is unchanged. If you add <KurlDownloadAssets /> to a page those customers can see, pass cliOnly={true} so they get the optional CLIs without the kURL installer tarball or application air gap bundle.
Update components
<LinuxUpdateAssets />: Renders Linux/Embedded Cluster upgrade instructions for the customer's current instance. For air gap upgrades, includes a registry hostname input for image relocation when the customer uses a private registry. Props: stepNumber.
<HelmUpdateAssets />: Renders Helm upgrade instructions. Props: stepNumber, charts (optional), exclude (optional).
<KotsUpdateAssets />: Renders a single line directing the customer to upgrade this instance in the Admin Console. It generates no CLI commands and no download links, and it ignores stepNumber.
<KurlUpdateAssets />: Renders a single line directing the customer to upgrade this instance in the Admin Console. It generates no CLI commands and no download links, and it ignores stepNumber.
<UpgradePath>: Conditionally shows content based on the customer's current version. Lets you show different upgrade instructions depending on which version the customer is upgrading from.
Props:
| Prop | Description |
|---|---|
fromBelow | Show content only when the customer's current version is below this version |
fromAbove | Show content only when the customer's current version is above this version |
fromBelowOrEqual | Show content only when the current version is at or below this version |
fromAtLeast | Show content only when the current version is at least this version |
All version values must be strict major.minor.patch format (e.g. 2.0.0). A v prefix is stripped automatically. Pre-release suffixes (e.g. 2.0.0-rc.1) are not supported.
Props can be combined to define a version range (AND logic). If the customer has no selected instance or the version can't be parsed, the content is hidden.
Example:
<UpgradePath fromBelow="2.0.0">
## Upgrading from 1.x
Before upgrading to 2.x, you must migrate your database schema. Run:
```shell
./migrate-schema.sh
```
</UpgradePath>
<UpgradePath fromAtLeast="2.0.0">
## Upgrading from 2.x
No manual migration needed. The upgrade is automatic.
</UpgradePath>
In this example, a customer on version 1.5.0 would see the "Upgrading from 1.x" instructions, while a customer on 2.1.0 would see the "Upgrading from 2.x" block.
<MarkUpdateComplete />: Button for the customer to confirm an upgrade is complete. No props.
<ReleaseNotes />: Displays release notes for the target update version. No props.
Portal components
<ReleaseHistory />: Renders a browsable release history timeline with version details and release notes. For air gap releases, each entry shows a build status badge (Ready, Building, Failed, or Not built). Props: limit (optional, max number of releases to show).
<SupportBundleUpload />: Upload interface for support bundles. No props.
<SupportBundleUploadHistory />: Lists previously uploaded support bundles. Props: limit.
<LinuxBundles />: Linux-specific support bundle generation instructions. No props.
<HelmBundles />: Helm-specific support bundle generation instructions. A download link for the support-bundle plugin binary is always included, regardless of registry access settings. No props.
<KurlBundles />: kURL-specific support bundle generation instructions. No props.
<KotsBundles />: KOTS-specific support bundle generation instructions for an existing cluster. No props.
Each of the four support bundle components renders the steps for one installation method and nothing else: no heading and no tab strip of its own. The page is what decides which methods a customer sees. The default template's Support Bundles page wraps all four in a single <Tabs> block, with each tab guarded by the entitlement for that installation method.
<ContactInfo />: Displays the support contact information configured in theme.yaml. No props.
<LicenseDownload />: Renders a button that lets customers download their license file. The button appears only for customers whose license enables Embedded Cluster, KOTS, or kURL installations, which are the installation methods that use a license file. Helm customers do not see it. No props.
<InstancesAndUpdates />: Renders the full instances and updates management page inline. Helm and Embedded Cluster instances can expand into inline upgrade CLI commands. KOTS and kURL upgrades are performed in the Admin Console. No props.
Security components
These components require Security Center to be enabled for the customer and are available for Helm and Embedded Cluster installs only. See Security Center for more information.
<CVEReport />: Displays CVEs by severity, component, and container image for the selected release. For each CVE, the Fixed In column identifies the earliest vendor release that resolves it, when one is available. The report also compares CVE counts with the latest release. Depending on your Security Center settings, the report shows only fixable CVEs or includes a toggle for customers to show all CVEs. When Enable raw CVE scan to be downloadable is enabled, the report also displays Download full CVE report, which downloads the raw Grype scan JSON for the selected release. This download is distinct from the SPDX SBOM available through <SBOMReport />. No props.
<SBOMReport />: Displays SBOM metadata and a download option for the selected release. If no SBOM is available, the component displays an unavailable state. No props.
<SecurityVersionSelector />: Selects the install type and release used by the security reports. For older releases, the component shows active instances and links to their upgrade options. When customers select the latest release, the component identifies active instances on older releases. No props.
Template variables
Enterprise Portal content supports Mustache-style templating with \{\{ \}\} syntax for dynamic rendering. Template variables and MDX components can be used together in the same page.
Available variables
| Variable | Description |
|---|---|
\{\{ app.name \}\} | Your application name |
\{\{ app.slug \}\} | URL-friendly app identifier |
\{\{ customer.name \}\} | Customer's name |
\{\{ customer.email \}\} | Customer's email |
\{\{ customer.id \}\} | Customer ID |
\{\{ channel.name \}\} | Release channel (Stable, Beta, etc.) |
\{\{ channel.slug \}\} | URL-friendly channel identifier |
\{\{ release.version \}\} | Current release version |
\{\{ license.* \}\} | Any field from the license object (e.g. \{\{ license.id \}\}, \{\{ license.expiresAt \}\}) |
\{\{ entitlements.* \}\} | Any entitlement value, built-in or custom (see below) |
\{\{ release.version \}\} depends on the customer having reported an active instance. It may be empty for new customers who haven't installed yet. Consider using \{\{ channel.name \}\} as a more reliable alternative for version-dependent content.
Conditionals
\{\{#if\}\}: Show content when a value is truthy. Supports nesting.
{{#if entitlements.isHAEnabled}}
## High Availability Setup
For production deployments, enable HA mode...
{{/if}}
Values are considered falsy if they are null, empty string, false, "false", "0", or 0. Everything else is truthy.
\{\{#ifEquals\}\}: Show content when a value equals a specific string. Useful for per-customer or per-channel content.
{{#ifEquals channel.name "Stable"}}
You are on the Stable channel. Updates are less frequent but thoroughly tested.
{{/ifEquals}}
{{#ifEquals customer.name "Acme Corp"}}
## Acme-Specific Configuration
Your dedicated endpoint is acme.example.com
{{/ifEquals}}
The comparison value must be quoted (double or single quotes). Supports nesting.
Entitlements
Entitlements are accessible as \{\{ entitlements.<name> \}\} for interpolation and \{\{#if entitlements.<name>\}\} for conditionals. There are two kinds:
- Built-in flags: Set on the license through the Vendor Portal:
isHelmInstallEnabled,isAirgapSupported,isEmbeddedClusterDownloadEnabled,isEmbeddedClusterMultiNodeEnabled,isKotsInstallEnabled,isKurlInstallEnabled,isHelmAirgapEnabled - Custom entitlements: Any that you define (e.g.
isHAEnabled,isEnterpriseEnabled)
Example:
{{#if entitlements.isHelmInstallEnabled}}
## Helm Installation
Follow these steps to install using Helm...
{{/if}}
{{#if entitlements.isHAEnabled}}
## High Availability Setup
For production deployments, enable HA mode...
{{/if}}
Visibility
Use visible_when to control which customers see which content. All conditions must be satisfied (AND logic). To keep a page unpublished for every customer, set hidden: true in the page frontmatter. hidden is not a license or entitlement gate. See Hide unpublished pages.
Navigation visibility (toc.yaml)
Apply visible_when on any navigation item in toc.yaml:
- title: Enterprise Features
page: pages/enterprise.md
visible_when:
entitlements:
- isEnterpriseEnabled
channel:
include: [Stable, Beta]
exclude: [Internal]
customer_type:
include: [paid]
All three filter types (entitlements, channel, and customer_type) are fully evaluated server-side. Unrecognized filter dimensions are rejected (fail closed).
To hide a page entirely, you can also omit it from toc.yaml. Pages not listed in the TOC are not reachable through navigation or direct URL (see Table of contents above). To keep the page listed in toc.yaml but unpublished, use hidden: true in the page frontmatter instead.
Per-user permissions in visible_when
In addition to license entitlements, you can gate content on per-user permissions by referencing them in the entitlements list:
- title: Security Reports
page: pages/security.md
visible_when:
entitlements:
- canViewSecurity
The following permissions are available:
| Permission | Description |
|---|---|
canViewSecurity | Can view Security Center (CVE reports, SBOMs). Resolves based on the customer's Security Center entitlement. |
canInviteUser | Can invite users to the portal team |
canRemoveUser | Can remove users from the portal team |
canManageServiceAccts | Can create or revoke service accounts |
canUploadBundles | Can upload support bundles |
Permissions are folded into the entitlements namespace, so they work in both visible_when conditions and \{\{ entitlements.canViewSecurity \}\} template expressions. Currently, canViewSecurity is the most useful permission for content gating because it resolves based on whether Security Center is enabled for the customer. The other four permissions resolve to true for all portal users.
Custom license fields in visible_when
In addition to built-in entitlements, you can use your own custom license fields in visible_when conditions. Any custom license field you create in the Vendor Portal is automatically available in the entitlements list. This lets you gate content on a per-customer basis using fields you define.
For example, if you create a boolean custom license field called hasAdvancedReporting:
- title: Advanced Reporting
page: pages/advanced-reporting.md
visible_when:
entitlements:
- hasAdvancedReporting
Only customers whose license has hasAdvancedReporting set to true will see this page. Custom license fields also work in template expressions (\{\{ entitlements.hasAdvancedReporting \}\}).
For information about creating custom license fields, see Manage custom license fields.
License type visibility (customer_type)
Use customer_type to show or hide content based on the customer's license type. Valid values are community, trial, and paid.
This is useful when you have different content needs for different tiers. For example, you might show upgrade prompts to trial users, or restrict advanced documentation to paid customers only.
# Show only to paid customers
- title: Production Deployment Guide
page: pages/production-deploy.md
visible_when:
customer_type:
include: [paid]
# Show to trial and community customers
- title: Upgrade to Paid
page: pages/upgrade.md
visible_when:
customer_type:
include: [trial, community]
Like channel, customer_type supports both include and exclude lists.
Page-level visibility (frontmatter)
You can also apply visible_when or hidden: true in a page's YAML frontmatter. visible_when adds a per-page access gate on top of the navigation rules in toc.yaml. hidden: true keeps the page unpublished for every customer.
---
title: Embedded Cluster Installation Requirements
visible_when:
entitlements:
- isEmbeddedClusterDownloadEnabled
---
# Embedded Cluster Installation Requirements
Ensure your environment meets these requirements...
The same entitlements conditions available in toc.yaml work in frontmatter, including built-in entitlements, custom license fields, and per-user permissions. Use this when you want to keep the gating condition on the page itself rather than on its toc.yaml navigation entry.
Frontmatter visible_when is an additional gate, not a replacement for navigation. A page must still be reachable through the navigation (or declared as an overrides target) for a customer to access it directly. A page that is not referenced anywhere in toc.yaml is not accessible, regardless of its frontmatter.
Hide unpublished pages
hidden controls whether a page is published, not who can see it. Use visible_when to show a page to some customers and not others based on their license. Use hidden: true to keep a page out of every customer's portal until you are ready to publish it, regardless of license.
Set hidden: true in a page's YAML frontmatter when the page belongs in your content repo but is not ready for customers yet. For example, stage a product announcement, a new install guide, or a revised section next to your live docs, then publish it by removing the flag when you are ready. Keep the page listed in toc.yaml while it is hidden so the navigation slot is already wired when you publish, rather than leaving the draft in a stray branch or an unwired file you have to remember later. Local preview hides the page the same as production, so it does not appear in the preview sidebar while hidden is set.
Put hidden on the markdown page, not on toc.yaml.
---
title: Q3 announcement
hidden: true
---
Keep the page listed in toc.yaml as a normal page entry:
- title: Q3 announcement
page: pages/announcements/q3.md
Customers do not see the page until you remove hidden or set it to false, then re-sync the content.
hidden: true marks unpublished content. It is not a license or entitlement gate. visible_when for built-in entitlements, custom license fields, and permissions is unchanged. hidden: true takes precedence over visible_when. Even if the customer would pass visible_when, the page stays unpublished. Entitlements cannot unhide it.
If a TOC node has a page with hidden: true, the portal drops that node and its subtree. The subtree includes child pages, nested helm_chart items, and terraform_module items. This is the same ancestor-gating behavior as visible_when on a parent.
A section that is only a title (no page) cannot use hidden. Set hidden on each child page, or use visible_when on the TOC node.
overrides.home cannot restore a hidden page or a child of a hidden parent. To hide the home landing page, set hidden: true on that page.
Omitting a page from toc.yaml still hides it entirely. Use hidden when you want to keep the page in the TOC and publish it later.
If you sync hidden against an Enterprise Portal binary that does not support it, the portal drops unknown YAML keys. After a binary that supports hidden is deployed, re-sync so the flag is stored.
Downloadable assets
You can distribute files (scripts, checklists, configuration templates, etc.) through Enterprise Portal by committing them to an assets/ directory in your content repo.
Repo structure
your-content-repo/
├── assets/
│ ├── deploy.sh
│ └── onboarding-checklist.pdf
├── pages/
│ └── resources.md
└── toc.yaml
Any file committed to the assets/ directory is available for download. There are no restrictions on file type or size beyond what your git hosting provider allows (GitHub supports files up to ~100MB via raw content). Assets are fetched directly from your git repo when a customer clicks a download link, so changes are available as soon as you push.
Linking to assets
Use the \{\{asset "path"\}\} template tag in your markdown to generate a download link:
## Resources
- [Deployment Script]({{asset "assets/deploy.sh"}})
- [Onboarding Checklist]({{asset "assets/onboarding-checklist.pdf"}})
The tag expands to a URL that authenticates the customer via their session and serves the file directly. Assets are version-aware, so each content branch can have its own set of files.
The path inside the tag is relative to the repo root and must start with assets/.
Any asset referenced by an \{\{asset\}\} tag on a page that a customer can see is downloadable by that customer. Asset access is controlled by the visibility of the page that references them, not by the file path or directory structure. A page with hidden: true does not authorize asset downloads. If you need to restrict an asset to specific customers, use template conditionals (like \{\{#ifEquals customer.name\}\}) around the asset reference, or place the asset reference on a page gated with visible_when. See the example below.
Per-customer asset delivery
To deliver different assets to different customers, combine \{\{asset\}\} with template conditionals. The conditional controls which customers see the download link, and only customers who can see the link can download the file:
## Resources
{{#ifEquals customer.name "Acme Corp"}}
- [Acme Deployment Guide]({{asset "assets/acme-deploy-guide.pdf"}})
- [Acme ArgoCD Values]({{asset "assets/acme-argocd-values.yaml"}})
{{/ifEquals}}
{{#ifEquals customer.name "Globex"}}
- [Globex CloudFormation Template]({{asset "assets/globex-cloudformation.yaml"}})
{{/ifEquals}}
{{#if entitlements.isAWSEnabled}}
- [AWS Deployment Script]({{asset "assets/deploy-aws.sh"}})
{{/if}}
- [Onboarding Checklist]({{asset "assets/onboarding-checklist.pdf"}})
In this example, only Acme Corp can download their deployment guide, and only customers with the isAWSEnabled entitlement can download the AWS script. The onboarding checklist is available to all customers because it is not wrapped in a conditional.
This lets you maintain one content repo with assets for all customers. Each customer only sees the downloads that apply to them. Unconditioned assets (like the onboarding checklist) appear for everyone.
This pattern works for any file type: Terraform modules, Argo manifests, Bicep templates, CloudFormation stacks, bash scripts, PDFs, or configuration templates.