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

# Build & hosting

> How ItemShop builds your site, where it hosts it, and how preview, publishing and rollback work.

Every site change takes the same road: **draft → revision → build → preview deployment → publish**. It doesn't matter whether the change came from the AI editor, an agent over MCP, an upload, GitHub or the CLI.

## Draft and revisions

File changes land first in the **draft** (with the author and time of each change). **Commit the draft** in **Workspace → Changes** to save an immutable **revision** — a numbered snapshot of all files. Revisions are never edited; rolling back means publishing an older deployment. You can see diffs between revisions or the draft in the same tab.

## Build

A build turns the project files into static HTML, CSS and JS. It is queued and runs in an isolated container:

* `npm ci --ignore-scripts` and the manifest's command — package install scripts are **not executed**,
* network only to the npm registry (`registry.npmjs.org`), no access to secrets or shop data,
* 1 vCPU, 1 GiB RAM, a capped process count, no root, a hard time limit of **120 s**,
* the build command in `itemshop.site.json` must be `npm run <script>`, `vite build` or `npx vite build`.

Build status: `queued` → `building` → `ready` or `failed`. On `failed` you see the log (up to 1 MB) — the AI editor can read it and fix the error. Build limits depend on the plan: Free — 1 active build at a time and 10 per hour, Pro — 2 at a time and 30 per hour (`409 SITE_BUILD_BUSY`, `429 SITE_BUILD_RATE_LIMIT`). Builds without a deployment older than 14 days are deleted with their log and output, and unreferenced files after 24 hours.

> [!TIP]
>
> A `static` project (plain HTML/CSS/JS) has no build step and no sandbox — files are published as you upload them. The builder only adds the configuration script to each HTML file.

### Build variables

For `vite-react` projects the builder sets explicit `ITEMSHOP_*` variables — read them in `vite.config.ts` or your code (e.g. for SEO tags). `static` projects have no build step and don't get them.

| Variable | Value |
| - | - |
| `ITEMSHOP_SITE_URL` | The shop's production address (origin, no path): the custom domain or `https://<shop-name>.itemshop.site` — also when the build goes to a preview |
| `ITEMSHOP_SHOP_NAME` | The shop's display name |
| `ITEMSHOP_SHOP_ID` | The shop id |
| `ITEMSHOP_LOCALE` | The default language |
| `ITEMSHOP_CURRENCY` | The shop currency |
| `ITEMSHOP_API_BASE` | The API address (`https://itemshop.dev/api/v2`) |

In the browser, `shopId` and the API address still come from `/itemshop.config.js` — the `ITEMSHOP_*` variables exist only at build time.

### What the builder adds

| Item | Contents |
| - | - |
| `/itemshop.config.js` | `window.__ITEMSHOP__ = { shopId, apiBase, locale, buildId }`, loaded by a `<script>` at the start of `<head>` of every HTML file. The SDK reads it automatically. |
| `/itemshop.data.json` | A snapshot of the shop and products from build time — for SEO and a fast first render. |

## Preview and production

| Deployment | Address | Who sees it |
| - | - | - |
| **Preview** | `preview-<deployment-id>.itemshop.site` | Anyone with the link — not indexed (`noindex`). In the panel the preview is embedded in a frame. |
| **Production** | `<shop-name>.itemshop.site` or your [custom domain](https://andcze.mintlify.site/en/shop/domains.md) | Players. |

The `itemshop.site` domain differs from the panel domain (`itemshop.dev`), so site code never has access to panel cookies. A build can have many previews. Production points to exactly one deployment. Custom domains work as before (TXT / Cloudflare verification), with no extra setup.

## Publishing

**Publish** in the panel (or `itemshop deploy --prod`) points production at the chosen deployment. From an API key, MCP token, the CLI or the AI agent, production is subject to the [publishing rules](https://andcze.mintlify.site/en/site/workspace.md#publishing-rules): with approval required (the default) the response is `403 WORKSPACE_PRODUCTION_REQUIRES_APPROVAL`, so `itemshop deploy --prod` works only after you turn that option off or promote in the panel. A panel session can always publish. Players see the new version after a refresh (HTML documents are always revalidated, files under `assets/` are cached indefinitely).

## Publishing rules

In **Workspace → Deployments** you set how changes reach players:

| Setting | Effect |
| - | - |
| Preview on every commit | Every new revision immediately gets a build and a preview address. |
| Production requires approval | Only what you promote manually goes to production. |
| Auto-deploy from a git branch | A green build from the connected GitHub branch goes straight to production. |

You see the build log live in the same tab.

## Rolling back

A rollback is re-publishing an older deployment: **Workspace → Deployments** → pick a deployment → **Restore**. Nothing is rebuilt, so the change takes seconds. The rolled-back deployment stays in the list, so you can return to it.

## Site security

* Only the static output is hosted — no site code runs on ItemShop servers, and the hosting server answers read requests only.

* Every page carries a **Content-Security-Policy** header that includes:

  | Directive | Allowed |
  | - | - |
  | `script-src` | own origin and `challenges.cloudflare.com` (Turnstile) — no inline scripts |
  | `connect-src` | own origin, the platform API and `challenges.cloudflare.com` |
  | `style-src` | own origin, inline styles and `fonts.googleapis.com` |
  | `font-src` | own origin, `data:` and `fonts.gstatic.com` |
  | `img-src` | own origin, `data:`, `blob:` and any `https:` |
  | `frame-src` | `challenges.cloudflare.com` and `discord.com` (widget) |
  | `object-src`, `base-uri` | blocked / own origin only |
  | `frame-ancestors` | production — itself only; preview — the panel |

* Responses also carry `X-Content-Type-Options: nosniff`, `Referrer-Policy` and COOP. There are no platform cookies on shop domains.

* A blocked or inactive shop returns 404.

> [!NOTE]
>
> So your site must load scripts from its own origin and connect only to its own origin and the ItemShop API. A CDN library or an inline script will be blocked by the browser — add it to the project and build it with the site.

## Through the API

The same flow is available through the API with a key (`site:write`):

```bash theme={null}
# build the draft
curl -X POST https://itemshop.dev/api/v2/shops/<shopId>/site/builds \
  -H "X-API-Key: <key>" -H "Content-Type: application/json" \
  -d '{ "revisionId": "draft" }'

# deploy the build as a preview
curl -X POST https://itemshop.dev/api/v2/shops/<shopId>/site/deployments \
  -H "X-API-Key: <key>" -H "Content-Type: application/json" \
  -d '{ "buildId": "<buildId>", "kind": "preview" }'

# publish (or roll back) a deployment
curl -X POST https://itemshop.dev/api/v2/shops/<shopId>/site/deployments/<deploymentId>/promote \
  -H "X-API-Key: <key>"
```

> **[Limits](https://andcze.mintlify.site/en/site/limits.md)**
>
> Build time, sizes, AI.

> **[Domains](https://andcze.mintlify.site/en/shop/domains.md)**
>
> A custom domain for your site.


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