Load Python Packages in the Browser with PyScript: A Practical Guide
Learn how to load external Python packages in the browser using PyScript’s <code><py-config></code> tag, with a hands‑on example, performance trade‑offs, and a practical checklist for production.
16 Apr 2026, 22:09 UTC

Why Load Packages with PyScript?
Modern web apps often need quick, client‑side data processing—think interactive charts, real‑time analytics, or lightweight scientific demos. Traditionally JavaScript handled these tasks, but developers wanting to leverage Python’s rich ecosystem faced a server‑side bottleneck or complex bundling. PyScript, built on Pyodide (CPython compiled to WebAssembly), lets you import and run full Python packages directly in the browser. The <py-config> tag is the key to making this work: it tells Pyodide which wheels to fetch before your <py-script> code runs.
How <py-config> Works
When the page loads, PyScript parses the <py-config> element. Each packages entry triggers a fetch of the corresponding wheel (or a custom URL if you provide one). Pyodide then installs the package into its virtual file system. Once all listed packages are ready, the <py-script> blocks execute.
Typical <py-config> Syntax
<py-config>
packages = [
"numpy",
"pandas"
]
</py-config>
For a custom wheel you can specify a URL:
<py-config>
packages = [
{"name": "my‑pkg", "url": "https://example.com/my_pkg‑0.1‑py3‑none‑any.whl"}
]
</py-config>
Concrete Example: Print NumPy Version
Below is a minimal HTML file that demonstrates loading NumPy and printing its version to the page. After opening the file in a modern browser, you should see the version number displayed.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>PyScript NumPy Demo</title>
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
</head>
<body>
<py-config>
packages = ["numpy"]
</py-config>
<py-script>
import numpy as np
print(f"NumPy version: {np.__version__}")
</py-script>
</body>
</html>
**Verification steps**
- Open the file in Chrome or Firefox.
- In the page, you should see a line like
NumPy version: 1.26.4.
- In the page, you should see a line like
- Open DevTools → Network tab, filter by "pyodide" or the wheel name. The
numpy‑1.26.4‑cp311‑none‑any.whlfile should load with status 200. - Check DevTools → Console for any Python tracebacks. A clean console indicates successful import.
Engineering Decision: Bundle Size vs. Feature Set
While the ability to load packages on demand is powerful, it comes with trade‑offs:
- Download size – Large wheels (e.g.,
scipyormatplotlib) can add 30–200 MB to the initial page load, which hurts performance on mobile or slow networks. - Memory usage – Pyodide runs in a WebAssembly sandbox that consumes memory. Loading many packages can push the browser’s memory limits, especially on older devices.
- Debugging – Errors are logged to the browser console. While stack traces appear, source maps may not map precisely back to the original Python code, making debugging a bit more manual.
To keep the experience snappy, only list the packages your page truly needs. If you only need data parsing, pandas might be sufficient; avoid pulling in heavy scientific stacks unless you’re building a full notebook.
Actionable Checklist for Production
- Identify the minimal set of packages required for the client‑side feature.
- Use
<py-config>to list those packages, optionally providing CDN URLs for custom wheels. - Measure the initial load time with DevTools Performance panel. Aim for under 3 s for interactive use.
- Monitor memory usage via DevTools → Memory tab. If the heap grows beyond 200 MB, consider splitting the page or lazy‑loading heavy packages.
- Test on target browsers (Chrome, Edge, Firefox) and on mobile data to ensure acceptable UX.
- Document any custom wheel URLs and maintain them in a versioned S3 bucket or CDN.
By following these steps, you can confidently decide when to bring Python into the browser with PyScript and how to keep the trade‑offs manageable.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.