1. Embed the widget (iframe)

Want the full drag-and-drop converter on your own site without writing any code? Drop in this iframe. It loads the isolated /widget route — no navbars, no footers, just the converter. Conversion still happens in your visitor's browser, so embedding it does not put you in the data path and does not make you a data processor for the uploaded files.

HTML
<iframe
  src="https://md-convert.org/widget/"
  title="MD Convert converter"
  width="100%"
  height="520"
  style="border:1px solid #1e3a5c;border-radius:12px"
  loading="lazy"
></iframe>

Each embed includes a small “Powered by MD Convert” link, which helps others discover the tool and supports the project. The iframe is lazy-loaded and responsive — set width="100%" and it will fill its container on mobile, tablet, and desktop without extra CSS.

2. Architecture & Engine Specification

The engine behind every converter on this site is a modular, client-side pipeline written in TypeScript and compiled to ESM. Each format is an isolated engine module — pdf, docx, excel, csv, tsv, json, yaml, xml, html, and more — exposing a single convert(engine, input, options) entry point. There is no React dependency, no Node server, and no shared mutable state between engines. You import only what you use, so bundles stay tiny and tree-shaking is effective across Vite, webpack, and Next.js.

Thread separation is automatic. Heavy parsers such as PDF (pdf.js), Excel (SheetJS), CSV (PapaParse), JSON, YAML, and Jupyter run inside a dedicated Web Worker via transferable ArrayBuffer messages. This keeps the main thread at 60 fps, prevents UI jank during large document parses, and avoids blocking input handling or animations. Engines that require DOM APIs — DOCX via Mammoth, HTML and URL via DOMPurify plus Turndown and Readability, and the DOM path for XML — intentionally stay on the main thread because DOMParser anddocument are not available inside a Worker. The router is deterministic, so the same file always takes the same path.

Zero-data-egress is a guarantee, not a policy toggle. Files are read locally with the FileReader API into volatile memory; the ArrayBuffer is never fetched, never posted, and never persisted to localStorage or IndexedDB. The only exception is the optional URL-to-Markdown flow, which fetches a remote URL through an anonymous stateless hop before parsing locally. When the tab closes, the memory is released. There are no subprocessors, no retention windows, and no cross-border transfer to assess.

  • Modular per-format imports — bundle only pdf if you only need PDFs.
  • Framework-agnostic ESM with no React or build-tool lock-in.
  • Automatic main-thread versus Worker dispatch for optimal responsiveness.
  • 100% client-side execution; no API keys or backend required.

The modular SDK will be published to npm as @mdconvert/core for direct programmatic use. Until the package ships, the iframe embed above exposes the same conversion engine with zero integration work, and you can get in touch if you need early programmatic access or a pre-release tarball.

Security & Content Security Policy (CSP)

Enterprise deployments serve the parent page with a strict Content-Security-Policy that allowlists the widget origin. Without an explicit frame-src directive, browsers will block the iframe or emit console warnings. Add the following response header on the page that embeds the widget:

HTTP
Content-Security-Policy: frame-src 'self' https://md-convert.org;

This permits frames from your own origin and from https://md-convert.org while denying every other embed source. If you already emit a broader CSP, merge the value rather than replacing it — duplicate Content-Security-Policy headers are enforced independently and can create unexpected blocks.

For defense-in-depth, apply a sandbox attribute to the iframe. The recommended minimum is:

HTML
<iframe
  src="https://md-convert.org/widget/"
  sandbox="allow-scripts allow-downloads allow-forms"
  title="MD Convert converter"
  width="100%"
  height="520"
  style="border:1px solid #1e3a5c;border-radius:12px"
  loading="lazy"
></iframe>

allow-scripts lets the converter run, allow-downloads enables the “Copy Markdown” and download actions, and allow-forms supports file inputs. Do not add allow-same-origin or allow-top-navigation unless you have a specific need — the widget does not require them and omitting them further isolates the embedded context.

Bidirectional postMessage Event Protocol

The widget emits window postMessage events on every completed conversion so host applications can react without polling or DOM scraping. Listen on the parent frame, validate event.origin strictly, and branch on event.data.type:

JavaScript
// Listen for completed Markdown conversions from the embedded MD Convert widget
window.addEventListener("message", (event) => {
  // Validate origin for strict security
  if (event.origin !== "https://md-convert.org") return;

  if (event.data?.type === "MD_CONVERT_SUCCESS") {
    const { markdown, format, filename } = event.data.payload;
    console.log(`Converted ${filename} (${format}) to Markdown:`, markdown);
  }
});

