JavaScript and security
Your theme runs on the firm's own website, next to clients' accounts and payments, so the platform applies some rules to every theme page.
Content security policy
Every theme page is served with a content security policy. In practice:
| You can | You can't |
|---|---|
Load scripts from your theme's assets/ (script_tag) |
Load scripts from other sites (CDNs, analytics snippets) |
Put JavaScript in a section's {% javascript %} tag (it gets the page's nonce) |
Write inline <script> tags or onclick="…" attributes: they're blocked |
Use inline style attributes and <style> / {% stylesheet %} |
|
Show images and media from any https:// address |
Load fonts from other sites (bundle font files in assets/, or use font_picker) |
Embed https:// iframes (YouTube, Vimeo, maps…) |
|
fetch() URLs on the firm's own site |
fetch() other sites |
| Post forms to the firm's site and to Stripe checkout | Post forms elsewhere |
If something doesn't load, the browser console names the blocked address and the rule.
JavaScript in uploaded themes
JavaScript in your theme (asset files and {% javascript %}) runs on the firm's public site and in previews. It never runs inside the firm's admin, which lives on a different address. The platform can switch theme JavaScript off; if it does, the Themes page says so, script_tag outputs nothing, and the components in Components fall back to their no-JavaScript behaviour. Design your theme to work without its scripts.
Platform scripts
The platform adds a small script and stylesheet of its own to every theme page, through content_for_header. They run animations (Motion and animations), fade in lazy images, show form submit states and, when the theme's Page transitions setting is on, add @view-transition { navigation: auto; }. They carry the page's nonce and run even when theme JavaScript is switched off.
They never hide content without JavaScript, and they turn every animation off for visitors who prefer reduced motion. Keep your own scripts and styles the same way: content must be readable before (and without) any script, and prefers-reduced-motion: reduce should stop anything that moves.
Rendering limits
Each page render is limited to 2 MB of HTML and a fixed amount of Liquid work. Loops over large lists and deeply nested renders can hit the limit: the page then shows an error inside the theme editor, and the Counsel theme's version of the page to visitors. Use limit: on loops ({% for link in linklists.footer.links limit: 6 %}).
A Liquid error in one section only breaks that section. The theme editor shows the error in its place.
Good practice
escapeeverything you output from settings and objects, except HTML on purpose (rich text, descriptions).- Use
routes.*for platform pages andformtags for forms. Don't post to platform URLs yourself. - Don't ask visitors for passwords or payment details outside the platform's forms and Stripe checkout.
Still need help?
Send a request to the Mattersimple team and we'll reply by email.