Skip to main content

Docusaurus

Toggly’s Docusaurus plugin lets you control the visibility of sections, links, and pages of your documentation instantly—no redeploys required—so your docs always match what users can actually access.

Grab the printable Docusaurus cheat sheet (download PDF) — plugin config, page gating, navbar links, edge enforcement.

Quick start​

  1. Install the plugin:
    npm install @ops-ai/toggly-docusaurus-plugin
    # or
    yarn add @ops-ai/toggly-docusaurus-plugin
  2. Add it to docusaurus.config.ts:
    plugins: [
    [
    '@ops-ai/toggly-docusaurus-plugin',
    {
    baseURI: 'https://definitions.toggly.io',
    appKey: process.env.TOGGLY_APP_KEY ?? 'YOUR_APP_KEY',
    environment: process.env.TOGGLY_ENVIRONMENT ?? 'Production',
    flagDefaults: {}, // optional fallbacks
    isDebug: process.env.NODE_ENV === 'development',
    },
    ],
    ];
  3. Restart npm start so the plugin loads the new configuration.

Browser crypto bundling​

If the browser build cannot resolve crypto from the signature verifier, add a local webpack configuration plugin to docusaurus.config.ts. The SDK uses native WebCrypto in browsers; only its guarded Node branch needs Node's crypto module.

Define this plugin above your existing configuration object:

import type { Plugin } from '@docusaurus/types';

function browserCrypto(): Plugin {
return {
name: 'toggly-browser-crypto',
configureWebpack(_config, isServer) {
return isServer
? {}
: { resolve: { fallback: { crypto: false } } };
},
};
}

Add browserCrypto alongside the Toggly plugin in your existing plugins array:

plugins: [
browserCrypto,
['@ops-ai/toggly-docusaurus-plugin', {
appKey: process.env.TOGGLY_APP_KEY,
environment: process.env.TOGGLY_ENVIRONMENT ?? 'Production',
flagDefaults: {},
}],
],

The isServer check preserves Node crypto for server rendering. The browser fallback does not provide a polyfill or disable verification; configure verifySignatures: true on your browser provider or core client when evaluating signed definitions. Serve the browser application over HTTPS or localhost so WebCrypto is available. Run npm run build after applying the configuration.

See Docusaurus's configureWebpack lifecycle API and webpack's resolve.fallback. Keep any existing plugins and configuration entries when adding this browser-only setting.

Initial browser targeting​

Pass known user context when mounting the provider. For a standalone client, pass the same fields to createTogglyClient from @ops-ai/toggly-client-core.

import { TogglyProvider } from '@ops-ai/toggly-docusaurus-plugin/client';

<TogglyProvider config={{
appKey: 'your-app-key',
identity: 'user-123', // Stable browser-user identifier.
groups: ['beta'], // Memberships used by targeting rules.
claims: { plan: 'pro' }, // String rule attributes.
}}>
<App />
</TogglyProvider>

The client captures context before the first request. A client retains its own context and evaluated cache; remount with a new client/provider when the context changes. Omitted identity stays anonymous, and empty groups/claims add no memberships/attributes. Up to 20 nonempty claims are sent; blank groups are omitted.

The same fields in plugin options are public build-time defaults embedded in the browser bundle. They are not per-user authentication or secrets. They do not change static build-time gating or edge-worker evaluation.

Enable the Toggly client-side API and create an App Key​

  1. In Toggly, open your app and go to App Settings. Check Enable Client Side API to allow browser access for the docs.
    Enable client-side API
  2. Click Generate App Key, choose a description, set Type = Frontend, and generate the key for the environment you'll use in the docs.
    Generate App Key
  3. Use that key as TOGGLY_APP_KEY in your Docusaurus config/env, and set TOGGLY_ENVIRONMENT to the matching environment (e.g., Production or Staging).

What it does​

  • Fetches flags server - and client-side so docs can conditionally render content.
  • Exposes a lightweight client for reading flag values in the browser.
  • Gates navbar links using an auto-generated page → feature map, hiding links whose feature flag is off.
  1. Add x-feature: <flag-key> in a doc’s frontmatter. The plugin scans all MD/MDX files, normalizes their routes (drops numeric prefixes, handles index files, prefixes /docs), and builds the route → flag map.
  2. At build time, it injects that map as __TOGGLY_PAGE_FEATURES__ (and on window) automatically.
  3. The client-side gate reads the map and removes navbar/menu links whose feature is false.
  4. If flags cannot be fetched, the gate fails open so links remain visible.
  • TOGGLY_APP_KEY: Your app key from Toggly.
  • TOGGLY_ENVIRONMENT: e.g., Production, Staging, Development.

Notes​

  • Keep flagDefaults minimal; use them only as safe fallbacks in case the API is unavailable.
  • For SSR/edge stripping of gated pages, pair the plugin with your edge worker to strip content when flags are off. Elements marked data-toggly-negate="true" (from <Feature negate>) are left for client hydration.
  • The client-side plugin hides links only in the browser. It intentionally keeps links visible when flags cannot be fetched, so a transient client fetch failure does not make docs navigation disappear.