The payload for MD_CONVERT_SUCCESS contains markdown as a string, format as the detected source type, and filename as provided by the user's file picker. Error cases emit MD_CONVERT_ERROR with a warnings array — useful for surfacing parse diagnostics in your own UI. Always check event.origin === "https://md-convert.org" before trusting the data; never use a wildcard check.

Engine Architecture & TypeScript Contracts

Under the iframe, the same TypeScript contracts power every format. Host applications that adopt the upcoming npm package will program against these exact types — the embed today and the SDK tomorrow share the identical engine surface:

TypeScript
// Core client-side conversion contracts
export type SupportedEngine = "pdf" | "docx" | "excel" | "csv" | "tsv" | "json" | "yaml" | "xml" | "html";

export interface ConversionOptions {
  delimiter?: "," | ";" | "\t" | "|"; // Tabular engines
  hasHeader?: boolean;
  extractMedia?: boolean;
}

export interface ConversionResult {
  markdown: string;
  warnings: string[];
  metadata?: Record<string, unknown>;
}

SupportedEngine enumerates every parser the platform ships. ConversionOptions is intentionally narrow: tabular engines accept a delimiter and hasHeader toggle, while document engines use extractMedia to decide whether embedded images become Markdown image nodes or are skipped. ConversionResult always returns the Markdown string plus any non-fatal warnings and optional metadata such as page count or sheet names.

Enterprise Privacy & Regulatory Compliance (GDPR, HIPAA)

Because conversion is purely client-side, most compliance burdens disappear by architecture rather than by policy. Documents are processed solely in client volatile memory inside the visitor's browser tab. They are never uploaded to MD Convert servers, never written to disk on our infrastructure, and never forwarded to a third-party subprocessor. This eliminates the need for a Data Processing Agreement covering file contents, removes data retention liabilities, and avoids cross-border data transfer hurdles that arise when files transit through a vendor region.

For GDPR, the embedding site remains the data controller for any personal data inside the uploaded file, but MD Convert does not become a processor of that content because it never receives it. No personal data, file names, or file contents are logged, and there is no pseudonymous identifier tied to the conversion. For HIPAA-sensitive workflows, the same property holds: protected health information inside a DOCX or PDF stays on the endpoint device and never traverses the network to MD Convert, so the service does not fall within the scope of a Business Associate Agreement for conversion itself. Teams should still assess their own hosting and logging posture for the parent page.

Operationally, this means no subprocessor list to review, no retention schedule to negotiate, and no deletion request workflow for file contents — there is simply nothing stored to delete. Security reviews can focus on the narrow iframe and CSP surface rather than a full data-flow audit. If your compliance team needs a written architectural attestation, contact us and we will provide it.

Developer FAQ

Does embedding the widget require an API key or account?

No. The widget is free, unauthenticated, and requires no account. Copy the iframe snippet and ship it. There are no API keys to rotate, no secrets to inject, and no billing tier to select. The “Powered by MD Convert” attribution is appreciated but not gating.

Can the widget operate in air-gapped or offline environments?

Yes. Once the parent site has cached the widget shell and its engine chunks via the service worker, all conversions run fully offline. This makes the widget suitable for intranets, on-prem documentation portals, and Electron or Tauri wrappers that must function without external network access. Revalidate the cache periodically to pick up parser improvements.

What are the CORS limitations for URL-to-Markdown conversions?

Browsers block cross-origin fetches to arbitrary sites unless the target sends permissive CORS headers — most do not. To make URL-to-Markdown reliable, the widget sends the URL through an anonymous, stateless proxy hop that fetches the HTML without cookies or credentials, then hands the raw markup back to the client where Readability cleans it and Turndown converts it to Markdown. The proxy retains no body, no URL log, and no session.

Are there rate limits or document size caps?

No server-side rate limits or quotas. Throughput and maximum document size are bounded by the client device's memory and CPU. Modern desktops comfortably handle hundred-page PDFs and large workbooks; low-memory mobile browsers should avoid extremely large single-sheet spreadsheets or split them first. If a file is too large for the tab, the engine returns a structured warning rather than silently truncating.

Why build on MD Convert?

  • 100% client-side — your users' files never touch a server.
  • Modular imports keep bundles tiny and tree-shakeable.
  • Heavy formats (PDF, Excel) run in Web Workers automatically.
  • Framework-agnostic ESM and dependency-light.
  • Straightforward CSP and iframe sandboxing for enterprise security.
  • Typed contracts and postMessage events for deep host integration.