Docs

Widget and iframe embed

Add widget.js and a div with your widget key, and the code inside it becomes an editor readers can run in any of 45 languages, with no account. Sites that only accept iframes get the same editor from an embed URL. This page lists every attribute, the JavaScript API and its events.

Put a runnable code example on any page with one script tag. Readers edit the code, change its input and run it, with no account. The widget uses a CodeMirror 6 editor and runs code over a WebSocket. It renders in Shadow DOM, so your page's styles and the widget's stay separate, and its height is fixed when it loads, so running code never shifts your page.

Requires a WebSocket key. Create one from the Widgets page in your dashboard. Widget keys are safe to embed in public HTML; they cannot be used to call the REST API.

Quick Start

index.html
<!-- 1. Add the widget script (before </body>) -->
<script src="https://onlinecompiler.io/widget.js"></script>

<!-- 2. Add a div with your key, the code, and optional input -->
<div class="runcode" data-key="YOUR_API_KEY" data-lang="python-3.14">
<pre>name = input()
print(f"Hello, {name}!")</pre>
<pre data-stdin>Ada</pre>
</div>

Your code and input

Put the code inside the widget's div in a <pre>, and the program's standard input in a <pre data-stdin>. Both must be direct children of the div. The code in a <pre> is readable, and indexed, before the script loads, but < and & must be escaped. For code full of angle brackets, such as C++ includes or generics, use <script type="text/plain"> instead, which needs no escaping. Shared indentation is removed, and Reset brings back your code and input after a reader edits them.

cpp-example.html
<!-- No escaping needed inside <script type="text/plain"> -->
<div class="runcode" data-key="YOUR_API_KEY" data-lang="g++-15">
  <script type="text/plain">
    #include <iostream>
    #include <vector>

    int main() {
        std::vector<int> v{1, 2, 3};
        for (int x : v) std::cout << x * x << "\n";
    }
  </script>
</div>

A widget without code of its own opens with a sample program and a language menu, as a playground.

Configuration

Configure each widget instance using data-* attributes:

AttributeRequiredDefaultDescription
data-keyYes-Your API key
data-langNopython-3.14Language of the code (any compiler key)
data-themeNodarkdark, light, or auto to follow the reader's system setting
data-heightNoFits the codeEditor height in pixels. Without it, the editor fits the starting code, from 6 to 20 lines. The whole widget is 227 pixels taller, for the header, console and credit line. fill fills the div's own height instead, so give the div a height.
data-lang-selectNoOnly without codetrue or false to always show or hide the language menu. Edits in each language are kept when a reader switches.
data-readonlyNoOffReaders can run the code and change its input, but not edit the code. setCode still works.

Hidden code around the reader's

Add a <script type="text/plain" data-template> (or a <pre data-template>) to run code the reader doesn't see, such as imports, a main function or test calls. The reader's code replaces ##CODE##, and its later lines get the marker's indentation, so it can sit inside a Python function. Without a marker, the reader's code runs after the template. The template applies to the language in data-lang only, and line numbers in errors count its lines too.

template.html
<!-- Readers see and edit only the function body -->
<div class="runcode" data-key="YOUR_API_KEY" data-lang="python-3.14">
  <script type="text/plain" data-template>
    def area(width, height):
        ##CODE##

    print(area(3, 4))
  </script>
  <pre>return width * height</pre>
</div>

JavaScript API and events

Each widget sends events to its div. They bubble, so you can also listen on document and read event.target. Use them to check a reader's answer, record progress, or unlock the next step:

exercise.html
<div class="runcode" id="exercise" data-key="YOUR_API_KEY" data-lang="python-3.14">
<pre># Print the sum of the numbers from 1 to 10
print()</pre>
</div>
<p id="verdict"></p>

<script>
  // Check the reader's answer each time they run it.
  document.getElementById("exercise").addEventListener("runcode:result", (event) => {
    const { exit_code, output } = event.detail;
    const correct = exit_code === 0 && output.trim() === "55";
    document.getElementById("verdict").textContent = correct ? "Correct!" : "Not yet, try again.";
  });
