Built-in analytics
Every site counts its own visitors and their time on page with nothing to install, and you can turn this off under Settings → Danger zone. Open the site’s Analytics page for people and AI agents on the site, or Traffic in GEO for AI crawlers and referrals across all your domains, while previews never count. See AI agents and search.Analytics integrations
To also send visits to your own analytics tool, add it on the site’s Integrations page or underintegrations in blog.json. The Integrations page saves a draft of blog.json that goes live when you publish it from the editor. Notra adds the provider’s script tag to the <head> of every page and allows its hosts in the Content-Security-Policy.
blog.json
Another tool, such as a chat widget or a tag manager, goes in a custom script.
Previews use the same integrations as your live site, so filter by hostname in your analytics tool to keep previews out of your numbers. Preview hosts look like
pr-7--acme.notra.site.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. These files work like custom CSS for JavaScript, while a .js file in snippets/, blog/ or changelog/ is a component you import instead.
defer from your site’s own address, and the scripts run in the order shown above once the HTML has been parsed.
- Plain browser JavaScript: these files are not modules, so
importandexportdon’t work in them, anddocument.createElement("script")loads a library from another host. - Syntax check only: the build checks the syntax and never runs your scripts, and a syntax error fails the build and shows the file and line.
- No imports from MDX: your MDX can’t import these files, so for a component, use a snippet in
snippets/instead.
scripts/external-links.js
Content-Security-Policy
Every page comes with aContent-Security-Policy header that says where scripts may come from and which servers they may connect to, and Notra builds it from your repository.
- Scripts: they can come from your site, the analytics integrations you turned on and your
allowedOrigins. Notra allows inline scripts only if they were on the page at build time and hashes each of them, so a script injected later doesn’t run. - Connections:
fetch, beacons and WebSockets may connect to your site, your integrations and yourallowedOrigins. - Images, styles, fonts, videos and embeds: the policy doesn’t limit them, so posts can still show images and videos from anywhere.
blog.json
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 entirely:
blog.json