Type to search the developer guide...

Fraczled SDK Guide

Securely embed the Fraczled editor.

A complete setup guide covering server-gated licensing, SDK configuration, store APIs, and every customizable UI surface.

What you need

apiKey

Your unique license key (dev or prod).

projectId

Identifier for your dashboard project.

Container

A div with a defined height.

The editor fills its container. Give it a height or the UI will be blank.

Quick Start (Server-Gated)

Validate licenses on your server and return a signed SDK URL.

server.js
app.post("/api/editor/init", async (req, res) => {
  const { licenseKey, projectId, origin } = req.body;

  const response = await fetch("https://fraczled.com/api/license/validate", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": "Bearer " + licenseKey
    },
    body: JSON.stringify({ projectId, origin })
  });

  const data = await response.json().catch(() => null);
  const status = data && typeof data === "object" ? (data.status ?? data) : null;

  if (!response.ok || !status || status.isValid === false) {
    return res.status(403).json({ error: "license_invalid" });
  }

  const token = signSdkSession({ origin, projectId });
  res.json({ sdkUrl: "/api/editor/sdk?token=" + token });
});

Tip: keep license keys on the server and return only the short-lived sdkUrl to the client.

Client Bootstrap

Request the SDK URL, then initialize the editor after it loads.

index.html
<div id="fraczled-editor" style="height: 100vh"></div>
<script>
  async function loadEditor() {
    const response = await fetch("/api/editor/init", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        licenseKey: "prod_...",
        projectId: "proj_123",
        origin: window.location.origin
      })
    });

    if (!response.ok) {
      const error = await response.json().catch(() => ({}));
      throw new Error(error.message || "License validation failed");
    }

    const { sdkUrl } = await response.json();
    const script = document.createElement("script");
    script.src = sdkUrl;
    script.defer = true;
    document.head.appendChild(script);

    script.onload = () => {
      FraczledSDK.createFraczledEditor({
        container: document.getElementById("fraczled-editor"),
        apiKey: "prod_...",
        projectId: "proj_123"
      });
    };
  }

  loadEditor().catch((err) => {
    console.error(err);
    alert("Failed to load editor. Check the console for details.");
  });
</script>

Secure Setup (Required)

The editor must be served through your backend. Your server validates the license and only then returns a signed SDK URL.

1) Validate on your server

  • Send projectId + origin to /api/license/validate.
  • Reject if isValid is false.
  • Never expose raw keys to the browser in production.

2) Issue short-lived access

  • Return a signed token (5 minutes max).
  • Serve the SDK bundle only when the token is valid.
  • Invalidate tokens when licenses are revoked.

3) Initialize the editor

  • Fetch /api/editor/init from the browser.
  • Load the SDK URL your server returns.
  • Call createFraczledEditor.

Security rules (non-negotiable)

  • Always gate the SDK bundle through your backend.
  • Validate projectId + origin on every init request.
  • Do not cache or reuse SDK tokens beyond their TTL.
  • Offline usage is only allowed with a signed offline token issued by Fraczled.

Configuration Reference

Every configuration option supported by createFraczledEditor.

editor.ts
createFraczledEditor({
  apiKey: "YOUR_LICENSE_KEY",
  projectId: "YOUR_PROJECT_ID",
  container: document.getElementById("editor"),
  showCredit: true,
  initialState: { pages: [], settings: {} },
  services: {
    licenseRequest: {
      projectId: "YOUR_PROJECT_ID",
      customerId: "cus_123",
      offlineLicense: OFFLINE_TOKEN
    },
    licenseTimeoutMs: 2500,
    aiEndpoint: "https://your-api.example.com/ai",
    unsplashProxyBaseUrl: "https://your-api.example.com/unsplash"
  },
  assets: {
    injectTailwind: true,
    tailwindCdnUrl: "https://cdn.tailwindcss.com",
    injectFont: true,
    fontHref: "https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap",
    injectBaseStyles: true,
    showLoader: true
  },
  ui: {
    hideDefaultPanels: false,
    hiddenPanels: [],
    topbarMode: "default",
    newDesignModal: {
      render: (ctx) => null,
      sizePresets: {
        social: [{ name: "Square", width: 1080, height: 1080, unit: "px", dpi: 72 }],
        print: [{ name: "Postcard", width: 6, height: 4, unit: "in", dpi: 300, bleed: 0.125 }]
      }
    }
  },
  customPanels: [],
  customContextMenuItems: [],
  customToolbarItems: [],
  keyboardShortcuts: {},
  customFonts: {},
  customTemplates: {},
  customExportFormats: [],
  customElementTypes: [],
  theme: {}
});
Key Required Purpose
apiKey Yes License key for validation.
projectId Yes Must match the project set in your dashboard.
container Yes DOM element the editor renders into.
showCredit No Show or hide the watermark (license can override).
initialState No Provide pages + settings to preload a design.
services No License request payload, timeout, and AI/Unsplash endpoints.
assets No Control injected Tailwind + fonts + loader.
ui No Hide panels, custom topbar, new design modal, size presets.
customPanels No Add sidebar tabs and panels.
customToolbarItems No Add topbar and object toolbar actions.
customContextMenuItems No Extend right-click menus on canvas or elements.
customTemplates No Provide templates, categories, and template save action.
customExportFormats No Register export formats in the Export menu.
customElementTypes No Add your own element types and renderers.
customFonts No Define font lists or custom loader.
keyboardShortcuts No Override or add keyboard shortcuts.
theme No Customize editor colors and layout styling.