</script>
<script src="https://onlinecompiler.io/widget.js"></script>
EventWhen, and what event.detail holds
runcode:readyThe widget has started. detail.widget is the widget.
runcode:runA run started. detail has the reader's code (without the template), input and compiler.
runcode:resultThe program ran. detail is the result: output, error, status, exit_code, signal, truncated, time, total and memory, as in the WebSocket codeoutput event.
runcode:errorThe program didn't run, or its result was lost. detail.message says why: the key was refused, an account limit was hit, the connection dropped, or no result came back within 60 seconds.

To control a widget from your page, get it with OnlineCompilerWidget.get(element):

control.js
// The widget on an element, once the script has started it (null before).
const widget = OnlineCompilerWidget.get(document.getElementById("exercise"));

widget.setCode('print(sum(range(1, 11)))');
widget.setInput("");
widget.run();
MethodWhat it does
getCode()The code in the editor, without the template.
setCode(code)Replaces the code in the editor. Readers can undo it, and Reset still brings back your original.
getInput(), setInput(text)Read or replace the Input tab.
run()Runs the code, like the Run button. Does nothing while a run is in progress or when the editor is empty.
reset()Goes back to your original code and input.
disconnect()Closes the connection. The next run reconnects.

Multiple Widgets

Add as many widgets as you need. Use class="runcode" for multiple widgets or id="runcode" for a single one. Each widget works independently, and connects only when it scrolls near the viewport, so a long page of examples doesn't open a connection for each one up front. Widgets added to the page later, as single-page sites and docs generators with instant navigation do, start on their own, and a widget taken off the page closes its connection. For setups in Docusaurus, MkDocs, Sphinx, Mintlify and WordPress, see runnable code examples in docs. For a live demo and how the widget compares with other embeddable code editors, see embeddable code editor.

multiple-widgets.html
<!-- Follows the reader's light or dark setting; editor fits the code -->
<div class="runcode"
  data-key="YOUR_API_KEY"
  data-lang="python-3.14"
  data-theme="auto">
<pre>print("Hello")</pre>
</div>

<!-- A Java playground: light theme, 300px editor, language menu shown -->
<div class="runcode"
  data-key="YOUR_API_KEY"
  data-lang="openjdk-25"
  data-theme="light"
  data-height="300"
  data-lang-select="true">
</div>

<!-- Multiple widgets on the same page work independently -->
<script src="https://onlinecompiler.io/widget.js"></script>

Sites that only take an iframe

Many course platforms, site builders and wikis strip script tags but allow an <iframe>. For those, https://api.onlinecompiler.io/embed/ is a page holding one widget that fills the frame. Fill in your widget key and code, and paste the iframe it gives you:

Paste into your page's HTML
<iframe src="https://api.onlinecompiler.io/embed/?key=YOUR_WIDGET_KEY&amp;lang=python-3.14&amp;theme=light#code=name%20%3D%20input(%22Your%20name%3F%20%22)%0Aprint(f%22Hello%2C%20%7Bname%7D!%22)&amp;input=Ada"
  title="Runnable Python example" width="100%" height="420" style="border: 0" loading="lazy"></iframe>
ParameterWhat it sets
keyYour widget key (required)
langThe compiler id, such as python-3.14 or g++-15; python-3.14 if left out
themedark (the default), light or auto
readonly1 to stop readers editing the code
#code=The starting code, URL-encoded, after the #
#input=The starting standard input, URL-encoded, after the #
  • The code and input go after the #, which browsers never send to a server, so they don't appear in our logs and long programs fit. Reset brings them back after a reader edits them.
  • A key restricted to your domain can only be framed by pages on that domain, and every frame around the embed must be on it too. Opened on its own, outside a frame, the embed shows a notice instead of running.
  • The console is 156 pixels tall and the editor gets the rest of the frame's height.
Features included: CodeMirror 6 editor with syntax highlighting for all 45 languages, Run with Ctrl+Enter (Cmd+Enter on Mac), Reset, a console with Output and Input tabs, the exit code with run time and memory, a resizable split that puts the console beside the editor on wide pages, and dark, light and auto themes.

Questions

Do readers need an account to run the code?
No. Runs use your widget key and count towards your account's allowance. Give the key its own monthly limit to cap a public page.
Can I check a reader's answer?
Yes. Listen for the runcode:result event on the widget's element and compare event.detail.output with the answer, as in the JavaScript API example.
Can readers edit only part of the program?
Yes. Put the whole program in a script tag with data-template and mark the editable part with ##CODE##; readers see and edit only that part.