BROWSER

Running it

Building your own image

Extending the published image with your dependencies, the version lock between Browser and Playwright, and using it as a CI job container.

The published image runs a plain Robot Framework suite. As soon as your suite imports another library, needs a driver, or wants a specific Python version, you need an image of your own.

The good news is that it is a handful of lines — the published image already runs as pwuser, so the USER line below is only insurance. The thing to be careful about is the version lock described further down — it is the one way to build an image that looks fine and fails at runtime.

Add your dependencies

FROM marketsquare/robotframework-browser:20.3.0USER pwuserCOPY --chown=pwuser requirements.txt /home/pwuser/RUN pip install --no-cache-dir -r /home/pwuser/requirements.txt
Dockerfile5 linesUTF-8

pip resolves to the virtualenv at /home/pwuser/.venv, which is already on PATH, so there is no activation step.

Pin the base image to an exact release, not latest. A pipeline that rebuilds weekly against latest will one day upgrade Browser under you, and the failure will arrive on a day when nothing in your repository changed.

Bake your suite in, or mount it?

Both are legitimate and they answer different questions.

Mount at run time`COPY` into the image

Mounting is the right default. Reach for COPY when the image itself has to be the deliverable — a smoke test handed to an ops team, for instance.

The version lock

This is the part that bites.

Browser is built against one specific Playwright version, and the browser binaries in the base image are the ones that Playwright version ships. Three things must agree:

  1. the Browser library,
  2. the Playwright npm package Browser installs,
  3. the browser binaries baked into the image.

The published image gets this right by construction: it starts from mcr.microsoft.com/playwright:v1.62.0-noble, and the Browser release it installs is built against Playwright 1.62.1. Those two can differ by a patch — the FROM line is bumped by hand — so if you are chasing a binary-level mismatch, compare them rather than assuming they agree.

Upgrading Browser inside a derived image breaks that. This looks harmless and is not:

FROM marketsquare/robotframework-browser:20.3.0RUN pip install --upgrade robotframework-browser   # don't

You now have a newer Browser expecting a newer Playwright, driving the browser binaries of the older one. What happens next depends on how far apart they are — which is worse than failing outright, because it can work for months and then not.

To move to a newer Browser, change the base image tag. That is the entire upgrade procedure, and it is the reason the tag exists.

If you genuinely must install a different Browser version in the same image, you own the whole chain: reinstall the Node side and let it fetch matching binaries (rfbrowser clean-node && rfbrowser init, which downloads a second, matching browser set — into the library's node_modules when PLAYWRIGHT_BROWSERS_PATH is unset, otherwise wherever it points, which in this base image is Playwright's own directory — while the base image's binaries stay on disk, so you pay for both), or install browsers separately and point PLAYWRIGHT_BROWSERS_PATH at them. Both give up what the image was for.

As a CI job container

Most CI systems can run a job inside an image, which removes the docker run line entirely — your steps execute in the container, and the checkout is already there.

jobs:  robot:    runs-on: ubuntu-latest    container:      image: marketsquare/robotframework-browser:20.3.0      options: --ipc=host --user pwuser    steps:      - uses: actions/checkout@v7      - run: robot --outputdir output tests/      - uses: actions/upload-artifact@v7        if: always()        with:          name: robot-results          path: output/
YAML14 linesUTF-8

Two details are load-bearing. --ipc=host and --user pwuser still apply — a job container gets no flags you do not give it. And if: always() on the upload: without it the results are discarded on exactly the runs where you needed them.

Building the official image yourself

The Dockerfiles live in docker/ in the library repository, and the same directory's README documents the local build and the pull-request image. Reach for it if you need to reproduce the official image with a change — a different Python version, a different base — or if you are contributing to Browser itself.

cd dockerdocker build --no-cache -t my-rfbrowser --file Dockerfile.latest_release .

For anything short of that, extending the published image is less work and stays correct through upgrades.