> ## Documentation Index
> Fetch the complete documentation index at: https://docs.abtestly.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Code check

> A static review of your variation JavaScript and CSS that runs on every publish, save, and resume. Warn only: it flags common mistakes but never blocks a publish.

Because you write real JavaScript and CSS for a variation, ABTestly
reads that code back and points out the mistakes that quietly break
experiments. It is a plain static review, the same kind of pass a
linter runs, and it happens on ABTestly's side every time you publish
or save.

It is **warn only**. Code check never blocks a publish. It tells you
what it found and leaves the decision to you.

<Frame caption="Code check on an experiment: persistent Issues above, Suggestions below, each grouped by variation and pointing at the line it found.">
  <img src="https://mintcdn.com/abtestly/MaMkeCmV9H2wUcUm/images/code-check-panel.png?fit=max&auto=format&n=MaMkeCmV9H2wUcUm&q=85&s=b19c8aad083df11ac548419ffba055dc" alt="Code check panel showing Issues and Suggestions grouped by variation" width="1466" height="1119" data-path="images/code-check-panel.png" />
</Frame>

## When it runs

Code check runs whenever your variation code could have changed:

* When you **publish** or republish an experiment.
* When you **save** a draft, a paused, or a live variation.
* When you **resume** a paused experiment.

It does not run on pause, archive, or a plain results refresh, and it
never runs on your live site or in a visitor's browser. It reads the
code you saved, not the page your visitors load.

## Two tiers: Issues and Suggestions

Findings come in two levels.

### Issues (safety)

Issues are the things most likely to actually break the experience for
a visitor. They **persist**: an issue stays on the experiment until the
code no longer triggers it, and each one shows how long it has been
open, so a real problem cannot scroll away and be forgotten. Examples:

* An `eval()` that a strict Content Security Policy will block.
* A `querySelector` result used without a guard, which throws when the
  element is not on the page yet.
* Variation code or CSS that hides the whole page.
* A `setInterval` that is never cleared.
* A syntax error.

<Note>
  When a source has a syntax error, code check reports the syntax error
  and holds that source's other open issues in place rather than marking
  them resolved, since it could not fully read the file.
</Note>

### Suggestions (quality)

Suggestions are lower severity nits. They are worth tidying but they
will not break a visit. Suggestions show alongside your saved code and
can be dismissed for the session. Examples:

* `var` where `const` or `let` would read better.
* `==` where `===` avoids a type coercion bug.
* An unused variable, or a variable declared twice.
* A listener added per element on a page that rebuilds its DOM, where
  one delegated listener on `document` would survive the rebuild.
* A redirect inside variation code, which a Split URL test should
  handle instead.

## How findings are shown

* Findings are **grouped by variation**, so you read each variant's own
  list.
* Each finding points at a **line and column** in the JavaScript or CSS
  pane.
* The panel **survives a page refresh**. Issues stay until they are
  fixed; a Suggestions panel you dismissed comes back on your next
  visit.
* A rule that fires on several lines is counted per line, so the header
  count matches the rows you see.

## What it checks

Code check looks for a fixed set of patterns across variation JavaScript
and CSS, more than forty in total. It is a set of heuristics: it checks
for the specific mistakes below rather than claiming to catch every
possible bug. Each row is the exact message the panel shows, in the same
two tiers the panel groups them into.

### Issues (safety)

**JavaScript**

| Check                                  | Message shown in the panel                                                                                                                       |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| Unreachable code                       | This code can never run, because the statement above always exits.                                                                               |
| `eval()`                               | eval() breaks on sites with a strict Content Security Policy. Run the code directly instead.                                                     |
| Function built from a string           | Building a function out of a string breaks on sites with a strict Content Security Policy. Write the function directly.                          |
| String passed to `setTimeout`          | Passing a string to setTimeout() runs it like eval() and breaks on sites with a strict Content Security Policy. Pass a function instead.         |
| `document.write()` after load          | document.write() after the page has loaded wipes the page. Use insertAdjacentHTML on an element instead.                                         |
| `javascript:` URL                      | javascript: URLs are blocked by Content Security Policy. Attach a click handler instead.                                                         |
| Duplicate object key                   | This object sets `count` more than once, so the first value is silently lost.                                                                    |
| Duplicate `switch` case                | This case value is already handled above, so this branch never runs.                                                                             |
| Unguarded `querySelector`              | This element may not exist when the code runs, because querySelector() can return null. Guard it with ?. or an if check.                         |
| Modifying a native prototype           | Experiment code must not modify Array.prototype, because it changes behavior for the entire site.                                                |
| JavaScript that hides the page         | Variation code should not hide the whole page. Use the platform anti flicker option instead of hiding html or body.                              |
| Comparing with `NaN`                   | Nothing equals NaN, not even NaN, so this comparison is always false. Use Number.isNaN() instead.                                                |
| Impossible `typeof` value              | "strign" is not a value typeof can return, so this comparison is always false.                                                                   |
| Loop that can never stop               | This loop condition is always true, so the loop can hang the visitor's page.                                                                     |
| Assignment inside a condition          | This condition assigns a value instead of comparing one. Did you mean === rather than = ?                                                        |
| `setInterval` id discarded             | The interval id is discarded, so this interval can never be cleared.                                                                             |
| `setInterval` never cleared            | No matching clearInterval() was found for this interval, so it may keep running on the page.                                                     |
| Insecure `http://` subresource         | This http\:// URL is blocked as mixed content on an https page, so the resource will not load. Use https.                                        |
| HTML built from a URL or storage value | Building HTML from a URL, cookie, or storage value can inject unexpected or unsafe markup. Set textContent instead, or sanitize the value first. |

**CSS**

