Skip to content

Embedding on your site

The embed runs your demo inside your own page. You can get embed code in the "Share this demo" block of the VM.

Embedding is part of the paid plan, and free on the open-source plan with the attribution required.

The share link and README badge work on every plan.

Browser support

Modern browsers (Chrome and Edge 137 released May 2025) run the demo right there in your page.

Older browsers, Firefox and Safari visitors get a Launch demo card instead, which opens the full-page demo on our site. They move to the in-page demo automatically as those browsers catch up, with no change on your side.

What the visitor sees first

A VM image can be a sizable download, so by default it's not fetched when the page loads. A visitor will see a RUN <vm name> button indicating VM size and can decide to download and start it.

You can control this behaviour with widget parameters (see below).

Embed widget options

You can modify widget code to adjust it's behaviour or recieve events as visitor executes the guide.

Demoshell.mount(target, options) returns a promise for a handle.

target is an element or a CSS selector. If you will be using a custom block (not the one provided by the defaule embed code) make sure you give it at least 420px height so that the terminal an guide will fit.

OptionDefaultWhat it does
snapshotRequired. The VM reference, org/project:vm.
keyRequired. Publishable pk_ key. Required for a private VM, ignored for a public one.
serversame originRequired. The Demoshell origin.
guide'auto''auto' shows the checklist beside the terminal, 'collapsed' starts it as a pill the visitor opens, 'off' hides it. A VM with no guide ignores this.
theme'auto''auto' follows the visitor's device. Can be hardcoded to 'light' or 'dark'.
autostartfalseStart loading with the page, without the click.
onProgressCalled with { stage, done, total } through resolvemanifestassetsstartmemoryrundone.

The handle

The handle is the small JavaScript object Demoshell.mount() gives you back: const demo = await Demoshell.mount('#demo', { ... }). You can user it to check what state the demo is in, start it or remove it.

FieldMeaning
modepending before the visitor loads it, frame once the demo is running, launch if their browser cannot run it in the page, error if the card is showing.
readyPromise of the handle once the visitor has loaded the demo.
start()Load a demo without the click.
errorReason why the error card is showing.
destroy()Tear it down.
js
const demo = await Demoshell.mount('#demo', { snapshot: 'acme/web:hello' });
const live = await demo.ready;              // resolves when the visitor loads it
if (live.mode === 'launch') myOwnFallbackNotice.hidden = false;

Changing theme after the load

If your page has its own switch, repaint a running demo:

js
const demo = await Demoshell.mount('#demo', { snapshot: 'acme/web:hello', theme: 'light' });
myToggle.onclick = () => demo.setTheme('dark');

Internet inside the demo

Internet access from the demo VM is Off bt default unless the VM's recipe has it enabled (see Enable internet access).

Web page demos

A VM whose recipe opens on a web page (see Open a web page) embeds exactly the same way — the same mount(...) call, the same options, the same handle. Instead of the terminal, the container fills with the app's own web UI, with a ▤ TERMINAL and an ↗ OPEN button in its top-right corner. Your page needs no extra headers and no extra code.

Attribution

Attribution is required only on the open-source plan. An embedded demo shows a small ⚡ Powered by Demoshell pill in the bottom-right corner, linking to demoshell.com, and the snippet includes a plain-HTML credit link next to the container.