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

# Loading and failures

> How the headless SDK loads your tests, how soon a change reaches your storefront, and what a visitor sees if loading fails.

The SDK loads your active tests from ABConvert before it assigns a visitor. This page covers how long that takes, how fresh the data is, and what happens when it fails.

## How tests load

The SDK fetches your tests and keeps them in memory. Every client you create reuses the copy, so creating a client for each request does not call ABConvert each time.

## How the copy refreshes

The copy is fresh for 60 seconds. The first request after that still uses it, and the SDK fetches a new copy in the background, so no visitor waits on ABConvert. A change you make in ABConvert, such as launching or pausing a test, reaches a server once that fetch is done. A server that had no requests for a while serves its old copy to its next request, however long ago you made the change. Once a visitor has seen a change, every server shows it to them, and fetches the new copy first if it has to, waiting at most your `timeout`.

Change the time with `cacheTtl`, in seconds:

```ts Server theme={null}
const abconvert = await createABConvert({
  shop: 'your-store.myshopify.com',
  storefrontKey: 'abc_pk_4f9c2e7a1b3d5f6e8a0c2b4d6f8e0a1c',
  request,
  cacheTtl: 30,
});
```

To refresh at once, for example right after you change a test or on a schedule, call `refreshTests()`. Each server keeps its own copy, so call it on every server:

```ts Server theme={null}
await abconvert.refreshTests();
```

If a refresh fails, the SDK keeps the last copy it has. If ABConvert no longer knows your storefront key, for example after you revoke it, the SDK drops its copy, your storefront shows the original store, and the SDK asks again after `cacheTtl`.

A [preview link](/headless-sdk/preview) loads a copy of its own, with your Preview tests. A test you just created previews at once: a link to a test that copy lacks fetches a fresh one for that request. The preview copy refreshes in the background like the shared copy, and the first preview page on a server waits up to 10 seconds for it rather than show your original store. If no preview copy arrives in that time, the page shows your live tests instead.

## After you launch, edit, or end a test

Your storefront shows the change within your `cacheTtl` plus your CDN's `s-maxage`, about two minutes with the defaults. Until then, a page can still show the old price:

| Where the old tests can be | For how long |
| - | - |
| The SDK's copy on each server | Up to 60 seconds, or your `cacheTtl` |
| Your CDN | Up to the page's `s-maxage`, for a page it stored before the change |
| Next.js's cached pages | None: a change gives a tested page a new page key, so Next.js renders it again |

Checkout charges the price Shopify has for the test, so for that time a page can disagree with checkout. Your cart can show what checkout charges: see [Show what checkout charges](/headless-sdk/cart#show-what-checkout-charges).

To shorten the time:

* Launch and end tests when traffic is low.
* Clear your CDN's cache for product, collection, and search pages right after the change.
* Call `refreshTests()` on each server right after the change.

## If loading is slow

A request waits for your tests only while its server holds no copy yet, usually the server's first request, and for at most one second. The fetch carries on after that and fills the copy for the next request. Once a server holds a copy, a refresh runs behind the request. A request then waits only when its visitor already saw a newer copy on another server, for at most your `timeout`. Change the limit with `timeout`, in milliseconds:

```ts Server theme={null}
const abconvert = await createABConvert({
  shop: 'your-store.myshopify.com',
  storefrontKey: 'abc_pk_4f9c2e7a1b3d5f6e8a0c2b4d6f8e0a1c',
  request,
  timeout: 500,
});
```

We trade a late test for a fast page: a visitor on a request that timed out sees your original store. A server that starts for each request, such as a serverless function, waits on more of its requests, so raise `timeout` there if `onError` reports timeouts.

## If loading fails

`createABConvert` never throws, with one exception: a client made with `pageKey` on Next.js, described in [Next.js caching and CDN](/headless-sdk/nextjs-caching#when-the-tests-cannot-be-loaded). When your tests cannot be loaded, or loading times out, the client is empty for that request:

| Method | Returns |
| - | - |
| `getAssignment`, `getFeature`, `getPriceByVariantId`, `getPriceByProductId`, `getShippingRates`, `getFreeShippingThreshold`, `getRedirectUrl` | `null` |
| `getAssignments`, `getOffers` | `[]` |
| `getPageKey` | `''` |
| `getCartAttributes`, `getCartLineAttributes` | One attribute that marks the cart as your headless store's, so ABConvert does not count its checkout in any test |

Your storefront then shows the original prices and pages for that request, and the visitor is not counted in any test for it. That response must stay out of shared caches, so your CDN does not store the original page and serve it to visitors in a test group; your stack's caching page shows how it stays `private`: [Next.js](/headless-sdk/nextjs-caching#how-tested-pages-are-cached), [Hydrogen](/headless-sdk/hydrogen-caching). After a failed first load, the server does not ask ABConvert again for 5 seconds, so visitors in that time do not each wait. A cart that already carries test groups keeps them, and checkout charges them: the marker replaces nothing the cart has. Keep writing the cart attributes as usual. See [Connect the cart](/headless-sdk/cart#write-the-attributes).

The same happens when ABConvert serves your tests in a form this release of the package cannot read, on a server that holds no copy yet. A server that already holds a copy keeps using it. `onError` then receives an error that says to update `@abconvert/headless`, and the SDK asks again after `cacheTtl` instead of on every request.

To log failures, pass `onError`:

```ts Server theme={null}
const abconvert = await createABConvert({
  shop: 'your-store.myshopify.com',
  storefrontKey: 'abc_pk_4f9c2e7a1b3d5f6e8a0c2b4d6f8e0a1c',
  request,
  onError: (error) => console.error('ABConvert', error),
});
```

## Common mistakes

* **Wrapping the SDK in your own `try` and failing the page.** The SDK already falls back to the original store. The fix: let the page render.
* **Setting `timeout` very low.** Most visitors then miss the test, and it takes longer to reach a result. The fix: keep the default unless you measure a problem.
* **Setting `cacheTtl` very low.** Every server then refreshes often for no gain, since a test changes rarely. The fix: keep the default, or call `refreshTests()` when you know something changed.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.