Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To run Python from an HTML page, load a browser Python runtime such as Pyodide, wait for it to initialize, then call Python code from JavaScript with pyodide.runPython(). The page still uses HTML and JavaScript; Pyodide supplies the Python runtime. This guide uses Pyodide for a direct, copyable setup and explains when PyScript or Brython may fit better.

Run Python in an HTML page with Pyodide

Save this as index.html and open it from a local web server. It loads a versioned Pyodide distribution, waits for initialization, executes Python, and displays the returned value in the page.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Python in the browser</title>
</head>
<body>
  <h1>Python in the browser</h1>
  <button id="run" disabled>Loading Python…</button>
  <pre id="output">Starting runtime…</pre>

  <script src="https://cdn.jsdelivr.net/pyodide/v314.0.7/full/pyodide.js"></script>
  <script>
    const button = document.querySelector("#run");
    const output = document.querySelector("#output");
    let pyodide;

    async function startPython() {
      try {
        pyodide = await loadPyodide();
        button.disabled = false;
        button.textContent = "Run Python";
        output.textContent = "Python is ready.";
      } catch (error) {
        output.textContent = `Could not start Python: ${error.message}`;
      }
    }

    button.addEventListener("click", () => {
      try {
        const result = pyodide.runPython("1 + 2");
        output.textContent = `Python returned: ${result}`;
      } catch (error) {
        output.textContent = `Python error: ${error.message}`;
      }
    });

    startPython();
  </script>
</body>
</html>

The versioned CDN path follows the Pyodide stable guide’s version context, which was listed as 314.0.7 when checked on September 29, 2026. Pinning a version makes deployments more reproducible; check the current usage guide before choosing a version for a new project. Do not substitute a development CDN URL for a deployed application.

What happens in the example

  1. The script tag loads pyodide.js, which exposes loadPyodide().
  2. startPython() is asynchronous and awaits loadPyodide(). The button remains disabled until setup succeeds, preventing a call before the runtime exists.
  3. pyodide.runPython("1 + 2") executes Python and returns a value that JavaScript can use.
  4. The event handler catches Python errors and presents their message in the page instead of silently failing.

To run more than a one-line expression, pass Python source as a string. For example, replace the call with pyodide.runPython("total = sum([2, 3, 5])ntotal"). The final expression’s value is returned to JavaScript. For larger programs, keep the source in a separate file or a template string so it is easier to maintain.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use Python variables and functions from JavaScript

Python names created in the runtime’s global scope can be accessed through pyodide.globals, as described in the Pyodide quickstart. For example, run Python that defines answer = 42, then read it with pyodide.globals.get("answer"). When you are finished with a Python value, follow Pyodide’s guidance for releasing proxies where applicable; values crossing between Python and JavaScript do not always behave like ordinary native JavaScript values.

Serve the page over HTTP during development

A simple page that only loads its runtime may appear to work when opened as a file, but browser security restrictions make file:/// an unreliable way to load local data files. If your Python code needs files, serve the project over HTTP instead. For example, with Python installed, run python -m http.server 8000 in the directory containing index.html, then open http://localhost:8000/.

This starts a basic development server; do not treat it as a production deployment server. The Pyodide FAQ also notes that browser File System API support is not uniform across Firefox and Safari, so do not build a cross-browser workflow around that capability without checking current browser support.

Choose between Pyodide, PyScript, and Brython

These projects offer different ways to put Python in a browser. The available project descriptions do not establish that they have identical package compatibility or performance, so choose based on how you want to integrate Python and whether your dependencies are supported.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Option Integration style Consider it when Important qualification
Pyodide Load a runtime from JavaScript and call Python explicitly with runPython(). You want direct control over when Python starts and how JavaScript invokes it. Check package support and load additional packages as needed; standard-library packages are available immediately after import.
PyScript An HTML-oriented browser application platform. You prefer an HTML-facing approach rather than writing all runtime calls yourself. The project description identifies Pyodide and MicroPython among its technologies. Consult its current documentation for the version’s syntax and supported features: PyScript project.
Brython A Python 3 implementation for browsers with interfaces for DOM elements and events. You want a browser-oriented Python interface to page elements and events. Its documentation describes serving a local project over HTTP and loading standard-library modules. The cited file/HTTP documentation is for version 3.10: Brython file and HTTP documentation.

Before committing to any option, check whether the libraries your application needs are available and how the chosen runtime exposes browser APIs. Do not assume a package built for desktop Python will work unchanged in a browser.

