#3610·MathJax

Self-hosting instructions don't cover font extensions

Author: daniil-bergCreated Sep 15, 2026Updated Sep 17, 2026
LabelsNeeds Documentationv4

Issue Summary

When self-hosting MathJax v4.0, font extensions are still fetched from cdn.jsdelivr.net (even though the main font is configured to load locally). The self-hosting documentation only covers whole font packages via output.font and/or output.fontPath.

The dependency is content-triggered, so it can survive testing and only appear once someone writes e.g. chemistry or blackboard-bold markup.

Steps to Reproduce

  1. Self-host MathJax 4.0.0 plus a local copy of @mathjax/mathjax-newcm-font, and set output.fontPath to it as documented.
  2. Typeset \ce{H2O}.
  3. Observe in the network tab: GET https://cdn.jsdelivr.net/npm/@mathjax/mathjax-mhchem-font-extension/chtml.js

Same for \bbm, \bboldx and \dsfont with their respective extension packages.

The cause seems to be the fontExtension helper:

javascript
export function fontExtension(id, name, pkg = `@mathjax/${name}`) {
  if (MathJax.loader) {
    const FONTPATH = hasWindow ? `https://cdn.jsdelivr.net/npm/${pkg}` : pkg;
    const path = name.replace(/-font-extension$/, '-extension');
    const jax = (MathJax.config?.startup?.output || 'chtml');
    combineDefaults(MathJax.config.loader, 'paths', {[path]: FONTPATH});
    ...
  }
}

I could not find the resulting key names documented anywhere. You can find the config I got working below; the key is the package name with -font-extension replaced with -extension.

I expect the self-hosting documentation to cover font extensions alongside fonts. Sites that self-host specifically to avoid third-party requests (GDPR compliance, in our case a German university, the TU Berlin) are otherwise left with a CDN call they have no reason to expect. The only reason I even caught this, is because our CSP blocked those requests breaking fonts in some tests, which users then reported.

v4.1 seems to introduce a [fonts] prefix which may make this simpler, but it does not exist in v4.0. This whole issue arose on a custom Moodle 5.2 instance, so it is unclear if an upgrade to MathJax v4.1 is even supported.

Technical details

  • MathJax Version: 4.0.0 (self-hosted, @mathjax/[email protected] bundle)
  • Client OS: Debian 13 (trixie)
  • Browser: Librewolf

The following MathJax configuration actually worked:

javascript
MathJax = {
  loader: {
    paths: {
      "mathjax-mhchem-extension": "<our-server>/font-extensions/mathjax-mhchem-font-extension",
      "mathjax-bbm-extension":    "<our-server>/font-extensions/mathjax-bbm-font-extension",
      "mathjax-bboldx-extension": "<our-server>/font-extensions/mathjax-bboldx-font-extension",
      "mathjax-dsfont-extension": "<our-server>/font-extensions/mathjax-dsfont-font-extension"
    }
  },
  output: {
    fontPath: "<our-server>/MathJax/v4.0.0/output/fonts/mathjax-newcm"
  }
};

The loader.paths entries are the undocumented fix. Without them, and with only the documented output.fontPath set, the jsdelivr requests occur.

and loading MathJax via

xml
<script src="<our-server>/MathJax/v4.0.0/tex-mml-chtml-safe.js"></script>

Supporting information

I cannot share a public live example because the affected pages are behind authentication. But you can reproduce this with any self-hosted 4.0.0 install. Set output.fontPath locally, omit the loader.paths entries above, and typeset \ce{H2O}.