Streaming ROS camera topics to a web browser
Set up web_video_server on ROS 1 or ROS 2, pick a stream format, build the stream URL, embed the feed in your own page and fix the usual connection problems.
Want to see what your robot sees, from a laptop or a phone, without installing anything? The web_video_server package turns any ROS image topic into a video stream that a normal web browser can open. This is handy for remote monitoring, teleoperation dashboards and demos.
How it works
$$ \underbrace{\text{Camera driver}}_{\text{ROS node}} \;\rightarrow\; \underbrace{\texttt{/camera/image\_raw}}_{\text{ROS topic}} \;\rightarrow\; \underbrace{\texttt{web\_video\_server}}_{\text{HTTP server, port 8080}} \;\rightarrow\; \text{Browser} $$
The server subscribes to the image topic only while someone is watching, encodes the frames and sends them over HTTP.
What you need
- ROS 1 Noetic or ROS 2 (Humble or newer)
- A node that publishes images, for example a camera driver or a Gazebo camera
- Any modern browser
1. Install
Use the package from your ROS distribution:
# ROS 2 (replace humble with your distribution, e.g. jazzy)
sudo apt install ros-humble-web-video-server
# ROS 1 Noetic
sudo apt install ros-noetic-web-video-serverIf no package exists for your distribution, build it from source in your workspace:
cd ~/ros2_ws/src
git clone https://github.com/RobotWebTools/web_video_server.git
cd ~/ros2_ws
rosdep install --from-paths src --ignore-src -y
colcon build --packages-select web_video_server
source install/setup.bash2. Start a camera and the server
Check that an image topic is being published:
ros2 topic list | grep image # ROS 1: rostopic list | grep image
ros2 topic hz /camera/image_raw # should show a steady rateThen start the server:
ros2 run web_video_server web_video_server # ROS 2, port 8080
ros2 run web_video_server web_video_server --ros-args -p port:=8081 # another port
rosrun web_video_server web_video_server _port:=8081 # ROS 13. Open it in the browser
Go to http://localhost:8080 on the robot, or http://<robot-ip>:8080 from another device on the same network. The page lists every image topic; click one to watch it.
Building the stream URL yourself
Every stream has its own address, so you can put it in your own pages:
http://<robot-ip>:8080/stream?topic=/camera/image_raw&type=mjpeg&quality=60&width=640&height=480| Parameter | Meaning |
|---|---|
topic |
The ROS image topic (required) |
type |
Stream format, see the table below (default mjpeg) |
width, height |
Resize the image before sending; saves bandwidth |
quality |
JPEG quality from 1 to 100 (for mjpeg) |
bitrate |
Target bitrate (for vp8, vp9, h264) |
Two more endpoints are useful: /snapshot?topic=... returns a single JPEG image, and /stream_viewer?topic=... shows the stream on a ready-made page.
Which format to choose
type |
Good for | Note |
|---|---|---|
mjpeg |
Most cases, lowest delay | Works in every browser inside an <img> tag; uses more bandwidth |
vp8, vp9 |
Slow networks | Better compression, needs a <video> tag, a little more delay |
h264 |
Slow networks | Good compression; browser support varies |
png |
Exact images | Lossless, large |
ros_compressed |
Cameras that already publish compressed images | Passes the JPEG through without re-encoding |
Embedding the stream in your own page
An MJPEG stream behaves like an image, so one line of HTML is enough:
<img src="http://192.168.1.20:8080/stream?topic=/camera/image_raw&type=mjpeg&quality=60"
alt="Live view from the robot camera" width="640">For a small dashboard, put several <img> tags side by side, one per camera, and add buttons that change the topic in the address with a line of JavaScript.
Troubleshooting
| Problem | Check |
|---|---|
| The page lists no topics | Is the camera node running? ros2 topic list. Is the message type sensor_msgs/Image? ros2 topic info /your/topic |
| The page does not open | Is the server running? ros2 node list. Is port 8080 already used, or blocked by a firewall (sudo ufw allow 8080)? |
| Works on the robot but not from a laptop | Use the robot's IP, not localhost. Both devices must be on the same network. Make sure the address parameter is 0.0.0.0 (all interfaces) |
| Stream is slow or jerky | Lower quality, add width and height, or switch to vp8 on weak Wi-Fi |
| Black or frozen image | Check the camera itself: ros2 run rqt_image_view rqt_image_view |
A note on security
web_video_server has no login. Anyone who can reach the port can watch the camera. On a shared or public network, keep it behind a VPN, or put a reverse proxy such as nginx with authentication and HTTPS in front of it.
Why it is worth setting up
Being able to open the robot's camera from any browser makes remote monitoring, debugging and demonstrations much easier, and it is the first building block of a web-based control panel for telepresence, inspection or teaching robots.