Twelve buyer questions answered with concrete debug recipes. Each entry has the question + a 2-3 sentence answer + a pointer at the canonical doc OR shipped example. Read top to bottom or jump to the heading that matches your situation.

## What PHP version + OS does the demo need?

PHP 8.1 or newer. The demo backend uses `declare(strict_types=1)`, named arguments, and `nullsafe ?->` operators — older PHP throws fatals at boot. macOS, Linux, and Windows-WSL all work; native Windows works if `php.exe` is on `PATH`. Verify with `php -v`. The shipped engine itself runs in any modern browser; the version constraint is on the demo's PHP backend only.

## Can I use BuilderJS for landing pages, not just email?

Yes. The shipped `default` theme has both — `master/sample/email/*.json` for email templates and `master/sample/page/*.json` for landing pages, checkout flows, thank-you pages. The container width matrix in [Layout best practice](/docs/08-layout-best-practice/) tunes per surface (email 600 / form 480 / page 1200). Buyers building both ship one theme with both sample directories populated.

## How do I add my own theme?

Two scopes. **For one new email** — author a `.json` sample inside `themes/default/master/sample/email/` per [Create a sample](/docs/06-create-sample/). **For your brand identity** — fork `themes/default/` to `themes/<your-brand>/` per [Create a theme](/docs/07-create-theme/). Most projects start with the first; graduate when one sample isn't enough to express the brand.

## How are themes / images licensed?

The shipped `default` theme + every `master/assets/image/` file ship under the BuilderJS commercial licence (you bought it, you can use it). The images are AI-generated — no third-party photographer to credit, no royalty trail to worry about. To replace with your own assets: drop files at the same paths; JSON pointers don't change. The engine source itself is commercial-licensed; the demo wrapper is MIT-licensed (see `LICENSE` files in the ZIP root).

## Which email clients are supported?

The shipped templates are tuned for Litmus's 22-client matrix — Outlook 2007-2024, Apple Mail (macOS + iOS), Gmail web + mobile, Yahoo Mail, AOL, ProtonMail, Thunderbird, and the major mobile clients. The Page template uses table-based layout with MSO conditionals (Outlook-specific) for max compatibility. When you fork the Page template, you inherit those decisions; when you author one from scratch, you'll need to re-tune for your audience. Run a Litmus test on any new template before shipping.

## How do I integrate with my existing auth?

The shipped handlers (`demo/backend/save.php`, `asset-upload.php`, …) start with `BackendAccess::requireWrite()` — the demo's own gate, switched off by default and configured in `demo/backend/config.php`. In your application, replace that line with your auth check. For session-based auth: `session_start(); if (empty($_SESSION['user_id'])) JsonResponse::error('Unauthorized', 401);` at the top of the handler. For JWT: verify the `Authorization: Bearer <token>` header. [Wire a real backend](/docs/13-backend/) walks both patterns; [`examples/backend/3-auth/`](/examples/backend/3-auth/) is the runnable end-to-end.

## The save endpoint returned 500 — how do I debug?

Three places to look. **(1) PHP error log** — usually `/var/log/php_errors.log` on Linux, `/usr/local/var/log/php-fpm.log` on Homebrew macOS. The fatal is logged there. **(2) Browser DevTools → Network tab** — click the failing request → Response tab. The PHP error often renders as the response body (visible only when `display_errors=On` in dev). **(3) Validator output** — if the response is 422 not 500, your validator caught a field. Check the `errors` array in the response.

Most common 500s: DB connection failure (wrong creds), filesystem write failure (`demo/themes/` or `demo/uploads/` not writable by PHP), missing PHP extension (`php-mbstring`, `php-zip`).

## The canvas paints blank after `load()` — what went wrong?

Open DevTools → Console. The engine logs warnings for: unknown element types (a JSON node with `name` not in `ELEMENT_REGISTRY`), missing template keys (a `Countdown.template.html` you forgot to ship), invalid JSON (a stray comma, unclosed brace).