Load packages beyond the standard library

Pyodide’s quickstart says that only standard-library packages are available immediately after import. Additional packages need to be loaded using Pyodide’s package-loading approach, and the package and its dependencies must be supported in that environment. Consult the quickstart and the package guidance in the usage guide for the current method.

A dependency that installs successfully in a desktop virtual environment is not automatically usable in the browser. Check availability, dependencies, and any runtime limitations before designing around it. The Pyodide distribution path and its NPM mirror are also different: the guide distinguishes a distribution that includes packages from an NPM mirror containing only the runtime. Select the delivery route that matches the packages and build process you need.

Keep the page responsive during longer computations

By default, WebAssembly runs in the main browser thread, and long computations can make the interface unresponsive. Pyodide’s usage guide identifies a Web Worker as one solution. If the page performs substantial computation, move the work off the UI thread and communicate progress or results back to the page rather than making a long synchronous call from a click handler.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For short examples, direct calls are simpler. For a real application, account for startup time, the runtime and package downloads, and the duration of the Python task. Avoid starting the runtime repeatedly for each interaction; initialize once and reuse it while the page remains active. These are implementation considerations, not a published speed comparison between Pyodide, PyScript, and Brython.

Browser support and runtime delivery

The stable Pyodide guide recommends recent browsers and lists tested minimum versions of Firefox 112, Chrome 112, and Safari 16.4. Those are the versions listed by the documentation page, not a guarantee about every device or future browser release. Check the current guide and test the browsers your users actually use.

For deployed pages, use a versioned runtime URL and keep the runtime version controlled as part of your release. The development documentation warns against deploying from a development CDN URL. If you use an NPM-based workflow, note that the NPM mirror contains only the runtime while the distribution includes packages; verify which assets your application expects before switching delivery approaches.

Troubleshooting browser Python

The page says loadPyodide is not defined

  • Check that the pyodide.js script URL is valid and that the browser successfully downloaded it.
  • Ensure your initialization runs after the script is loaded. In the example, the runtime script appears before the inline code that calls loadPyodide().
  • Open the browser developer console and network panel to inspect script-loading errors, including blocked requests or an unavailable version path.

Python runs before initialization completes

loadPyodide() is asynchronous. Await it before calling runPython(), and keep controls disabled until it resolves. If initialization throws, display the error and provide a retry or reload path instead of calling methods on an unset runtime.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

An import fails even though the package works on desktop

Pyodide starts with standard-library packages; additional packages must be loaded, and not every desktop dependency is necessarily supported in a browser runtime. Check the current package guidance and whether dependencies are available for the selected runtime rather than assuming a desktop installation transfers unchanged.

A local data file cannot be loaded from file:///

Use an HTTP development server, such as python -m http.server 8000, and open the page through http://localhost:8000/. Browser security restrictions prevent ordinary JavaScript from freely loading local data files through file URLs. File System API behavior also varies across browsers, including Firefox and Safari, as noted in the Pyodide FAQ.

The page freezes while Python is working

A long computation on the main browser thread can block interface updates. Move work to a Web Worker and report results or progress back to the page. If a worker is not appropriate, reduce the amount of work per interaction and avoid synchronous long-running tasks on the UI thread.

The page works in one browser but not another

Compare the browser with the minimum versions currently listed in the Pyodide guide, then test the actual target browsers. Differences in browser capabilities, runtime versions, file access, or package support can affect behavior; a successful run in one browser is not proof of identical support elsewhere.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your goal is to capture a website rather than execute Python in the page, ScreenshotNeo is a website screenshot API and MCP server: one GET request can return a PNG, JPEG, WebP, or PDF. Its clean-shot flow accepts consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing status.

Here is a cURL request:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Replace YOUR_API_KEY with your key and change the target URL as needed. See the ScreenshotNeo API documentation for the available options. ScreenshotNeo also provides an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots.

Sign up for ScreenshotNeo’s free plan: 1,000 screenshots a month, no card required.

Frequently Asked Questions

Can Python in a browser access the page’s DOM?

Yes, but the integration depends on the runtime. Pyodide is called from JavaScript, which can interact with the DOM; Brython’s project describes interfaces for DOM elements and events. Check the selected project’s current documentation for its supported API.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Does browser Python replace a Python server?

No. This approach runs Python in the visitor’s browser. It does not by itself provide server-side execution, shared data storage, or protected server credentials.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.