| Check                   | Message shown in the panel                                                                                         |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------ |
| CSS that hides the page | Variation CSS should not hide the whole page. Use the platform anti flicker option instead of hiding html or body. |
| Insecure `http://` URL  | This http\:// URL is blocked as mixed content on an https page, so the resource will not load. Use https.          |

### Suggestions (quality)

**JavaScript**

| Check                                     | Message shown in the panel                                                                                                                                                                                 |
| ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `alert`, `confirm`, or `prompt`           | alert() blocks the page in the middle of the experiment. Show a message inside the page instead.                                                                                                           |
| Fragile selector                          | Selector ".sc1a2b3c" appears tied to generated or positional markup and may break after a site deploy.                                                                                                     |
| Redirect inside variation code            | Redirecting inside variation code can loop if the destination also matches this experiment. Use a Split URL test instead.                                                                                  |
| `${...}` in a plain string                | Text in normal quotes does not fill in `${...}`, so visitors will see the literal text. Use a template literal in backticks.                                                                               |
| `debugger` statement                      | debugger pauses the page for any visitor browsing with devtools open. Remove it before publishing.                                                                                                         |
| `var` instead of `const` or `let`         | Prefer const for values that never change, and let for values that do.                                                                                                                                     |
| Loose equality (`==` or `!=`)             | == converts types before comparing, which hides bugs. Use === instead.                                                                                                                                     |
| Empty `catch` block                       | An empty catch hides failures, so the variation may silently do nothing. Consider reporting or handling the error.                                                                                         |
| Unknown global                            | `tippy` is not a known browser or attached library global. Make sure the page defines it before this variation runs.                                                                                       |
| MutationObserver not stored               | This MutationObserver is never stored, so it can never be disconnected.                                                                                                                                    |
| MutationObserver not disconnected         | No matching .disconnect() was found for this MutationObserver, so it may keep running on the page.                                                                                                         |
| Insert without a duplicate guard          | This variation inserts markup (insertAdjacentHTML) but no duplicate guard was found. If the variation reapplies, the element may be inserted more than once.                                               |
| Variable declared twice                   | `count` is declared more than once.                                                                                                                                                                        |
| Unused variable                           | `count` is never used and can be removed.                                                                                                                                                                  |
| `let` that could be `const`               | This value never changes, so it can be a const.                                                                                                                                                            |
| Listener added inside a loop              | This adds a new listener to the same target on every loop pass, so handlers will fire multiple times.                                                                                                      |
| One listener per element                  | If the site rebuilds these elements, common on React and Vue pages, listeners attached one by one are lost. One listener on document that checks event.target survives rebuilds.                           |
| Styling elements one by one               | Styling many elements one by one is fragile on pages that rebuild their content. Put this styling in the CSS tab instead, where one rule covers them all.                                                  |
| Library loaded from a CDN                 | This loads a library from a third party CDN at runtime. Attaching it as a Dev Library instead keeps it versioned and served with your snippet.                                                             |
| Observer that mutates in its own callback | This MutationObserver changes the DOM inside its own callback without disconnecting first, which can retrigger the observer in a loop. Disconnect before mutating, or guard against running again.         |
| Global listener not removed               | This listener on document is added inside your onApply callback, so it stacks every time that callback runs on an SPA route change and the handler fires multiple times. Remove it before adding it again. |

**CSS**

| Check                                    | Message shown in the panel                                                                                                          |
| ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| Fragile selector                         | Selector ".sc1a2b3c" appears tied to generated or positional markup and may break after a site deploy.                              |
| `!important`                             | !important can make variation cleanup and interaction with the site's existing styles harder to reason about.                       |
| `transition: all`                        | Transitioning every property can cause unnecessary layout and paint work. Specify the properties being animated instead.            |
| Extreme `z-index`                        | This z-index is far higher than the site's stacking order needs. Prefer a value that slots into the site's existing stacking order. |
| Large fixed width                        | This fixed width of 1200px may break on smaller screens. Consider a max width or responsive units instead.                          |
| `100vw` width                            | 100vw includes the scrollbar width on some platforms and can cause horizontal overflow. Consider 100 percent instead.               |
| `pointer-events: none` on a broad target | Setting pointer events to none on a broad target can make page content unclickable. Scope this to a specific element instead.       |
| Broad selector                           | Selector "\*" may affect elements outside the intended experiment area.                                                             |
| `@import`                                | @import blocks rendering while it fetches. Put the styles here directly, or attach the stylesheet as a Dev Library.                 |

Where a message names a specific value, like a selector, variable, or
size, the panel fills in the real one from your code. The values shown
here (for example `count`, `.sc1a2b3c`, and `1200px`) are placeholders.

## It never blocks your publish

This is the point worth repeating. Code check is a second set of eyes,
not a gate. Even with open issues, your experiment publishes when you
publish it. The findings are there so a mistake is caught before it
reaches visitors, not to stand between you and shipping.

<Warning>
  Code check catches common mistakes. It is a set of heuristics, not a
  guarantee, and it cannot know your site's markup. Treat a clean panel
  as one fewer thing to worry about, not as proof the variation is
  correct. Preview and QA on your own site before you rely on a result.
</Warning>

## What code check is not

* **It is not AI.** It reads your code the way a linter does, with a
  fixed set of rules. Nothing is sent to a model.
* **It does not run on your live site.** It analyzes the code you
  saved, on ABTestly's side. It does not load your pages, execute your
  code, or test your selectors against the running site.
* **It is not a blocker.** Warn only, always.

## Related

<CardGroup cols={2}>
  <Card title="Variations" href="/build/variations">
    Write the JavaScript and CSS that code check reviews.
  </Card>

  <Card title="Preview and QA" href="/preview/preview-modal">
    Force a variant and check it on your own site before you launch.
  </Card>
</CardGroup>
