Wasm powered Jupyter running in the browser 💡

Overview

JupyterLite

ci-badge binder-badge docs-badge

JupyterLite is a JupyterLab distribution that runs entirely in the browser built from the ground-up using JupyterLab components and extensions.

Status

Although JupyterLite is currently being developed by core Jupyter developers, the project is still unofficial.

Not all the usual features available in JupyterLab and the Classic Notebook will work with JupyterLite, but many already do!

Don't hesitate to check out the documentation for more information and project updates.

Try it in your browser

JupyterLite works with both JupyterLab and RetroLab.

Try it with JupyterLab! Try it with RetroLab!
lab-screenshot retro-screenshot

🏗️ Build your own JupyterLite 🏗️

Install jupyterlite from PyPI, which comes with the CLI and a pre-built, empty site archive.

python -m pip install --pre jupyterlite

Use the jupyter lite CLI to build, check, or create a reproducible, remixable archive of your site, then publish your built site to any static host, such as GitHub Pages or ReadTheDocs.

jupyter lite description extras
init build an empty site from the bundled app archive
build add your own notebooks, labextensions, and settings jupyter_server for indexing content
serve try out your site locally tornado for snappier serving
check check your site's metadata jsonschema for schema validation
archive create a single-file archive

Features

For more details, see the JupyterLite documentation.

Browser-based Interactive Computing

  • Python kernel backed by Pyodide running in a Web Worker
    • Initial support for interactive visualization libraries such as altair, bqplot, ipywidgets, matplotlib, and plotly
  • JavaScript and P5.js kernels running in an IFrame
  • View hosted example Notebooks and other files, then edit, save, and download from the browser's IndexDB (or localStorage)
  • Support for saving settings for JupyterLab/Lite core and federated extensions
  • Basic session and kernel management to have multiple kernels running at the same time
  • Support for Code Consoles

Ease of Deployment

  • Served via well-cacheable, static HTTP(S), locally or on most static web hosts
  • Embeddable within larger applications
  • Requires no dedicated application server much less a container orchestrator
  • Fine-grained configurability of page settings, including reuse of federated extensions

Showcase

Jupyter Interactive Widgets

widgets

JupyterLab Mimerender Extensions

image

Matplotlib Figures

image

Altair

altair

Plotly

plotly

Development install

See the contributing guide for a development installation.

Related

JupyterLite is a reboot of several attempts at making a full static Jupyter distribution that runs in the browser, without having to start the Python Jupyter Server on the host machine.

The goal is to provide a lightweight computing environment accessible in a matter of seconds with a single click, in a web browser and without having to install anything.

This project is a collection of packages that can be remixed together in variety of ways to create new applications and distributions. Most of the packages in this repo focus on providing server-like components that run in the browser (to manage kernels, files and settings), so existing JupyterLab extensions and plugins can be reused out of the box.

See also:

  • p5-notebook: A minimal Jupyter Notebook UI for p5.js kernels running in the browser
  • jyve: Jupyter Kernels, right inside JupyterLab
  • Starboard Notebook: In-browser literal notebooks
  • Basthon: A Jupyter notebook implementation using Pyodide
