# rclnodejs/web — Browser SDK guide > Talk to ROS 2 from a web app — typed, allow-listed, `curl`-able. `rclnodejs/web` is the browser-side of `rclnodejs`: a compact ESM module plus a server runtime that together expose a declarative subset of your ROS 2 graph over WebSocket **and** plain HTTP. The browser API is three verbs — `call`, `publish`, `subscribe` — typed end-to-end from your ROS 2 message and service types. For runnable code see [`demo/web/`](../demo/web/): | Demo | Pick this if you… | | ------------------------------------------------- | --------------------------------------------------------------------------- | | [`demo/web/javascript/`](../demo/web/javascript/) | want a single static page — no build tools, no `npm install` for the page | | [`demo/web/typescript/`](../demo/web/typescript/) | already have a Vite / Next / React / Vue / Svelte project, want full typing | ## 1. Server side: stand up the runtime > `-p rclnodejs` tells npx the `rclnodejs-web` binary lives inside the > `rclnodejs` package; drop it once `rclnodejs` is already installed in > the current project. ```bash source /opt/ros//setup.bash npx -p rclnodejs rclnodejs-web \ --port 9000 --http-port 9001 \ --call /add_two_ints=example_interfaces/srv/AddTwoInts \ --publish /chatter=std_msgs/msg/String \ --subscribe /scan=sensor_msgs/msg/LaserScan # rclnodejs/web listening on ws://localhost:9000/capability (3 capabilities) # also http://localhost:9001/capability (call/publish only) ``` Or feed the same allow-list from `web.json`: ```json { "port": 9000, "http": { "port": 9001 }, "expose": { "call": { "/add_two_ints": "example_interfaces/srv/AddTwoInts" }, "publish": { "/chatter": "std_msgs/msg/String" }, "subscribe": { "/scan": "sensor_msgs/msg/LaserScan" } } } ``` ```bash npx -p rclnodejs rclnodejs-web web.json ``` > The `expose` block is the **public API** your browser depends on. > Anything not listed is rejected with `code: 'not_exposed'` before > any ROS 2 API runs. Keep it narrow. ## 2. Client side: talk to it from the browser ### Connect ```ts import { connect } from 'rclnodejs/web'; // or via esm.sh in a