Feature component (MDX / React)​

Use <Feature> for section-level gating in MDX or React. Set negate for the off path — the same pattern as Next.js and .NET <feature negate>:

import { Feature } from '@ops-ai/toggly-docusaurus-plugin/client';

<Feature flag="beta_advanced_filters">
<h2>Advanced Filters (Beta)</h2>
<p>Shown when the flag is on.</p>
</Feature>

<Feature flag="beta_advanced_filters" negate>
<p>Shown when beta is off.</p>
</Feature>

With an edge worker, positive data-feature wrappers are stripped when the flag is off. Negated wrappers stay in the HTML so hydration matches the client tree.

Edge gating​

Client-side gating hides content from the UI but leaves it visible in the HTML source and reachable via direct URL. To truly prevent disabled content from being served, pair the plugin with the Toggly Docusaurus Edge SDK — a small piece of Cloudflare-side code that:

  1. reads /toggly-page-features.json (which the plugin emits at build time),
  2. fetches the live flag map from Toggly,
  3. returns 404 (or redirects) on requests for pages whose flag is off, and
  4. streams every HTML response through HTMLRewriter to remove [data-feature] blocks for disabled flags before bytes hit the browser (negated data-toggly-negate wrappers are kept for client hydration).

The SDK ships two installation paths. Pick the one that matches where you host the site today.

If your Docusaurus site is already deployed on Cloudflare Pages, drop a single middleware file into the project. No second deploy, no separate domain, no Cloudflare Access service-token to manage, no extra npm deps — the middleware is a single self-contained file.

1. Add the middleware

Copy functions/_middleware.ts from Toggly.FeatureManagement/toggly-docusaurus-edge-sdk/cloudflare/pages-function into your Docusaurus project as functions/_middleware.ts:

mkdir -p functions
curl -o functions/_middleware.ts \
https://raw.githubusercontent.com/ops-ai/Toggly.FeatureManagement/main/toggly-docusaurus-edge-sdk/cloudflare/pages-function/functions/_middleware.ts

The functions/ folder is a Cloudflare Pages convention — every file you put there is auto-bundled and runs at the edge in front of your static assets on the next deploy.

2. Set environment variables

In the Cloudflare dashboard → your Pages project → Settings → Environment variables, add the following for Production (and Preview if you want gating on preview deploys):

VariableRequiredDescription
TOGGLY_API_BASE_URLYeshttps://definitions.toggly.io
TOGGLY_ENVIRONMENTYesMatches the environment you set in docusaurus.config.ts
TOGGLY_APP_KEYYesA Frontend app key from Toggly. Mark as a Secret.
TOGGLY_PAGE_GATE_BEHAVIORNo404 (default) or redirect
TOGGLY_REDIRECT_URLNoRedirect target when behavior is redirect. Defaults to /.

3. Deploy

git add functions
git commit -m "Add Toggly edge middleware"
git push

Cloudflare Pages rebuilds, picks up the new function, and starts applying gating on the next request.

4. Verify

# Hydration snapshot should be present in HTML responses:
curl -s https://docs.your-domain.com/ | grep -o '__TOGGLY_EDGE_FLAGS__.\{0,80\}' | head -1

# A page gated by an OFF flag should now 404:
curl -I https://docs.your-domain.com/<a-gated-page>

Option B — Standalone Cloudflare Worker (for non-Pages origins)​

If your site is on GitHub Pages, Netlify, Vercel, S3 + CloudFront, your own server, or anywhere other than Cloudflare Pages, deploy the standalone Cloudflare Worker in front of it. The Worker fetches HTML from your existing origin and applies the same gating logic.

The Worker source and wrangler.toml template live at Toggly.FeatureManagement/toggly-docusaurus-edge-sdk/cloudflare/worker.

Quick install

git clone https://github.com/ops-ai/Toggly.FeatureManagement.git
cd Toggly.FeatureManagement/toggly-docusaurus-edge-sdk
pnpm install
cd cloudflare/worker
# edit wrangler.toml: set the route pattern + ORIGIN_BASE_URL for your site
wrangler secret put TOGGLY_APP_KEY --env production
wrangler deploy --env production

The Worker needs:

