Write your own JavaScript and CSS
Add your own code to a test variant, or let AI write it, for changes that text and style edits can't make.
In this article
Most tests only need the visual editor: new texts, links, images and styles. Custom code is for everything else, for example a sticky add to cart bar, a new block with reviews, moving the price above the title, or opening a size guide on click.
Add code to a variant
- Open the test under Optimize → Experiments.
- Scroll to Custom code. Does the test have more than one variant? Pick the variant at the top of the card.
- Choose JavaScript or CSS and type or paste your code. The editor shows line numbers and colors, and marks lines with a problem as you type. Below the editor, Blocked lines must be fixed before you can save; Check lines are worth a look but don't block.
- Choose when the JavaScript runs under Run the JavaScript (see below), and what happens on an error under If the code fails.
- Click Save and check. Varly checks the code on every device and makes new screenshots of the original and the variant. This takes one to three minutes.
You can also open the code from the visual editor on your live page: click Code in the toolbar. There you can click Try on this page to see the result in your own browser right away. Nothing is saved until you click Save, and nothing is measured.
A variant can have only code, only edits from the visual editor, or both. Edits from the visual editor run first, then your code.
Let AI write the code
- Under Describe the change, write what you want in plain words, for example: "Add a bar at the bottom on mobile with the price and the add to cart button, shown after the visitor scrolls past the button."
- Click Write the code with AI. The AI looks at the elements on your page and writes JavaScript, CSS or both into the editor.
- Read the code. Change anything you like.
- Click Save and check.
The AI uses the same rules as you: Varly checks its code the same way, and tells you in plain words if it blocked something. Nothing is saved or launched until you do it. The change history notes that the code was first written by AI.
When the code runs
| Choice | When | Good for |
|---|---|---|
| Right away | As soon as Varly loads, often before the page is fully there. | Code that only adds CSS classes or waits for elements itself. |
| When the page is ready | When the HTML of the page has loaded. This is the default. | Most changes. |
| When an element appears | When an element matching the selector you enter is on the page, also if it comes later. | Elements that load late, such as reviews or a cart drawer. |
CSS is always added right away, before the page shows, so visitors don't see the original flash by.
Helpers you can use
Your code runs inside a function that gets a varly object:
varly.waitFor(selector, callback): callscallbackwith the element as soon as it is on the page, also if it appears later. Use it instead ofdocument.querySelector, so your code never runs too early.varly.track('event_name'): sends a custom event. You can pick it as the goal of the test under What counts as a conversion → Custom event. See Send your own events with Varly.track.varly.onCleanup(() => { … }): runs when the variant stops, for example when a visitor goes to another page in a single-page shop. Remove what you added here.varly.variant: the test and variant the visitor sees, withexperimentId,experimentName,keyandname.varly.preview:truein the preview link and in Varly's check, so you can skip things that should only happen for real visitors.
setTimeout, setInterval and requestAnimationFrame work as usual. Varly catches errors in them and stops them when the variant stops.
Examples
A line of text above the product title:
varly.waitFor('h1', (title) => {
if (document.querySelector('.varly-usp')) return
const line = document.createElement('p')
line.className = 'varly-usp'
line.textContent = 'Free shipping and free returns'
title.before(line)
varly.onCleanup(() => line.remove())
})
.varly-usp { margin: 0 0 8px; font-size: 14px; color: #0f7a3d; }
Move the reviews block above the description, and count clicks on it:
varly.waitFor('#reviews', (reviews) => {
const description = document.querySelector('#description')
if (!description) return
const before = reviews.previousElementSibling
description.before(reviews)
reviews.addEventListener('click', () => varly.track('reviews_clicked'))
varly.onCleanup(() => before?.after(reviews))
})
A sticky add to cart button on mobile:
varly.waitFor('#add-to-cart', (button) => {
if (window.innerWidth > 767 || document.querySelector('.varly-sticky')) return
const bar = document.createElement('div')
bar.className = 'varly-sticky'
const copy = document.createElement('button')
copy.type = 'button'
copy.textContent = button.textContent
copy.addEventListener('click', () => {
varly.track('sticky_add_to_cart')
button.click()
})
bar.append(copy)
document.body.append(bar)
varly.onCleanup(() => bar.remove())
})
.varly-sticky { position: fixed; left: 0; right: 0; bottom: 0; z-index: 50; padding: 12px; background: #fff; box-shadow: 0 -4px 16px rgb(0 0 0 / 0.1); }
.varly-sticky button { width: 100%; padding: 14px; border: 0; border-radius: 999px; background: #17161a; color: #fff; font: inherit; }
What Varly blocks
Varly reads every line before saving and refuses code that could harm your shop or your visitors. You get a short explanation with the line number.
- Running text as code:
eval,new Function, andsetTimeoutwith text instead of a function. - Writing cookies or using
cookieStore. Cookies belong to your site and your cookie banner. - Changing your site's own data in
localStorageorsessionStorage. Your code may read anything, but only write keys that start withvarly_test_, for examplevarly_test_bar_closed. - Sending data to other websites:
fetchto another address,XMLHttpRequest,WebSocket,sendBeacon.fetchto a fixed path on your own site, such asfetch('/cart.js'), is fine. - Loading other scripts:
import(), or addingscript,iframeorobjectelements. document.write, which can wipe the page.- Anything on checkout, payment or cookie elements, password or card fields, and sending forms or changing where a form sends its data.
- In CSS:
@import,http://addresses, and anything that tries to run code.
Some things are allowed but marked Check, such as sending visitors to another page, alert() and reading cookies.
What happens when the code fails
The code runs inside a safety net, so an error never breaks your page. Under If the code fails you choose what happens next:
- Stop the code and keep going (default): the code stops, other changes and the CSS stay.
- Show the original: the visitor sees your normal page for the rest of the visit. They still count in the variant, so the results stay fair.
Either way, Varly logs the error with the test, so you can find it under Research → Analyses as a JavaScript error.
Before you can launch
A test with custom code has two extra checks on the launch checklist:
- A person approved the code. Code you save in Varly counts as approved. Code that an AI assistant saved through a chat (such as Claude or ChatGPT) is a draft: someone with the Owner or Editor role must read it and click I read this code, approve it.
- The check passed. After every change to the code, click Save and check (or Run the check). Varly opens your page on desktop, tablet and mobile, runs the code exactly like for visitors and looks for errors, for the element the code waits for, and for security settings that block it. The Custom code card shows the result, and the screenshots show the real result.
The test card and the experiments list show Uses custom code. Under Change history you see who changed the code, when and where.
Single-page shops
Some shops change pages without reloading, for example many headless and Shopify Hydrogen shops. Varly notices each page change. Is the new page still part of the test? Then Varly runs varly.onCleanup, then your code again. On a page outside the test, or on a checkout page, Varly stops the code and removes its CSS.
Sites with strict security settings
Some sites use a Content Security Policy (CSP) that limits which scripts and styles may run. Your code comes with the Varly script itself, so it doesn't need 'unsafe-inline' or 'unsafe-eval' for scripts. Your site does need to:
- allow the Varly script in
script-src(needed for Varly anyway), and - allow style tags in
style-srcwith'unsafe-inline', without a nonce or hash. Without it, your CSS and Varly's protection against flicker can't run.
Varly's check tells you when your site's security settings will block the test code. When visitors' browsers block it, the Custom code card says "Your site's security settings blocked the test code". Ask your developer to change the policy, or test without custom CSS.
Common problems
- "Pause the test before you change its code." A running test can't change. Pause it, change the code, run the check and resume.
- "Custom code is available for A/B and A/B/n tests." Multivariate and split URL tests don't have custom code. Use the visual editor, or a separate A/B test.
- The check says the element was not found. The selector under When an element appears, or in
varly.waitFor, doesn't match anything on the test page. Check it in your browser's developer tools. - My code works in the preview but not for some visitors. Check the device and browser. Very old browsers can't read modern JavaScript; Varly accepts code up to the 2020 version of JavaScript.
- The code runs twice. In a single-page shop your code runs again after each page change. Check whether your element already exists, and remove it in
varly.onCleanup.
Still stuck? Email support@varly.ai and we'll help you out.
Related articles
- Build a test by selecting parts of your live pageSelect any part of your real page, then describe the change for the AI or edit it directly yourself.
- Preview and check a test before launchOpen the test on your real site, switch between the original and each variant, and share the link.
- Launch, pause, resume and end a testGo through the launch checklist, start with a dry run or go live, and stop a test when you need to.
- Send your own events with Varly.trackCount actions such as a newsletter signup or an add to cart, and use them as the goal of an A/B test.
- Why is my test not showing?The variant doesn't appear on your site? Go through these checks, from status and targeting to consent and flicker.