Comments
  • Implement a custom Emscripten File System which communicates with the JupyterLab Content Manager, giving file access to pyolite

    Implement a custom Emscripten File System which communicates with the JupyterLab Content Manager, giving file access to pyolite

    Fixes https://github.com/jupyterlite/jupyterlite/issues/665 Fixes https://github.com/jupyterlite/jupyterlite/issues/119

    Progress towards https://github.com/jupyterlite/jupyterlite/issues/315

    This PR implements a DriveFS custom file system which allows Emscripten kernels to have access to JupyterLab files. It uses a service worker to make any async task of accessing/deleting/renaming files into a synchronous task.

    enhancement 
    opened by martinRenou 56
  • add piplite for customizing pyolite packages, automate wheel management

    add piplite for customizing pyolite packages, automate wheel management

    References

    • starts on #151

    Code changes

    • [x] removes all the hard-coded whl URLs from the pyolite extension
    • [x] hoist pyodide-specific config to new namespaced litePluginSettings
      • [x] adds pipliteUrls to jupyter-lite.json
      • [x] create a schema for a new well-known all.json describing the necessary subset of the warehouse API
      • [x] optionally disablePyPIFallback access altogether
    • [x] wraps micropip really early to obey these
      • [x] encapsulated as piplite, could be upstreamed, but we might need other stuff here (e.g. %pip)
    • [x] implement jupyter_lite_config.json and CLI-serviceable options for
      • [x] specify custom micropipUrls
      • [x] validating the metadata schema
    • [x] adds CLI, jupyter lite pip index for just generating an all.json for a directory of wheels
    • [x] anticipate wheels, etc. in federated_extensions (including this thing itself in #386)
      • [x] move wheels into pypi during webpack build of app, handle more robustly
      • [x] define package.json conventions/schema for declaring location of wheels, e.g. #/piplite/wheelDirs
      • [x] determine when to find wheels in package.json, weighing flexibility/resilience and performance (e.g. 2n+1 requests)
        • [x] at build time, updating jupyter-lite.json
        • [ ] at run time... could be done in parallel with initial pyodide load?

    User-facing changes

    • for GUI users
      • might be slightly faster, as it would save ~5 requests to pypi.org... but not really until more stuff is indexed
      • if fully cached, dependencies that change "in the wild" will not impact users of an already-built site, leading to less breakage a la #311
    • for CLI users
      • eventually should be able to
        • point to alternate PyPI indexes, mirrors
        • easily include additional, pre-cached packages
          • e.g. offer pip freeze (or equivalent) from a known set of "leaf" packages (plus the kernel dependencies)
          • make no requests to pypi.org at all

    Backwards-incompatible changes

    • n/a, probably, as this was either working and you didn't notice it, or was broken and you couldn't tell
    enhancement performance 
    opened by bollwyvl 31
  • Support for Comms in the pyolite kernel

    Support for Comms in the pyolite kernel

    Related to https://github.com/jtpio/jupyterlite/issues/18 Similar to https://github.com/jtpio/jupyterlite/pull/141 but for pyolite and ipywidgets.

    This is not yet working.

    enhancement new 
    opened by martinRenou 28
  • Upgrade to JupyterLab 3.1.0rc1

    Upgrade to JupyterLab 3.1.0rc1

    Binder

    References

    • started from #198 (of #197)

    Code changes

    • [x] bump all the (upstream) versions The Hard Way
      • not sure i got them all :blush:
      • don't know if there's a more automated way for everything a la #204)
        • ... but maybe as a datapoint for tracking stuff down?
    • [x] add appName and appVersion to jupyter-lite(.schema).json
      • [x] validate in dodo
      • [ ] consider version of last resort from a package.json if available? yarn.lock for better reproducibility?
    • [x] implement setPath in packages/application-extension/src/index.tsx
      • didn't have time to go run this one down, yet

      • [x] consider deferring in #109?

    User-facing changes

    • About now shows app name and version

    Screenshot from 2021-07-02 20-51-00

    previous screenshot

    Backwards-incompatible changes

    maintenance 
    opened by bollwyvl 23
  • pandas.read_csv(

    pandas.read_csv("iris.csv") FileNotFound

    Description

    Pandas read_csv gave FileNotFound error on example file iris.csv. I'm hope this is not a silly user error and I'm sorry in advance if it is.

    Screenshot 2021-06-01 at 17 02 46

    Reproduce

    • Create new notebook in examples folder
    • import pandas as pd
    • pd.read_csv("iris.csv")

    Expected behavior

    Load and display the content of iris.csv on screen

    Context

    • Operating System and version:
    • MacOS 11.2.3
    • MacBook Air (M1, 2020)
    • Apple M1 chip
    • Browser and version: Brave Version 1.24.84 Chromium: 90.0.4430.93 (Official Build) (arm64)
    • JupyterLite version: can't find version number but I did this today (2021/06/01) using JupyterLite for the first time
    Browser Output
    Dispose worker for kernel 7f928317-a338-41fb-9c00-6c1d041909fd
    default.js:1228 Connection lost, reconnecting in 0 seconds.
    _reconnect @ default.js:1228
    reconnect @ default.js:516
    restart @ default.js:487
    async function (async)
    restart @ default.js:484
    restartKernel @ sessioncontext.js:298
    restart @ sessioncontext.js:758
    async function (async)
    restart @ sessioncontext.js:733
    onClick @ toolbar.js:343
    y.createElement.onMouseDown @ toolbar.js:402
    Be @ react-dom.production.min.js:52
    Ke @ react-dom.production.min.js:52
    (anonymous) @ react-dom.production.min.js:53
    xr @ react-dom.production.min.js:100
    Cr @ react-dom.production.min.js:101
    (anonymous) @ react-dom.production.min.js:113
    De @ react-dom.production.min.js:292
    (anonymous) @ react-dom.production.min.js:50
    Lr @ react-dom.production.min.js:105
    Zn @ react-dom.production.min.js:75
    Jn @ react-dom.production.min.js:74
    n.unstable_runWithPriority @ scheduler.production.min.js:18
    Bl @ react-dom.production.min.js:122
    Me @ react-dom.production.min.js:292
    Xn @ react-dom.production.min.js:73
    pyodide.asm.js:9 Python initialization complete
    pyodide.js:146 Loading matplotlib, cycler, six, kiwisolver, numpy, pillow, pyparsing, python-dateutil, pytz
    pyodide.js:196 Loading matplotlib from https://cdn.jsdelivr.net/pyodide/v0.17.0/full/matplotlib.js
    pyodide.js:196 Loading cycler from https://cdn.jsdelivr.net/pyodide/v0.17.0/full/cycler.js
    pyodide.js:196 Loading six from https://cdn.jsdelivr.net/pyodide/v0.17.0/full/six.js
    pyodide.js:196 Loading kiwisolver from https://cdn.jsdelivr.net/pyodide/v0.17.0/full/kiwisolver.js
    pyodide.js:196 Loading numpy from https://cdn.jsdelivr.net/pyodide/v0.17.0/full/numpy.js
    pyodide.js:196 Loading pillow from https://cdn.jsdelivr.net/pyodide/v0.17.0/full/pillow.js
    pyodide.js:196 Loading pyparsing from https://cdn.jsdelivr.net/pyodide/v0.17.0/full/pyparsing.js
    pyodide.js:196 Loading python-dateutil from https://cdn.jsdelivr.net/pyodide/v0.17.0/full/python-dateutil.js
    pyodide.js:196 Loading pytz from https://cdn.jsdelivr.net/pyodide/v0.17.0/full/pytz.js
    pyodide.js:252 Loaded matplotlib, cycler, six, kiwisolver, numpy, pillow, pyparsing, python-dateutil, pytz
    pyodide.js:146 Loading micropip, pyparsing, packaging
    pyodide.js:196 Loading micropip from https://cdn.jsdelivr.net/pyodide/v0.17.0/full/micropip.js
    pyodide.js:184 pyparsing already loaded from default channel
    pyodide.js:196 Loading packaging from https://cdn.jsdelivr.net/pyodide/v0.17.0/full/packaging.js
    pyodide.js:252 Loaded micropip, pyparsing, packaging
    8ebb3553-36cc-44b7-9b0c-539a2f402d28:29 Pyolite kernel initialized, version 0.1.0
    8ebb3553-36cc-44b7-9b0c-539a2f402d28:63 Inside worker {code: "import pandas as pd"}
    pyodide.js:146 Loading pandas, numpy, python-dateutil, pytz
    pyodide.js:196 Loading pandas from https://cdn.jsdelivr.net/pyodide/v0.17.0/full/pandas.js
    pyodide.js:184 numpy already loaded from default channel
    pyodide.js:184 python-dateutil already loaded from default channel
    pyodide.js:184 pytz already loaded from default channel
    pyodide.js:252 Loaded pandas, numpy, python-dateutil, pytz
    8ebb3553-36cc-44b7-9b0c-539a2f402d28:63 Inside worker {code: "pd.read_csv("iris.csv")"}code: "pd.read_csv(\"iris.csv\")"__proto__: Object
    
    opened by mklilley 23
  • Update to jupyterlab 3.1.0rc2

    Update to jupyterlab 3.1.0rc2

    References

    Code changes

    • [x] bump baseline verisons
    • [x] resolve yarn, environment
    • [x] check package versions vs imports in check
    • [x] handle the context plugin
      • didn't have to do anything :tada:

    • [x] reorganize non-kernel/shell patches/mocks while investigating demo fails
      • each patch/mock is now wrapped in a try, and no longer brings down the whole runtime if one fails

    • [x] retro stuff??

    User-facing changes

    | thing | screenshot | |-|-| | see context menu | Screenshot from 2021-07-21 16-08-38

    Backwards-incompatible changes

    • ???
    maintenance 
    opened by bollwyvl 22
  • Upgrade to pyodide 0.21.0

    Upgrade to pyodide 0.21.0

    References

    • blocked by #671
      • currently causes a hard crash in pyodide when some files come back with null/undefined properties stat properties
    • fixes #766
    • fixes #648

    Code Changes

    • updates to pyodide 0.21.0
    • handles rather significant micropip API changes
      • updates references to pyodide repodata.json (was packages.json)
      • updates supported wheel prefixes
      • removes cache-busting for fetched wheels (uses string comparisons for e.g. endswith('.whl')
        • really only a problem for tight development loops with in-development wheels that don't change their name
    • initialize more size attributes for stats, which cause nasty, irrecoverable/uncatchable failures in pyodide

    Backwards-incompatible Changes

    • can't use pyodide installations older than 0.21.0
      • old-style wheels won't work
      • micropip API has changed drastically
    enhancement api-change 
    opened by agoose77 21
  • Add list of federated extensions for the demo site

    Add list of federated extensions for the demo site

    References

    Initial steps for #83

    Code changes

    Demo site changes only.

    User-facing changes

    Users of the RTD demo will be able to use some federated extensions by default.

    Backwards-incompatible changes

    None

    opened by jtpio 20
  • Use IPython in Pyolite kernel

    Use IPython in Pyolite kernel

    Using await micropip.install('ipython') and then import IPython works in the notebook. However, we want to be able to import IPython by default, so it makes sense to run await micropip.install('ipython') in the worker.ts script.

    However, it doesn't work and we get ModuleNotFoundError: No module named 'IPython' on using import IPython in the notebook.

    enhancement 
    opened by madhur-tandon 19
  • federated extensions, webpack sharing, deploying/configuring docs

    federated extensions, webpack sharing, deploying/configuring docs

    References

    • for #55

    Code changes

    • [x] Adds build from upstreams
    • [x] better handle setting federated_extensions in the index.html files
    • [x] try with a simple extension that has schemas, for example: https://github.com/jtpio/jupyterlab-cell-flash
      • for now schemas are all bundled into a all.json file on build:
    • [x] be able to just copy the prebuilt extension assets to lab/extensions
      • not have to edit all.json when new federated extensions are installed?
    • [x] settings service will have to be aware of federated extensions
      • [x] dynamically construct the list of all settings in this getAll() method.
    • [ ] a @jupyterlite/top (or site or something) that carries and abstracts some of the boilerplate
      • [ ] should be able to dedupe the app webpack bundles

    User-facing changes

    Deployer

    • Someone who wants to deploy a site would be able to
      • at the very leasst on this PR
        • drop some well-formed packages in <app>/extensions (as copied from $share/labextensions)
        • run a .py and/or .js script to update various all.json files

    End User

    • n/a (though load times might be.... different, due to multiple packages)

    Backwards-incompatible changes

    ?

    enhancement 
    opened by bollwyvl 19
  • Initial support for real time collaboration

    Initial support for real time collaboration

    References

    #88

    To try it out

    https://jupyterlite--109.org.readthedocs.build/en/109/_static/lab/index.html?room=the-coolest-room

    https://user-images.githubusercontent.com/591645/120011349-787c7780-bfde-11eb-94a5-f8ae0808128e.mp4

    Code changes

    • [x] Switch to WebrtcProvider
    • [x] Set collaborative to true on the demo site
    • [x] Basic link sharing to group users in rooms
    • [x] ~Extra URL parameter to enable RTC? For example ?rtc=1 to enable, disabled otherwise~ -> not needed
    • [x] Update the docs to show how to use RTC features

    User-facing changes

    Add options to enable RTC to end users.

    Backwards-incompatible changes

    enhancement 
    opened by jtpio 18
  • Add seaborn example

    Add seaborn example

    References

    Fixes https://github.com/jupyterlite/jupyterlite/issues/919

    Code changes

    Add an example notebook for seaborn.

    User-facing changes

    Backwards-incompatible changes

    None

    documentation 
    opened by jtpio 6
  • Handling of failing addon entry_points

    Handling of failing addon entry_points

    References

    • from #934

    Problem

    from https://github.com/jupyterlite/jupyterlite/pull/934#discussion_r1059924167

           try:
               addon_implementations[name] = entry_point.load()
           except Exception as err:  # pragma: no cover
               warnings.warn(f"[lite] [{name}] failed to load: {err}")
    

    It could be convenient if this was an exception instead, I've seen cases where the xeus-python addon would fail to load and it would have been convenient for jupyter lite build to not continue building.

    Proposed Solution

    Some options:

    • check the strict mode (True by default) and fail on any entry_point.load()
      • maybe still try to .load() all of them, and collect and print all the errors together
        • getting all of the tracebacks is often useful, though, too
      • this is a breaking change, but not a huge one
    • ??? please add more :P

    Additional context

    ...

    enhancement 
    opened by bollwyvl 2
  • Strange inconsistency with the file system

    Strange inconsistency with the file system

    Description

    I am playing around with JupyterLite, and I often end up facing a problem with the file system. It basically goes as follows:

    1. When opening for the first time an instance served by a static Github Page such as this one, if I enter the command pwd I get in return /drive. This is important because it means that Pyodide is able to "see" what is in the contents folder, and I can import local scripts.
    2. After a while playing with the repo, making some changes, something breaks. The command pwd returns /home/pyodide, and files in the browser become invisible to pyodide (I explored the filesystem with os and there is no drive folder to be found. This means that I cannot do anymore local imports.

    Reproduce

    I am sorry that I cannot yet point to what exactly I do wrong. I have a hard time reproducing consistently the issue, yet it happened twice to me.

    A few elements though:

    • if I open the webpage from a different browser there is no problem at all.
    • I usually install both pyodide and Xeus-python to compare them

    I hope this makes sense to someone.

    • JupyterLite version: I use a clone of https://github.com/jupyterlite/demo
    • Operating System and version: Windows 10
    • Browser and version: Firefox 108
    bug 
    opened by Guillaume-Garrigos 2
  • Hoist the Python package to the top-level?

    Hoist the Python package to the top-level?

    Problem

    Currently the jupyterlite Python package is located under py/jupyterlite: https://github.com/jupyterlite/jupyterlite/tree/main/py/jupyterlite

    If I recall correctly this was mostly to accommodate the potential new Python packages that would be developed in the monorepo such as https://github.com/jupyterlite/jupyterlite/issues/165.

    Proposed Solution

    With the use of CLI addons and support for federated extensions, maybe there won't be any needs for new Python packages in the same jupyterlite repository.

    If we want to provide more Python packages, maybe they could live outside of the main repo but within the jupyterlite org on GitHub: https://github.com/jupyterlite

    Benefits for hoisting the Python package to the top-level would be:

    • a single pyproject.toml (the others in Pyolite will be moved to https://github.com/jupyterlite/pyodide-kernel with #854)
    • no need to sync the README.md
    • follow the same structure as many other Jupyter projects

    Additional context

    In https://github.com/jupyterlite/jupyterlite/pull/854 and some other issues there were also mentions of having a jupyterlite_core or jupyterliter, and make jupyterlite a metapackage to distribute JupyterLite with a set of pre-defined packages.

    Even if that was the case, maybe the jupyterlite metapackage could then also live outside in the main repo but still in https://github.com/jupyterlite.

    enhancement question 
    opened by jtpio 1
  • Lite Kernels: dependencies consistency with JupyterLite

    Lite Kernels: dependencies consistency with JupyterLite

    When loading a jupyter lite kernel, we need to ensure that the jupyterlite version used to run the kernel (or at least the versions of jupyterlite packages which are dependencies of the lite kernel) is the same as that used to build the lite kernel, otherwise the kernel crashes.

    enhancement 
    opened by JohanMabille 10
Releases(v0.1.0b17)
Owner
JupyterLite
Wasm powered Jupyter running in the browser 💡
JupyterLite
Multi-user server for Jupyter notebooks

Technical Overview | Installation | Configuration | Docker | Contributing | License | Help and Resources Please note that this repository is participa

JupyterHub 7k Jan 2, 2023
JupyterLite is a JupyterLab distribution that runs entirely in the browser power by wasm

JupyterLite is a JupyterLab distribution that runs entirely in the browser built from the ground-up using JupyterLab components and extensions.

Jeremy Tuloup 76 Dec 13, 2022
Performance data for WASM SIMD instructions.

WASM SIMD Data This repository contains code and data which can be used to generate a JSON file containing information about the WASM SIMD proposal. F

Evan Nemerson 5 Jul 24, 2022
edgedressing leverages a Windows "feature" in order to force a target's Edge browser to open. This browser is then directed to a URL of choice.

edgedressing One day while experimenting with airpwn-ng, I noticed unexpected GET requests on the target node. The node in question happened to be a W

stryngs 43 Dec 23, 2022
Browser - A GTK browser trying to follow the GNOME Human Interface Guidelines.

A simple GTK browser trying to follow the GNOME Human Interface Guidelines.

Cleo Menezes 12 Nov 26, 2022
Dot Browser is a privacy-conscious web browser with smarts built-in for protection against trackers and advertisments online.

?? Take back your privacy with Dot Browser, the privacy-conscious web browser that protects you from being tracked and monitored online.

Dot HQ 1k Jan 7, 2023
lfb (light file browser) is a terminal file browser

lfb (light file browser) is a terminal file browser. The whole program is a mess as of now. In the feature I will remove the need for external dependencies, tidy up the code, make an actual readme, add documentation, and change the name.

null 2 Apr 9, 2022
Hexa is an advanced browser.It can carry out all the functions present in a browser.

Hexa is an advanced browser.It can carry out all the functions present in a browser.It is coded in the language Python using the modules PyQt5 and sys mainly.It is gonna get developed more in the future.It is made specially for the students.Only 1 tab can be used while using it so that the students cant missuse the pandemic situation :)

null 1 Dec 10, 2021
SymPy-powered, Wolfram|Alpha-like answer engine totally in your browser, without backend computation

SymPy Beta SymPy Beta is a fork of SymPy Gamma. The purpose of this project is to run a SymPy-powered, Wolfram|Alpha-like answer engine totally in you

Liumeo 25 Dec 21, 2022
Run your jupyter notebooks as a REST API endpoint. This isn't a jupyter server but rather just a way to run your notebooks as a REST API Endpoint.

Jupter Notebook REST API Run your jupyter notebooks as a REST API endpoint. This isn't a jupyter server but rather just a way to run your notebooks as

Invictify 54 Nov 4, 2022
Euporie is a text-based user interface for running and editing Jupyter notebooks

Euporie is a text-based user interface for running and editing Jupyter notebooks

null 781 Jan 1, 2023
Magma is a NeoVim plugin for running code interactively with Jupyter.

Magma Magma is a NeoVim plugin for running code interactively with Jupyter. Requirements NeoVim 0.5+ Python 3.8+ Required Python packages: pynvim (for

Daniel Csillag 372 Dec 26, 2022
Infrastructure template and Jupyter notebooks for running RoseTTAFold on AWS Batch.

AWS RoseTTAFold Infrastructure template and Jupyter notebooks for running RoseTTAFold on AWS Batch. Overview Proteins are large biomolecules that play

AWS Samples 20 May 10, 2022
Interactive Data Visualization in the browser, from Python

Bokeh is an interactive visualization library for modern web browsers. It provides elegant, concise construction of versatile graphics, and affords hi

Bokeh 17.1k Dec 31, 2022
robobrowser - A simple, Pythonic library for browsing the web without a standalone web browser.

RoboBrowser: Your friendly neighborhood web scraper Homepage: http://robobrowser.readthedocs.org/ RoboBrowser is a simple, Pythonic library for browsi

Joshua Carp 3.7k Dec 27, 2022
Simple plotting for Python. Python wrapper for D3xter - render charts in the browser with simple Python syntax.

PyDexter Simple plotting for Python. Python wrapper for D3xter - render charts in the browser with simple Python syntax. Setup $ pip install PyDexter

D3xter 31 Mar 6, 2021
A Python library that provides an easy way to identify devices like mobile phones, tablets and their capabilities by parsing (browser) user agent strings.

Python User Agents user_agents is a Python library that provides an easy way to identify/detect devices like mobile phones, tablets and their capabili

Selwin Ong 1.3k Dec 22, 2022
Websockify is a WebSocket to TCP proxy/bridge. This allows a browser to connect to any application/server/service. Implementations in Python, C, Node.js and Ruby.

websockify: WebSockets support for any application/server websockify was formerly named wsproxy and was part of the noVNC project. At the most basic l

noVNC 3.3k Jan 3, 2023
A browser automation framework and ecosystem.

Selenium Selenium is an umbrella project encapsulating a variety of tools and libraries enabling web browser automation. Selenium specifically provide

Selenium 25.5k Jan 1, 2023