{"id":9027,"library":"h2o-wave","title":"H2O Wave","description":"H2O Wave is a lightweight software stack for building beautiful, low-latency, real-time, browser-based applications and dashboards entirely in Python, without requiring HTML, Javascript, or CSS expertise. It excels at capturing data, visualizations, and graphics from multiple sources and broadcasting them live over the web. The current version is 1.8.4, with frequent releases often including security updates.","status":"active","version":"1.8.4","language":"en","source_language":"en","source_url":"https://github.com/h2oai/wave","tags":["web framework","dashboard","realtime","GUI","analytics","data visualization"],"install":[{"cmd":"pip install h2o-wave","lang":"bash","label":"Install with pip"}],"dependencies":[],"imports":[{"note":"The 'query' object (q) passed to app handlers, containing request arguments and methods for page manipulation.","symbol":"Q","correct":"from h2o_wave import Q"},{"note":"Used to mark the entry point function for a Wave app.","symbol":"main","correct":"from h2o_wave import main"},{"note":"Decorator to register a Python function as a Wave app at a specific route.","symbol":"app","correct":"from h2o_wave import app"},{"note":"Module containing all UI components (cards, widgets) for building the application interface.","symbol":"ui","correct":"from h2o_wave import ui"}],"quickstart":{"code":"from h2o_wave import Q, app, ui, main\n\n@app('/')\nasync def serve(q: Q):\n    q.page['hello'] = ui.markdown_card(\n        box='1 1 2 2',\n        title='Hello World!',\n        content='This is a simple H2O Wave app.'\n    )\n    await q.page.save()\n\n# To run this app, save it as `app.py` and execute `wave run app.py` in your terminal.\n# Then, navigate to http://localhost:10101 in your browser.","lang":"python","description":"This 'Hello World' example demonstrates a basic Wave application. It defines a single page with a Markdown card displaying a title and content. The `@app('/')` decorator registers the `serve` function to handle requests at the root URL. The `Q` object provides access to the current page and other context. `ui` is used to create UI components. Finally, `await q.page.save()` sends the page updates to the browser."},"warnings":[{"fix":"Review the official Wave 1.0 changelog and update routing logic, preferably adopting the `handle_on` mechanism for reliable event handling.","message":"Wave 1.0 introduced minor breaking changes, particularly affecting routing. The `handle_on` mechanism was introduced to address issues with `q.args` order, which could lead to unexpected behavior in older versions.","severity":"breaking","affected_versions":"<1.0"},{"fix":"Ensure `waved` (the Go-based Wave server) is running and accessible to your Python Wave app, usually via `H2O_WAVE_ADDRESS` environment variable if on separate machines or containers.","message":"When deploying with an ASGI server like Uvicorn, the Wave server (`waved`) must be run separately from the Python app. `wave run` automatically starts `waved` for development, but for production, you need to manage both processes independently.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Understand and correctly apply state scopes: `q.app` for global application state, `q.user` for per-user state across all their sessions, and `q.client` for per-browser-tab state.","message":"Incorrect usage of state scopes (`q.app`, `q.user`, `q.client`) can lead to performance or UX issues. For example, loading a static dataset into `q.client` will cause it to be re-uploaded for every browser connection, wasting resources.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Always ensure your app handler explicitly updates at least one UI element, even a non-existent one (`q.page['non-existent'].items = []`), or provide user feedback, to clear the loading spinner.","message":"In `unicast` mode (the default for applications), if a button click or other event handler does not result in *any* UI update (e.g., just printing to console), the UI may appear to hang with an infinite loading spinner.","severity":"gotcha","affected_versions":"All versions"},{"fix":"For production, ensure proper TLS certificates are configured and verified for all communication, and do not disable TLS verification.","message":"Disabling TLS verification using `H2O_WAVE_NO_TLS_VERIFY` environment variable or `--no-tls-verify` parameter is a significant security risk and should only be done for development purposes, never in production environments.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Start the `waved` server separately. If running on different hosts or non-default ports, configure the Wave app with `H2O_WAVE_ADDRESS` environment variable to point to the correct `waved` address, e.g., `H2O_WAVE_ADDRESS='http://your-waved-host:10101'`.","cause":"The Python Wave app (running via Uvicorn, Gunicorn, etc.) cannot connect to the H2O Wave server (`waved`). This often happens when `waved` is not running or is not accessible at the expected address/port.","error":"httpx connection err [Errno 111] Connect call failed"},{"fix":"Even if no visual change is intended, explicitly update a UI component or a dummy card within your handler (e.g., `q.page['feedback_card'] = ui.message_bar(type='info', text='Action complete!')` or `q.page['temp'].items = []`) before `await q.page.save()`.","cause":"The app handler for the button click event completed without making any changes to `q.page` or updating any UI component. In unicast mode, the browser expects a UI update to acknowledge the event and dismiss the loading state.","error":"UI hangs in an infinite loading spinner after button click (in unicast mode)."},{"fix":"Navigate to `/Applications/Python X.Y` (where X.Y is your Python version) and execute the `Install Certificates.command` script. This updates the certificate store.","cause":"This error on macOS indicates that Python's SSL certificate store is not correctly configured or updated, preventing it from verifying SSL certificates when downloading resources.","error":"urllib.error.URLError: urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (on macOS during `wave fetch`)"}]}