Skip to main content
Run your own JavaScript on every page of your site and control which origins your pages may load code from. To send visits to Google Analytics 4, PostHog, Plausible or Umami, use an analytics integration instead, which needs no script.

Custom scripts

Every .js file outside the content folders runs on every page, whether it’s script.js, a file in a scripts/ folder or a file like analytics.js at the root. They’re the JavaScript counterpart to custom CSS, while a .js file in snippets/, blog/ or changelog/ is a component you import instead.
Notra loads every script on every page with defer from your site’s own address, and the scripts run in the order shown above after the browser parses the HTML.
  • These files are plain browser JavaScript rather than modules, so import and export don’t work in them, and you load a library from another host with document.createElement("script") and add that host to allowedOrigins.
  • The build checks the syntax without running your scripts, and a syntax error fails the build with the file name and line number.
  • Your MDX can’t import these files, so for a component, use a snippet in snippets/ instead.
scripts/external-links.js

Content-Security-Policy

Notra builds a Content-Security-Policy header for every page from your repository, and it decides where scripts can load from and which servers they can connect to.
  • Scripts can come from your site, the analytics integrations you turned on and your allowedOrigins. Notra hashes every inline script that was on the page at build time into the policy, so the browser blocks any inline script injected later.
  • Connections from fetch, beacons and WebSockets may go to your site, your integrations and your allowedOrigins.
  • The policy doesn’t limit images, styles, fonts, videos and embeds, so posts can still show images and videos from anywhere.
If your custom scripts or components load code from another host or call an API, add that origin:
blog.json
Origins must start with https:// or wss:// and have no path, and https://*.example.com covers every subdomain. A wss:// origin only allows connections rather than scripts, and you can list up to 32 origins. To turn the policy off, set contentSecurityPolicy to false:
blog.json
If a script doesn’t run, open your browser’s developer console, where each request the policy blocked shows the origin you need to add to allowedOrigins.
Last modified on October 9, 2026