📖 When you save a file in the Code Editor, Boost checks the code against a content policy before the save goes through. This article explains what the policy allows, what each error means, and how to write customizations that pass.
⚠️ The Code Editor is available on Boost AI Search & Discovery TURBO with template version 1.6.1 and above. To open it, follow Manage your template: Code Editor.
The rule in one sentence
Code saved in the Code Editor may only make the shopper's browser open, load, or send data to a URL on your own store or on a reviewed list of allowed hosts.
Two rules follow from that:
If the checker cannot tell where a URL goes, the URL is not allowed. For example,
fetch(url)whereurlis a variable.If the checker does not recognize something, it is not allowed. For example, an unknown Liquid tag, an unknown Liquid variable, or a browser API that is not on the reviewed list.
The checker only reads your code. It never runs it and never calls the network.
When the check runs
The check runs when you save a file in the Code Editor.
File | What happens |
| Checked with the JavaScript rules. A violation rejects the save, and the editor lists the issues. |
| Checked with the CSS rules. The save still goes through, and the issues are recorded. |
Any widget | Checked with the Liquid and HTML rules, plus the JavaScript and CSS rules for code inside the template. A violation rejects the save. |
Each save is checked in two steps.
Syntax first. JavaScript, CSS and Liquid are checked for syntax errors. If one of these fails, you see that error and the content policy does not run yet.
Then the content policy. It runs only after step 1 passes.
How a Liquid file is checked
The checker does not look at the file you edit on its own. It builds every widget that Boost publishes and that includes your edit, the same way publishing does, and checks each result. Because of this:
{% settings %}and{% render './x.liquid' %}work in the editor, because publishing resolves them before the check.Variables that a parent widget sets, such as loop variables, are known to the checker.
Each issue names the published widget it was found in, for example Collection header. Liquid issues have no line number, because the line would point into the built widget, which the editor does not show.
One problem can appear once for each published widget that contains it.
A violation in another customized widget inside the same published widget also rejects your save.
Reading an error in the Code Editor
Each issue has a message and a rule ID. JavaScript and CSS issues also have a line and column. Liquid issues name the widget instead.
The start of the message tells you where the URL is, for example fetch, img[src], CSS url(), href write, or CSS @import.
Example message | What it tells you |
| The rule ID is |
| The rule ID is |
The seven rule IDs
Rule ID | What it means, and how to fix it |
| The URL goes to a host that is not your store and not on the allowed hosts list for that kind of use. Typical causes: |
| A link, form, or redirect sends the shopper to another site. Typical causes: |
| The URL uses a scheme other than |
| The checker cannot work out where the URL goes. Typical causes: |
| The code uses something the checker does not allow or does not recognize. Typical causes: |
| The checker could not read the code. Typical causes: a syntax error, or |
| The code is too large or too complex to check. Typical causes: very large files, or very deep nesting. Fix: split or simplify the code. |
URL rules, for every file type
The four kinds of URL use
The checker sorts every URL by what the browser does with it.
Kind | What the browser does, and where it appears |
Navigation | Takes the shopper to the URL. |
Network | Sends a request, which can carry data. |
Resource | Loads a passive file that cannot run code. |
Code-exec | Loads something that can run code or load more files. |
JavaScript el.src = ... and el.href = ... count as code-exec, because the checker cannot know whether el is an <img> or a <script>.
Which hosts pass
Kind | Passes when the host is |
Navigation | Your store. |
Network | Your store, or a host on the allowed hosts list below. |
Resource | Your store, or a host on the allowed hosts list below. |
Code-exec | Your store only. The reviewed code allowlist is empty today. |
⚠️ "Your store" means your .myshopify.com domain. The Code Editor does not pass your custom domain to the checker, so https://www.brand.com/cart.js is blocked. Use a relative path such as /cart.js, which always points to your store.
Allowed hosts list, for network and resource URLs only. A subdomain of a listed host also passes.
Host | Why it is allowed |
| Shopify product images and theme assets |
| Shopify fonts |
| Boost theme CDN, and icon URLs in default settings |
| Country flags in the back-in-stock widget |
Example | Result |
| Passes |
| Passes |
| Passes |
| Blocked: |
| Blocked: |
| Passes |
| Blocked: |
| Blocked: |
Allowed URL schemes
Kind | Allowed schemes |
Navigation |
|
Network |
|
Resource |
|
Code-exec |
|
Relative URLs such as /cart, ?page=2 and #top resolve to your store over https:, so they pass.
Example | Result |
| Passes |
| Blocked: |
| Blocked: |
| Blocked: |
| Blocked: |
| Passes |
| Blocked: |
Building URLs from variables
The checker cannot know the value of a variable. It accepts a URL built from a variable only when the fixed text at the start already decides which site the URL goes to.
A fixed start decides the site when it is one of these:
A path with at least one character after the first
/, such as/products/or/search?q=.A query or fragment, such as
?page=or#.A full
https://host/with a/,?or#after the host.
A bare / is not enough, because the variable could start with / and turn //evil.example into another site.
Example | Result |
| Passes |
| Passes |
| Passes |
| Passes. |
| Passes. |
| Blocked: |
| Blocked: |
| Blocked: |
| Passes |
| Blocked: |
What the checker sees through
The checker decodes text the way a browser does before it judges a URL. These are blocked even though the raw text looks harmless:
HTML entities, for example
<img src="&#x2f;&#x2f;evil.example/x.png">.CSS escapes in function or at-rule names.
Every URL in a list, for example the second URL in
srcset="/a.png 1x, https://evil.example/b.png 2x".Markup printed from a Liquid string.
Absolute URLs in any HTML attribute, for example
<div data-video="https://evil.example/v.mp4">.Tab and newline characters inside a URL, and
user@hosttricks.
JavaScript rules
These apply to customization.js and to JavaScript inside a Liquid <script>, {% javascript %}, or on* attribute. customization.js is checked as a classic script with modern syntax.
Only known global names
A name your script does not declare itself must be on the list of allowed globals. Any other global is blocked, including eval, Function, XMLHttpRequest, Reflect, Proxy, DOMParser, Worker, $ and jQuery.
Type | Allowed globals |
Plain values and helpers |
|
URL calls, where the URL is checked |
|
Timers, where the callback must be a function |
|
Objects, whose members are checked below |
|
Global object |
|
Example | Result |
| Blocked: unknown global |
| Blocked: unknown global |
| Blocked: unknown global |
| Passes |
Objects and URL functions only at the start of a chain
document, location, window, fetch and the other non-value globals may only be used at the start of a.b.c or as a direct call. Storing them or passing them around is blocked.
Example | Result |
| Passes |
| Blocked: global |
| Blocked: member of a global object used as a value |
| Passes |
| Passes |
Browser API members must be on the reviewed list
The checker knows every property and method name that Chrome defines, about 5,000 names. When your code uses one of those names, the name must be on the reviewed list with the right kind of use: read, write or call. Names that Chrome does not define, such as getCarouselConfig or slidesToShow, pass.
⚠️ This applies to every object, including your own objects and classes, because the checker cannot tell which object is which. If you name your own property state, target, x, go, filter or active, it is treated as the browser API with that name. Pick a distinct name instead, such as slideIndex or drawerState.
Example | Result |
| Passes |
| Blocked: Web API member |
| Blocked: Web API member |
| Passes |
| Blocked: Web API member |
Writes that hold a URL, markup or CSS are checked
Write | How it is checked |
| The value is checked as a URL. |
| A fixed string is checked as HTML. A string built from a variable is blocked as |
| The value is checked as CSS. |
|
|
| Writing is always blocked. |
Example | Result |
| Passes |
| Blocked: |
| Blocked: |
| Passes. Use |
| Passes |
| Blocked: |
| Passes |
| Blocked: |
| Blocked: write to origin property |
Clicking and submitting from code is blocked
click(), submit(), requestSubmit() and dispatchEvent() can follow a link or send a form that your theme put on the page. The checker cannot see those URLs, so these calls are always blocked as unresolvable navigation.
To move the shopper to another page, write location.href = '/path' with a store path.
Other JavaScript rules
Rule | What passes and what does not |
| Only on your own functions. |
| The tag must be fixed text and one of |
Computed property names | Reading |
Timers | The callback must be a function. |
Modules | Dynamic |
Boost widget integration customizations
The standard pattern for extending the Boost widget integration passes the policy. For example, overriding RecommendationAPI through window.boostWidgetIntegration.onBeforeAppBootstrap and window.boostWidgetIntegration.extend('RecommendationAPI', ...) is allowed.
The code inside your overridden methods is still checked with every rule above. A fetch to a host that is not allowed is still blocked, and your own method and property names still follow the browser API rule, so avoid names such as state or x.
CSS rules
These apply to customization.css, <style>, style="" and {% css %}. CSS inside a Liquid file follows that file's rules, so a violation there rejects the save.
Example | Result |
| Passes |
| Passes |
| Blocked: |
| Blocked: |
| Blocked: |
| Blocked: |
| Passes |
| Blocked: |
| Blocked: |
| Blocked: |
Liquid and HTML rules
These apply to widget .liquid files.
Allowed Liquid tags
if, elsif, else, unless, case, when, for, break, continue, assign, capture, comment, raw, liquid, echo, render, css, javascript, style, stylesheet.
Any other tag, such as include or section, is blocked as an unknown Liquid tag.
Known Liquid variables
Every {{ variable }} must be a variable the checker knows. A variable is known when your template sets it with assign, capture or for, or when it is on the reviewed list. Anything else is blocked as an unknown Liquid value.
The list also sets how far each variable is trusted:
Trust level | Variables, and where they may go |
Store host |
|
Store path |
|
Path segment |
|
Platform image or file |
|
Merchant-entered settings |
|
Display data |
|
Example | Result |
| Blocked: unknown Liquid value |
| Passes |
| Passes |
| Passes |
| Passes |
| Passes |
Filters
Filters change how far a value is trusted. Any filter not listed here is blocked.
Filter group | Filters, and their effect |
Keep trust |
|
Join |
|
Rewrite |
|
Display |
|
JSON |
|
Default |
|
Platform file |
|
Where {{ ... }} may appear
Position | Allowed? |
Text between tags, | Yes |
Inside a quoted attribute value, | Yes. In a URL attribute, the URL rules apply. |
Inside a string in | Yes |
As JSON in | Yes |
Directly in | No |
Inside a start tag, | No |
Unquoted attribute value, | No. Add quotes. |
Inside an HTML comment | No |
Where if, unless, case and for may appear
They may appear in text, between attributes, and inside a quoted attribute value. Every branch must end in the same HTML position where it started.
Example | Result |
| Passes |
| Passes |
| Blocked: branches end in different HTML contexts |
| Passes, because the start |
| Blocked. Put the whole |
HTML attributes that hold URLs
Kind | Attributes |
Navigation |
|
Network |
|
Resource |
|
Code-exec |
|
Catch-all | Any other attribute whose value starts with a scheme or |
Blocked elements
Element | Why |
| Changes where every relative URL on the page goes |
| Can redirect the page |
| The browser reads their content in a way the checker does not model |
| Same reason |
Inside | Same reason, or they can load or change URLs. Plain |
| Not modeled |
Code inside a template
Where | Rules used |
| JavaScript rules |
| Skipped |
| Liquid and HTML rules |
| Blocked |
| JavaScript rules |
| CSS rules |
| CSS rules for declarations |
| JavaScript rules |
| Liquid and HTML rules |
Feel free to reach out to our dedicated support team via chat if you have any questions or require additional assistance.