Offline tokens are issued by Fraczled and are required for offline mode. If you need one, contact support.

Store API

The store is the single source of truth for the editor. Use it to read state, mutate content, and listen for changes.

store.ts
const editor = createFraczledEditor({ /* config */ });
const { store } = editor;

// Read state
console.log(store.state.pages, store.state.settings);

// Subscribe to changes
const unsubscribe = store.subscribe(() => {
  console.log("State updated", store.state);
});

// Mutate
store.addElement({ type: "text", content: "Hello", width: 240, height: 80 });
store.updateElement(store.state.selection[0], { color: "#0f172a" });

// Dirty state
if (store.hasUnsavedChanges()) {
  console.log("Unsaved changes detected");
}

// Persist
const json = store.exportJSON();
store.loadJSON(json);

// Cleanup
unsubscribe();

Read + Subscribe

  • store.state gives the latest snapshot.
  • store.subscribe() fires on any state change.
  • store.subscribeLicense() fires when entitlements update.
  • store.hasUnsavedChanges() exposes dirty state.

License + Entitlements

  • store.getLicenseStatus() returns plan + state.
  • store.getEntitlements() returns feature access.
  • Use these values to gate your own UI.
Category Methods
Pages addPage, duplicatePage, deletePage, renamePage, setActivePage
Elements addElement, updateElement, deleteElement, duplicateElement
Selection setSelection, selectAll, deselectAll, deleteSelection
Guides addGuide, updateGuide, deleteGuide, clearGuides
Settings updateSettings
Templates loadTemplateAsNewDesign
Dirty State hasUnsavedChanges, markClean
History undo, redo, canUndo, canRedo
Persistence exportJSON, loadJSON, reset

Store Items & UI Extensions

Everything you can replace or extend in the SDK. These are the official extension points and are fully supported.

Store Item Config Key Plan Feature Purpose
Custom Topbar Actions ui.topbarMode + customToolbarItems topbarActions Replace save/new/export/undo/redo UI.
New Design Modal ui.newDesignModal.render newDesignModal Replace the Create New Design modal UI.
Template Size Presets ui.newDesignModal.sizePresets templateSizes Override social/print sizes and bleeds.
Save as Template Button customTemplates.saveAction templateSave Customize "Save Current Design as Template".
Sidebar Tabs + Panels customPanels, ui.hiddenPanels (optional via feature) Add your own tools and workflows.
Context Menu Items customContextMenuItems None Extend right-click menus.
Toolbar Items customToolbarItems None Add buttons in object toolbar or topbar.
Custom Export Formats customExportFormats None Add new export actions.
Custom Element Types customElementTypes None Render your own element types.
Custom Fonts customFonts None Supply fonts or a font loader.
Custom Templates customTemplates templates Provide template data or fetch templates.
Keyboard Shortcuts keyboardShortcuts None Override defaults or add custom combos.
Theme theme None Customize editor colors and layout.

Custom Topbar Example

createFraczledEditor({
  ui: { topbarMode: "custom" },
  customToolbarItems: [
    {
      id: "my-topbar-export",
      label: "Export",
      location: "topbar",
      onClick: ({ topbar }) => topbar?.onExport?.("web")
    }
  ]
});

Template Save Action

createFraczledEditor({
  customTemplates: {
    saveAction: {
      label: "Save as Brand Template",
      onClick: ({ openSaveModal }) => openSaveModal()
    }
  }
});

Plan-gated features

Plan features are configured in https://www.fraczled.com/admin/ and enforced by the license response.

  • topbarActions - Custom topbar UI
  • templateSave - Save as Template action
  • newDesignModal - Custom Create New Design modal
  • templateSizes - Custom size presets
  • templates, design, elements, draw
  • text, images, brand, uploads
  • qrcode, layers, saveLoad

