> ## 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.

# Upload an asset

> Images and PDFs, served from usercontent.abtestly.com with an immutable, canonical filename. Per-plan storage budget.

The **Assets** tab on each site is a small file store for the media
your experiments need. Hero images for a variant, a downloadable PDF
for a lead magnet, product shots. Everything you upload gets an
immutable URL you can hard-code into variant JS or CSS.

<Frame caption="Assets tab, upload, storage meter, per-file rows.">
  <img src="https://mintcdn.com/abtestly/pnpJFDTFa50Ks6SL/images/assets-tab.png?fit=max&auto=format&n=pnpJFDTFa50Ks6SL&q=85&s=b0b1450a37acbf774ebb36a6bf876d06" alt="Assets tab" width="2400" height="1141" data-path="images/assets-tab.png" />
</Frame>

## What is accepted

* **Images**, JPEG, PNG, GIF, WebP.
* **PDFs.**

Nothing else. If your variant needs a video, host it somewhere that
does streaming properly and reference the URL, ABTestly is not a
video CDN.

## Per-file cap and per-plan budget

Per file:

* Images: up to 5 MB.
* PDFs: up to 20 MB.

Per site, the storage budget depends on your plan:

* **Free:** 0 (upload disabled).
* **Starter:** 1 GB.
* **Pro:** 5 GB.
* **Business:** 20 GB.
* **Enterprise:** 100 GB.

The Assets tab shows the meter at the top. The budget includes
soft-deleted files, see [Recycle bin](/assets/recycle-bin) for how
to actually free storage.

## Upload

Drag onto the tab or click **Upload**. Runs with a real progress bar
so you know it is doing something.

On upload the file is:

1. Sniffed for its real type (extension is not trusted).
2. Hashed with SHA-256.
3. Deduplicated by content hash within the site. If the same content
   already exists, the existing URL is returned and no new storage is
   used.

## The URL you get back

Every file gets an **immutable, canonical URL**:

```
https://usercontent.abtestly.com/a/<namespace>/<hash>/<filename>
```

* `<namespace>`, a per-site 32-character hex string, isolated from
  other sites.
* `<hash>`, the content hash. A change to content produces a new
  hash and therefore a new URL.
* `<filename>`, canonical filename. A request with the wrong
  filename returns a 308 redirect to the canonical one.

Served with `Cache-Control: public, max-age=31536000, immutable`.
Browsers and CDNs cache forever, because it truly is forever, content
is content-addressed, so a change means a new URL.

## Where the URL is safe

* **Variant JS**, hard-code the URL.
* **Variant CSS**, `background-image: url(https://usercontent.abtestly.com/...)`.
* **PDFs**, reference in a download link.
* **Emails**, public and immutable, safe to send as an image
  reference.

## Dependents lookup

Click a file to see which variants reference it. Substring match on
the URL across every variant's JS and CSS on the site, accurate
enough that you can safely delete a file that shows zero dependents.

## Serving

`Access-Control-Allow-Origin: *`, so images work inline anywhere.
Full URL-shape, cache, and takedown detail on [Serving](/assets/serving).
