BuilderJS

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

Explore