If console is silent, the issue is one of: `dist/builder.js` failed to load (network 404 — re-extract the ZIP), `THEME_TEMPLATES` is `undefined` (your PHP didn't render the inline globals — see [Architecture](/docs/02-architecture/) on the four globals contract), or your `mainContainer` selector matches no DOM element.

## How do I report a bug or request a feature?

Open a support ticket on the [CodeCanyon item page](https://codecanyon.net/item/builderjs-html-email-page-builder/27146783/support) with: extracted ZIP version (from `package.json`), PHP version (`php -v`), the EXACT steps to reproduce, the EXACT output you saw vs expected. Reproducible reports get fixes; vibes-bug-reports stall. For feature requests, include the buyer-facing use case ("my buyers want X because Y") — that drives prioritisation more than abstract elegance.

## How often is BuilderJS updated?

Quarterly minor releases with bugfixes and small features; monthly patch releases for regressions. Major releases ship every 18-24 months with breaking changes telegraphed via deprecation cycle ≥ 6 months. Follow the [BuilderJS item page on CodeCanyon](https://codecanyon.net/item/builderjs-html-email-page-builder/27146783) to get release notifications. The "Verified for vX.Y" chip in every doc footer tells you which version the docs were verified against — when the engine bumps but a doc hasn't been re-verified, the chip flips to a "needs verification" warning.

## How do I migrate saved pages between versions?

Page JSON is **forward-compatible by default** — the engine can load any saved page from a previous minor version. Major-version migrations ship with a one-line transformer in `demo/backend/migrate.php`: `php migrate.php` walks every saved page, applies the v(N-1)→vN transform, writes back. The migration script is idempotent — running it twice on already-migrated pages is a no-op.

## Do I need React / Vue / Angular?

**No.** BuilderJS is pure vanilla JS — no framework dependency. Drop `<script src="dist/builder.js">` into any host page (Laravel, Rails, Next.js, plain PHP, plain HTML) and instantiate `new Builder({...})`. The engine does its own DOM management; it doesn't fight your framework's render cycle. The shipped demo is plain PHP because that's the shortest path to "buyer extracts ZIP + runs"; production hosts swap in their stack.

## Where do I host the uploaded images?

The shipped `demo/backend/asset-upload.php` writes uploads (raster images only — JPEG / PNG / WebP / GIF) to `demo/uploads/` on the same server as the engine. For production: most teams swap this for S3 / Cloudflare R2 / Cloudinary. The handler accepts the multipart upload, streams to your storage, returns the public URL — that's the only contract the engine cares about. [`examples/backend/2-s3/`](/examples/backend/2-s3/) walks the AWS SDK setup; the same pattern applies to any S3-compatible store.

If your assets are sensitive (private SaaS, gated content), keep them behind your auth boundary by returning signed URLs that expire — the engine treats the URL string as opaque, so signed URLs work transparently.

## How do I rate-limit the save / asset-upload endpoints?

The engine retries failed POSTs (429 / 503) with exponential backoff up to 3 attempts. To rate-limit your handler, return 429 with a `Retry-After` header — the engine respects it. For tighter control, swap your save endpoint behind a per-user token bucket (Redis-backed `INCR / EXPIRE` is the lightest implementation) and return 429 when the bucket is empty.

For asset uploads specifically: enforce a per-user MB-quota at the handler. The engine's UI shows the upload-progress percentage by default; failures throw a toast the buyer sees.

## Can I use BuilderJS offline / on-prem / air-gapped?

Yes. The engine bundle (`dist/builder.{js,css}`) doesn't make any outbound network calls — it only POSTs to whatever `saveUrl` / `assetUploadUrl` you configure. The constructor option `loadAssets: false` opts out of the auto-injected Material Symbols + Bootstrap peer-deps so you can self-host those too. Air-gapped deployments work end-to-end; the only network requirement is your own backend reachable from the browser.

The buyer-package itself ships entirely self-contained (no npm install, no CDN, no signup flow) — that's the buyer-zero-deps decision baked into the package layout.

## Did you make it?

You've reached the end of the docs portal. By here you should be able to:

- ✅ Boot the demo end-to-end ([Quickstart](/docs/01-quickstart/)).
- ✅ Read a saved page JSON top to bottom and recognise every node ([JSON structure](/docs/03-json-structure/)).
- ✅ Author a new sample, theme, custom Element, custom Control, custom Widget.
- ✅ Wire a real backend with auth + multi-tenant ([Wire a real backend](/docs/13-backend/)).
- ✅ Ship a locale pack ([i18n](/docs/14-i18n/)).

That's the whole extensibility surface. Anything beyond is engine-source territory — the canonical specs in `docs/core/` cover the rest.

What's next?

- 🔗 [Browse all 15 docs](/docs/) — return to the index for any track.
- 🔗 [Examples hub](/examples/) — 35 runnable code snippets across 7 tiers.
- 🔗 [Gallery](/gallery.php) — 50+ shipped sample previews.
- 🔗 `docs/core/` — engine-internal canonical specs (4800 LOC across STRUCTURE, USAGE, ELEMENT_DEFINITION, CONTROL_DEFINITION, OVERLAY, UI, THEME_BEST_PRACTICE, LANGUAGE, BUILD).

If you've shipped something interesting with BuilderJS — file an issue with the link, we'd love to learn from it.
