A Django Drag and Drop Page Builder You Embed in Your Own Templates
BuilderJS is a framework-agnostic, vanilla-JavaScript drag-and-drop builder for web pages and HTML email that you embed directly inside your own Django project. It is the editor you self-host and own, not a SaaS: there is no monthly fee, no per-seat pricing, and no hosted backend to depend on. Because the engine ships as two static files served from your own origin, the Django integration is deliberately boring — add a script and stylesheet tag to a template, render three container divs, instantiate new Builder({...}) on the client, and persist the canvas by POSTing a single getData() snapshot to one of your own views. Django never renders the editor on the server; it owns the routes, CSRF, auth, persistence, and serving. BuilderJS produces both responsive web/landing-page HTML and Outlook-safe email HTML from the same JSON, and the reference PHP backends port cleanly to a Python view. Try the live editor at builder.emotsy.com.
Mount it
{# templates/builder.html — client-side mount in a Django template #}
{% load static %}
<link rel="stylesheet" href="{% static 'builder/builder.css' %}">
<div id="WidgetsContainer"></div>
<div id="MainContainer"></div>
<div id="SettingsContainer"></div>
<script src="{% static 'builder/builder.js' %}"></script>
<script>
// Containers exist above, so mount immediately (client-side only).
const builder = new Builder({
mainContainer: '#MainContainer',
widgetsContainer: '#WidgetsContainer',
settingsContainer: '#SettingsContainer',
outputMode: 'page', // or 'email' for the Outlook-safe export pipeline
// save config: builder POSTs getData() here, with Django CSRF.
save: {
url: "{% url 'builder_save' %}",
csrf: "{{ csrf_token }}", // sent as the CSRF token on the POST
},
});
// load(themeJson, themeTemplatesJson, themeConfigData, mediaUrl) — 4 args.
// {{ design_json }} is the saved getData() output serialized by your view.
const saved = {{ design_json|default:"null" }};
builder.load(saved, {}, {}, "{% static 'builder/media' %}/");
// Manual save also available: const json = builder.getData();
</script>
{# views.py
from django.shortcuts import render
from django.http import JsonResponse
from django.views.decorators.http import require_POST
import json
def builder_page(request):
design = Design.objects.filter(owner=request.user).first()
return render(request, "builder.html", {
"design_json": json.dumps(design.data) if design else "null",
})
@require_POST # CSRF-protected; builder posts getData() here
def builder_save(request):
payload = json.loads(request.body)
Design.objects.update_or_create(
owner=request.user, defaults={"data": payload.get("data")},
)
return JsonResponse({"ok": True})
#}
A static script in a template — not a pip package, no SSR
BuilderJS is not published to PyPI and there is no Django app to add to INSTALLED_APPS. You copy dist/builder.js and dist/builder.css into your static files, reference them with normal <script> and <link> tags inside a template, and call new Builder once the three container divs exist in the DOM. The constructor takes CSS selector strings for mainContainer, widgetsContainer, and settingsContainer, plus an optional outputMode of 'page' or 'email'. The whole thing runs client-side, so it drops into any server-rendered Django template, a class-based TemplateView, the admin, or an HTMX-driven panel without touching the server render. Collect it like any other static asset with collectstatic.
Persist with getData() to your own Django view
The editor is JSON-first: builder.getData() returns a lossless snapshot of the canvas and builder.load() restores it exactly on the next edit. In Django that means a single path() routed to a view that accepts the JSON, validates it, and writes to a model field, a JSONField, or wherever you keep designs. The save config takes a url and a csrf token, so the builder POSTs through Django's standard CSRF protection — pass the token from {{ csrf_token }} or read the csrftoken cookie. On reopen you serialize the saved JSON into the template and hand it to load(). The data is yours, in your database, behind your own login_required or DRF permissions. BuilderJS has no opinion about routing, auth, or tenancy.
Reference PHP handlers that port to Python
The download includes working reference backends for the three jobs an embedded builder needs: save a snapshot, upload an asset, and authenticate the request. They are plain PHP on MySQL, SQLite, or S3-compatible storage, and the wire contract is just 'accept a JSON body, return a URL or success'. That contract maps directly onto Django: the save handler becomes a view writing to your model; the upload handler becomes a view that stores the file via Django's default_storage and returns its URL; auth is whatever middleware or decorator you already use. You are reimplementing a thin endpoint, not reverse-engineering an SDK — and the same contract works equally in DRF, FastAPI, or a plain Go handler if your stack shifts.
One editor for both email and landing pages
The same mounted builder produces two outputs depending on outputMode. In 'page' mode you get responsive web/landing-page HTML. In 'email' mode an export pipeline rewrites the document to be client-safe: flexbox layouts become nested tables, SVG icons rasterize to PNG, @media rules collapse to mobile-stack, and Outlook MSO conditionals are injected, with a CSS inliner finishing the job. The bundled templates were Litmus-tested across 22 email clients. So a single Django integration can power both a transactional-email template editor and a marketing landing-page editor — you flip one constructor option per use case. BuilderJS builds the markup; bringing an ESP to send the email or a host to serve the page is your app's job.
Own the source with a one-time license
BuilderJS is sold once on CodeCanyon (item 27146783) as Regular $52 or Extended $99 — you own the source, self-host the bundle, and there is no monthly fee, no per-seat charge, no usage metering, and no phone-home. You extend it without forking: register custom Elements, Widgets, and Controls through Builder.registerElement, ship your own themes, and localize with built-in i18n across 20+ locales including RTL. It is multi-tenant capable because each instance is closure-captured, so you can run many editors — but your Django app owns tenant isolation, seats, and billing. Serving both files from your own origin means the editor has no external runtime dependency on a vendor service. Author support is time-boxed (roughly 6–12 months), which is normal for a one-time CodeCanyon license.
Frequently asked questions
-
Is there a pip package or Django app I install?
No. BuilderJS is a DOM-mount bundle (dist/builder.js + dist/builder.css), not a PyPI package, and there is nothing to add to INSTALLED_APPS. You copy the two files into your static files, reference them in a template, and call new Builder({...}) against three container divs. The exact same files work in plain HTML, React, Vue, or Laravel — that is what keeps the editor framework-agnostic.
-
Does the builder run during my Django server render?
No — it is client-side only. Django renders the template and the container divs normally, then the browser instantiates the builder after the DOM is ready. Your Python layer only gets involved at save time, when the editor POSTs its getData() JSON to a view you control. You can put it inside any normal template, a TemplateView, or the admin without special handling.
-
How do I handle Django's CSRF when saving?
Pass the CSRF token into the save config. The Builder constructor accepts save:{ url, csrf }, so render {{ csrf_token }} into the page (or read the csrftoken cookie) and hand it to the builder, which then includes it on its POST. The save view stays a normal CSRF-protected Django view — no @csrf_exempt needed. You keep full control of the route, validation, and which login_required or permission gate protects it.
-
Can I reuse the PHP reference backends from Python?
Yes. BuilderJS ships reference PHP backends for save, upload, and auth on MySQL/SQLite/S3, but they are a convenience, not a requirement. The editor only sends a JSON body (and an HTML string) over fetch, so re-implementing the same save and upload endpoints as Django views is a small job: write the JSON to a model, store uploads via default_storage and return the URL. The wire contract is identical regardless of server language.
-
Does BuilderJS send the email or host the page it builds?
No. BuilderJS is the editor you embed — it builds the email template or page markup, and that is where its job ends. It does not send email, host or publish pages, run funnels, or do CRM and automation. You bring your own ESP to send and your own host to publish. For email, its export pipeline produces Outlook-safe HTML (table layout, MSO conditionals, inlined CSS) that you then hand to your sending platform.