An Embeddable Email Editor for Newsletter & Creator Platforms
If you run a newsletter or creator platform, your creators write the words — but they still need somewhere to design the issue: a hero image, a two-column digest, a call-to-action button, a footer. Building that drag-and-drop editor yourself is months of work that has nothing to do with your actual product, and renting a hosted one means a per-seat or per-session bill that quietly grows with every free creator who signs up. BuilderJS is the editor part, ready to embed. It is a framework-agnostic, vanilla-JavaScript drag-and-drop builder that mounts inside any DOM node — React, Vue, Svelte, Angular, Next.js, Laravel, or plain HTML — and renders inside your product, under your domain, with your branding. Your creators design newsletters and signup/landing pages from the same canvas; BuilderJS exports Outlook-safe email HTML through its EmailExportPipeline and clean page HTML for the web. Be honest about the line: BuilderJS is the editor your creators click in, not the platform around it. It builds the markup and hands you lossless JSON; your application owns sending, subscriber lists, billing, analytics, and deliverability. You buy it once on CodeCanyon, get the source, and self-host it — no SaaS subscription, no per-seat fee, no per-session metering, no phone-home. This page explains where BuilderJS fits in a newsletter platform, and just as importantly, where it does not.
Mount it
// React: mount BuilderJS once inside your creator's newsletter editor screen.
// builder.js + builder.css are self-hosted globally (e.g. in index.html),
// which attaches window.Builder. There is NO npm package to import.
import { useEffect, useRef } from 'react';
export default function NewsletterEditor({ creatorDraft, mediaUrl }) {
const mounted = useRef(false);
useEffect(() => {
if (mounted.current || !window.Builder) return; // React 18 Strict-Mode guard
mounted.current = true;
const builder = new window.Builder({
mainContainer: '#bjs-canvas', // REQUIRED — CSS selector string
widgetsContainer: '#bjs-widgets', // optional
settingsContainer: '#bjs-settings', // optional
});
// load(themeJson, themeTemplatesJson, themeConfigData, mediaUrl) — 4 args
builder.load(creatorDraft.themeJson, creatorDraft.templates, creatorDraft.config, mediaUrl);
// Save: const json = builder.getData(); POST json to YOUR route.
// Your worker injects merge tags and pushes the HTML to your own ESP.
// No destroy() exists — React discards the DOM on unmount.
}, [creatorDraft, mediaUrl]);
return (
<>
<div id="bjs-widgets" />
<div id="bjs-canvas" />
<div id="bjs-settings" />
</>
);
}
Why per-seat editor pricing breaks newsletter-platform margins
Newsletter and creator platforms have a specific economic shape: lots of creators, many of them free or low-tier, and revenue that only shows up once a creator grows an audience or upgrades. That shape is exactly where hosted, metered embeddable editors hurt. If the editor in your dashboard bills per active seat or per editing session, your cost scales with sign-ups — not with revenue — so every free creator who opens the editor to try it once becomes a line item. BuilderJS removes that variable entirely. It is a one-time CodeCanyon license (item 27146783, Regular $52 / Extended $99): you own the source, self-host the bundle from your own origin, and pay nothing per creator, per seat, per session, or per export. Whether ten creators or ten thousand mount the editor, your editor cost is the license you already paid. For a platform whose growth depends on a generous free tier, owning the editor outright is the difference between a fixed cost and a tax on adoption.
One editor for newsletter issues AND signup pages
A newsletter platform is rarely just the email. Creators need a subscribe page, a welcome page, an archive landing page — and most teams end up bolting a second tool onto the email editor to cover that. BuilderJS produces both from one canvas. For the newsletter itself, its EmailExportPipeline emits Outlook-safe markup: flexbox and grid layouts are converted to nested tables, SVG graphics are rasterized to PNG, @media rules stack columns on mobile, MSO conditional comments handle Windows Outlook, and a CSS inliner pushes every safe declaration onto its element so the issue survives Gmail, Outlook, and Yahoo stripping head styles. For the signup or landing page, the same design exports as clean, responsive page HTML for a real browser — no inlining, full modern CSS. The library ships 30+ templates and 200+ samples that have been Litmus-tested across 22 email clients, so your creators open the editor to working starting points, not a blank box. One editor, two outputs, one integration — and one tool to support instead of two.
Your brand, your domain, your creators' data
The reason to embed rather than redirect is control of the experience. BuilderJS renders inside your app's DOM, so creators never see a third-party editor or leave your product to design — the canvas, the chrome, and the locale (i18n supports 20+ locales including RTL) all look like yours. You can theme the editor UI to match your dashboard and extend the engine with newsletter-specific blocks your platform needs — a paid-subscriber-only section, a referral-link module, a sponsor slot. BuilderJS exposes three extension surfaces for that: register a custom Element class via the static Builder.registerElement(name, klass), add a drag-droppable palette item via builder.widgetsBox.addWidget() inside the load() callback, and attach a custom settings panel by returning your own control from an Element's getControls() — all without forking the core. Just as important, the design data stays yours. BuilderJS is JSON-first: getData() returns a complete, lossless snapshot of an issue, and load() restores it exactly, so a creator's draft re-opens identically next week. You store that JSON in your own database; there is no external service holding your creators' work and nothing phoning home. Where a hosted SaaS editor keeps designs in the vendor's account under the vendor's terms, here the round-trip is entirely inside your platform.
Multi-tenant by design, but you own the account layer
A newsletter platform is inherently multi-tenant — many creators, isolated from each other. BuilderJS is multi-tenant capable: configuration is closure-captured per mount, so multiple editor instances coexist without leaking state between tenants. But be clear on the boundary. BuilderJS does not impose tenancy, seats, or billing on you; it gives you the editing surface, and your application owns tenant isolation, who can edit which newsletter, seat management, and subscription billing — which is exactly where that logic belongs. Persistence is deliberately your call: on save, call getData() and POST the JSON to your own route; to reload, pass it back into load(). The download ships reference PHP backends (MySQL, SQLite, and S3 for save, upload, and auth) that you copy and own outright — a working blueprint to port to Node, Go, or Python if that matches your stack. The editor stays a focused library; the platform around it stays yours.
What BuilderJS does not do — and why that's the right boundary
It is worth stating plainly so your architecture stays clean: BuilderJS does not send newsletters, manage subscriber lists, run double opt-in, schedule sends, track opens and clicks, handle deliverability, or process creator payouts. Those are your platform's core value, not the editor's job. The handoff is the JSON-and-HTML boundary — your app calls getData(), POSTs the result to your route, and your worker injects merge tags and pushes the exported HTML to your own ESP, SMTP relay, or sending queue. Keeping that line sharp is precisely what lets BuilderJS stay a lightweight, embeddable editor you fully own rather than a service in your critical path. If a hosted editor went down or changed its pricing, your creators couldn't design; because you self-host the bundle from your own origin, the editor has no external runtime dependency on a vendor. You can try the drag-and-drop, the controls, and the export live at builder.emotsy.com before you write a line of integration code.
Frequently asked questions
-
Does BuilderJS send the newsletters my creators design?
No. BuilderJS is the editor only — it builds Outlook-safe email HTML and clean page HTML, and hands you the design as lossless JSON via getData(). Sending, subscriber lists, double opt-in, scheduling, open/click tracking, and deliverability are your platform's responsibility. You take the exported HTML, inject merge tags, and push it to your own ESP, SMTP relay, or sending queue.
-
How does the pricing work for a platform with thousands of creators?
BuilderJS is a one-time CodeCanyon license (item 27146783, Regular $52 / Extended $99). You own the source and self-host it, so there is no per-seat charge, no per-session metering, and no usage-based fee no matter how many creators mount the editor. Your editor cost is fixed at the license you already paid — it doesn't scale with sign-ups, which is the main reason it suits free-tier-heavy newsletter platforms. Author support is time-boxed (roughly 6–12 months), but your right to run and extend the source never expires.
-
Can I embed it in my React, Vue, or Next.js app and brand it as mine?
Yes. BuilderJS is a framework-agnostic DOM-mount bundle (dist/builder.js + dist/builder.css), not a published npm component, so you mount it client-side from your framework's lifecycle hook: useEffect in React, onMounted in Vue, ngAfterViewInit in Angular, onMount in Svelte. In Next.js, use a dynamic import with ssr:false inside a 'use client' component, since the editor runs in the browser only. It renders inside your DOM under your domain, you can theme the UI, and i18n covers 20+ locales including RTL.
-
How do creators' newsletter drafts get saved and re-opened exactly?
Through a lossless JSON round-trip. Call builder.getData() to serialize the current issue to JSON and POST it to your own backend route; store it however you like. To re-open the draft, pass that JSON back into builder.load(themeJson, themeTemplatesJson, themeConfigData, mediaUrl) — four positional arguments in that order. Feeding the saved getData() output back through load() reconstructs the design exactly, so a creator returns to the same blocks and settings they left.
-
Can I add newsletter-specific blocks like a paid-section or referral module?
Yes. Register a custom Element class through the static Builder.registerElement(name, klass), then surface it in the palette as a drag-droppable Widget via builder.widgetsBox.addWidget() in the load() callback — your platform-specific blocks live alongside the 30+ built-in element types and 20+ stock widgets without touching or forking the core. Need a bespoke settings panel for the block? Return your own control from the Element's getControls(); there is no separate control-registration call. Because you own the source, deeper changes are always possible and upgrades are yours to apply on your own schedule. BuilderJS also exposes pluggable, vendor-neutral AI hooks — you point each feature (e.g. inline rewrite) at your own endpoint URL — so if you offer subject-line or copy suggestions you wire in whatever model you already use rather than being locked to a provider.