Supported environments matrix#
This page answers: “Will notebook embedding + hooks work in my environment?”
Short answer: yes, usually, as long as the browser can reach the Cellucid server URL used by the embedded iframe.
The hooks system is designed to avoid brittle notebook-specific machinery:
Python → viewer commands use
postMessageinto the iframe.Viewer → Python events use HTTP POST to
/_cellucid/eventson the local server.
At a glance#
Audience
Wet lab / beginner: check your environment row, then use the quickstart.
Computational users: pay attention to HTTPS/remote and to “browser can reach the server”.
Developers/IT: read the proxy + security notes and the network requirements.
Start here
Quickstart sanity check: Quickstart: minimal round-trip (select → highlight)
Mixed content / HTTPS details: Security: CORS, origins, and mixed content
Matrix#
Legend:
✅ should work with defaults
⚠️ works, but you may need one extra step
❌ not supported (or not a notebook environment)
Environment |
Embed viewer |
Python → viewer commands |
Viewer → Python events |
Session bundle “no-download” |
Notes |
|---|---|---|---|---|---|
Classic Jupyter (local) |
✅ |
✅ |
✅ |
✅ |
Direct loopback ( |
JupyterLab (local) |
✅ |
✅ |
✅ |
✅ |
Same as classic when the browser can reach loopback. |
VSCode notebooks (local kernel) |
✅ |
✅ |
✅ |
✅ |
Works as long as the VSCode webview can reach the server URL. |
Google Colab |
⚠️ |
✅ |
✅ |
✅ |
Obtain Colab’s browser-reachable HTTPS proxy base and pass it as |
JupyterHub / hosted Jupyter (HTTPS) |
⚠️ |
✅ |
✅ |
✅ |
Expose the Cellucid port through an HTTPS proxy and pass its exact base as |
Remote kernel over SSH (browser on laptop) |
⚠️ |
✅ |
✅ |
✅ |
Forward the port, then pass the forwarded browser base as |
“Notebook” served from |
⚠️ |
✅ |
✅ |
✅ |
Pass an exact HTTP(S) |
Not in Jupyter (plain Python script) |
❌ |
❌ |
❌ |
❌ |
Use |
Important
The biggest real-world failure mode is connectivity, not hooks logic:
The viewer iframe is loaded in a browser tab, but the Python server is not reachable from that browser origin.
When this happens, the UI may show errors like “Failed to fetch”, selection events won’t arrive, and highlighting commands won’t do anything.
Network requirement: exact viewer generation#
In notebooks, Cellucid serves one verified local viewer generation:
At each viewer/server startup, Python establishes the complete generation declared by
https://www.cellucid.com/cellucid-web-assets.json.The generation includes
index.html, root browser metadata, and all declared assets; every byte is verified before publication.The selected generation lives on disk (configure with
web_cache_dir=).Startup requires access to the configured source and never substitutes a previous generation after source failure.
See:
Security: CORS, origins, and mixed content (why this exists + mixed content)
Troubleshooting (hooks) (“Viewer UI could not be loaded”)
Environment-specific notes (with actionable fixes)#
JupyterHub / HTTPS notebooks: browser cannot reach loopback#
If your notebook is served over HTTPS and your Cellucid server is plain HTTP on loopback, browsers may block it as mixed content.
Expose the Cellucid port through an HTTPS proxy, then construct its exact base URL, for example:
https://<notebook-origin>/<base>/proxy/<port>/?jupyter=true&viewerId=...&viewerToken=...
With Jupyter Server Proxy, the notebook administrator must install and enable
that extension’s server route and the caller must pass the resulting browser
base as client_server_url=.... The Cellucid package already depends on
jupyter-server-proxy; package installation alone does not expose a route or
select its URL.
If the direct iframe is blocked:
expose the port through an HTTPS reverse proxy and pass its exact base as
client_server_url=..., oruse SSH port forwarding and pass the local forwarded base.
Google Colab#
Colab runs the kernel on a remote VM. Obtain its proxy URL in the notebook:
from google.colab.output import eval_js
eval_js("google.colab.kernel.proxyPort(<port>)")
Then pass the returned base to show_anndata(..., client_server_url=base).
Cellucid does not invoke Colab’s proxy API implicitly.
Practical implications:
The viewer URL must be the explicit HTTPS proxy URL, not remote loopback.
Each viewer startup still establishes the configured exact web generation.
Remote / HPC kernels (browser on laptop)#
If your notebook kernel runs on a remote machine but you view the notebook in a browser on your laptop, you must bridge the server port.
Most robust: SSH local port forwarding (example uses port 8765):
In the notebook (remote):
from cellucid import AnnDataViewer viewer = AnnDataViewer( "data.h5ad", port=8765, dataset_name="Example", dataset_id="example", client_server_url="http://127.0.0.1:8765", ) print(viewer.viewer_url)
On your laptop:
ssh -N -L 8765:127.0.0.1:8765 <user>@<remote-host>
Now the exact printed
http://127.0.0.1:8765/?jupyter=true&viewerId=...&viewerToken=... URL in your
browser forwards to the remote kernel.
Edge cases#
Ad blockers / corporate proxies can block POSTs to
/_cellucid/events(hooks) or block downloads fromhttps://www.cellucid.com.Kernel restarts can orphan an iframe tab; re-run the cell to create a fresh viewer/server pair.
Multiple viewers in one notebook are supported (routing uses
viewerId), but can be confusing during debugging—useviewer.debug_connection().
Troubleshooting#
Run:
viewer.debug_connection()
Then follow: Troubleshooting (hooks)
Next steps#
Minimal working loop: Quickstart: minimal round-trip (select → highlight)
Architecture details: Architecture: message routing (HTTP vs postMessage)