VariableRequiredDescription
TOGGLY_API_BASE_URLYeshttps://definitions.toggly.io (set in [vars])
TOGGLY_ENVIRONMENTYesMatches the environment in your Docusaurus config
TOGGLY_APP_KEYYesFrontend app key (wrangler secret put)
ORIGIN_BASE_URLYesWhere the Worker fetches HTML from (e.g. https://my-docs.netlify.app)
TOGGLY_METRICS_BASE_URLNoUsage/metrics gateway (default https://app.toggly.io/) — not the definitions host
TOGGLY_USAGE_ENABLEDNotrue/false; defaults on when TOGGLY_APP_KEY is set
TOGGLY_METRICS_ENABLEDNotrue/false; defaults on when TOGGLY_APP_KEY is set
CF_ACCESS_CLIENT_IDIf origin is Access-gatedCloudflare Access service-token client ID
CF_ACCESS_CLIENT_SECRETIf origin is Access-gatedCloudflare Access service-token client secret

Usage + metrics (Worker HTTPS telemetry)​

The standalone Docusaurus Worker batches feature check/view usage and business metrics, then POSTs JSON to:

  • {TOGGLY_METRICS_BASE_URL}api/usage/stats
  • {TOGGLY_METRICS_BASE_URL}api/metrics

Workers cannot use native gRPC. Flushes run via ctx.waitUntil after the response path so gating and HTML rewriting stay unblocked. Soft-fail on send errors — pending batches are restored in memory.

wrangler.toml already sets TOGGLY_METRICS_BASE_URL = "https://app.toggly.io/". Opt out per environment:

[vars]
TOGGLY_USAGE_ENABLED = "false"
TOGGLY_METRICS_ENABLED = "false"

The Pages Function path (Option A) does not currently ship the same usage/metrics batcher — use Option B (Worker) or the general Cloudflare Workers integration when you need edge HTTPS telemetry.

Same gateway contract as Next.js edge and the public Cloudflare Workers docs page.

Pages-and-Worker gotcha. If your domain is also a Pages custom domain, removing it from the Pages project (or pointing the Worker at a different origin URL like a Pages branch alias) is required — otherwise the Worker can recurse into itself or be bypassed by Pages. See the Worker README for the routing setup.

Which one should I use?​

Your situationPick
Site is on Cloudflare PagesOption A (Pages Function)
Site is on GitHub Pages / Netlify / Vercel / S3 / your own serverOption B (Worker)
You want the edge transform to be a separate deploy from the static siteOption B (Worker)
You want zero new infra (one repo, one deploy)Option A (Pages Function)

Both runtimes do the same three things — read the manifest, fetch the flag map, and run HTMLRewriter to strip disabled [data-feature] blocks and inject the hydration-safe window.__TOGGLY_EDGE_FLAGS__ snapshot. They just differ in where they run and how they read the static HTML.

Edge cache reliability​

The Docusaurus edge worker preserves the last-known-good page manifest and flag cache when a transient fetch fails. It does not replace a valid cache with an empty fallback just because /toggly-page-features.json or the Toggly definitions endpoint was temporarily unavailable.

This keeps edge gating predictable:

  • disabled pages continue to be stripped or 404'd using the last valid data;
  • temporary upstream failures do not broaden access by clearing the manifest;
  • temporary upstream failures do not hide every gated page by caching {}.

The worker does not expose an application-level onError callback. Use Cloudflare Worker logs or observability for edge runtime failures. For the shared SDK behavior, see Reliability and Error Handling.

Entity context with the core client​

The plugin's <Feature> component and page/navbar maps accept boolean flags; they do not accept entity props. For a per-block entity check, use the separate @ops-ai/toggly-client-core client and render its boolean result. Entity checks are not evaluated by the edge HTML rewriter.

import { useEffect, useState } from 'react';
import { createTogglyClient } from '@ops-ai/toggly-client-core';

type Section = { id: string; audience: string };

export function PremiumBlock({ appKey, section }: { appKey: string; section: Section }) {
const key = JSON.stringify([appKey, section.id, section.audience]);
const [result, setResult] = useState<{
key: string; enabled: boolean; error: string | null;
} | null>(null);

useEffect(() => {
if (!appKey) return;
let active = true;
const client = createTogglyClient({ appKey });
client.registerContext<Section>('DocSection', (item) => ({
kind: 'DocSection', key: item.id,
attributes: { Audience: item.audience },
}));
client.getFlag('PremiumBlock', false,
{ id: section.id, audience: section.audience }, 'DocSection')
.then((enabled) => { if (active) setResult({ key, enabled, error: null }); })
.catch(() => {
if (active) setResult({ key, enabled: false, error: 'Unable to evaluate this section' });
});
return () => {
active = false; // Ignore responses after unmount or a context change.
client.stopWebSocket();
};
}, [appKey, section.id, section.audience, key]);

if (!appKey) return <p>Configure your Toggly app key.</p>;
// Never show an earlier entity's result while the next check is pending.
if (result?.key !== key) return null;
if (result.error) return <p role="alert">{result.error}</p>;
return result.enabled ? <section>Premium content</section> : null;
}

For lists, reuse a core client for one fixed user context and pass each entity to getFlag. Supply known identity, groups, and claims when creating that client; recreate it when user targeting changes. An entity mapper does not change user identity or register a schema with the dashboard. Missing entity context fails closed. UI gating is not a substitute for server-side authorization.

Sample references​

Browse the Toggly Samples catalog for hands-on examples. Start with a sample’s README for setup instructions, then follow its source walkthrough to see how configuration, flag checks, and UI behavior fit together.

Try the Docusaurus showcase and its README. Follow the setup and first-flag exercise, then use the source map to trace native MDX gates, programmatic checks, and Order context.