Skip to content
Wire to production D3 8 min read Reference

FAQ

Twelve questions answered — version, email-client matrix, debug recipes.

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 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. For your brand identity — fork themes/default/ to themes/<your-brand>/ per Create a 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?

Wrap the shipped demo/backend/save.php (and asset-upload.php) 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 walks both patterns; 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/uploads/ not writable — chmod 755 demo/uploads), 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 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 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 (engine v6.X) with bugfixes and small features; monthly patch releases (v6.X.Y) for regressions. Major releases (v7) ship every 18-24 months with breaking changes telegraphed via deprecation cycle ≥ 6 months. Follow the BuilderJS item page on CodeCanyon to get release notifications. The Last verified for v6.X.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 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/ 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).
  • ✅ Read a saved page JSON top to bottom and recognise every node (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).
  • ✅ Ship a locale pack (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 — return to the index for any track.
  • 🔗 Examples hub — 35 runnable code snippets across 7 tiers.
  • 🔗 Gallery — 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.