Templates & Size Presets

Provide your own templates and define the exact sizes + bleeds your product requires.

Custom templates

Templates can be static, fetched from your API, or merged with Fraczled templates.

createFraczledEditor({
  customTemplates: {
    templates: [
      { id: "t1", name: "Promo", category: "marketing", tags: ["promo"], thumbnail: "...", designState: {} }
    ],
    fetchTemplates: async () => fetch("/api/templates").then(r => r.json()),
    categories: ["marketing", "product"],
    hideDefaultTemplates: false
  }
});

Size presets with bleeds

Use inches, millimeters, points, or pixels. Bleed/safe area uses the same unit.

createFraczledEditor({
  ui: {
    newDesignModal: {
      sizePresets: {
        social: [
          { name: "Square", width: 1080, height: 1080, unit: "px", dpi: 72 }
        ],
        print: [
          { name: "Sleeve", width: 8.25, height: 5.5, unit: "in", dpi: 300, bleed: 0.125 }
        ]
      }
    }
  }
});

Unit support

Accepted units: px, in, mm, pt. The editor converts units automatically.

Guides, Rulers & Snapping

Ruler guides are persistent, per-page alignment targets that share the same Smart Guide engine as object snapping.

Persistent ruler guides

  • Guides live on each page (per-artboard).
  • Locking prevents edits but still allows snapping.
  • Hidden guides only snap when snapToHiddenGuides is true.

Smart guides & snapping

  • Object-to-object and object-to-guide use the same alignment rules.
  • Snapping can be toggled without disabling visual feedback.
  • On touch devices, snapping uses a slightly higher tolerance.

Guide + snap settings

store.updateSettings({
  showRulers: true,
  showGuides: true,
  lockGuides: false,
  showSmartGuides: true,
  snapEnabled: true,
  snapToObjects: true,
  snapToGuides: true,
  snapToHiddenGuides: false
});

Guide API

const pageId = store.state.activePageId;
store.addGuide(pageId, { axis: "x", position: 120 });
store.addGuide(pageId, { axis: "y", position: 320 });

store.updateGuide(pageId, guideId, { position: 240 });
store.deleteGuide(pageId, guideId);
store.clearGuides(pageId);

Guide coordinate system

Guide positions are stored in canvas pixels. If you work in inches/mm/pt, convert with your unit helpers before calling guide methods.

Events & Saving

Listen to editor events and persist designs as JSON.

events.ts
editor.on("change", (state) => {
  console.log("State updated", state);
});

editor.on("save", (payload) => {
  console.log("User saved", payload);
});

editor.on("export", (payload) => {
  console.log("Exported", payload);
});

// Persist
const json = editor.save();
await fetch("/api/designs", { method: "POST", body: json });

Event types

  • change - any editor update
  • save - user saved a design
  • select - selection changed
  • export - export completed
  • designSaved - saved design created/updated
  • designDeleted - saved design removed
  • toast - inline notifications from the SDK

Best practices

  • Store JSON in your DB; reload via initialState or loadJSON.
  • Debounce autosave on change events.
  • Always keep the editor container height set.

Licensing & Security

Licenses are validated server-side. The editor remains restricted until validation succeeds.

Server-gated delivery

Your backend must validate the license and return a signed SDK URL. This is required for production use.

License states

  • pending - restricted while validating
  • valid - full access per entitlements
  • invalid - blocked + watermark
  • offline - allowed only with signed token

Offline mode

Offline usage requires a signed offline license token issued by Fraczled. No token means no offline access.

LicenseStatus
{
  "isValid": true,
  "state": "valid",
  "plan": "team",
  "showWatermark": false,
  "entitlements": {
    "ai": true,
    "export": { "web": true, "print": true },
    "features": {
      "templates": true,
      "topbarActions": true,
      "templateSave": true,
      "newDesignModal": true,
      "templateSizes": true
    },
    "limits": { "maxPages": 50 }
  }
}

Production rule: the SDK bundle must only be served after your server validates the license and issues a short-lived token.

Deploy Checklist

Use this checklist before pushing to production.

Licensing

Always server-gate the SDK. Validate projectId + origin, issue short-lived tokens, and revoke when needed.

Layout

Give the editor a fixed height or full viewport. Call destroy() on teardown.

Assets

Disable injected Tailwind if it conflicts with your app. Prefer self-hosted fonts in production.

Support

Need help integrating?

Our engineering team can help you debug integration issues or plan custom SDK workflows.