diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index af8d73a7fa09280bf6b5c01f29330cc5d8e77f25..69d24dd60690229f664e03241332bf8d48d7c278 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -31,4 +31,11 @@ test:
     - xzcat /tmp/testdata.$CI_JOB_ID/noblogs/noblogs.sql.xz | mysql --user=root --password=rootpass --host=mysql noblogs
     - for blog in cavallette detriti docs ; do xzcat /tmp/testdata.$CI_JOB_ID/noblogs/noblogs_${blog}.sql.xz | mysql --user=root --password=rootpass --host=mysql noblogs; done
     - with-container --expose=8080 --mount=type=bind,source=docker/test-config.json,destination=/etc/noblogs/config.json --mount=type=tmpfs,destination=/opt/noblogs/www/wp-content/blogs.dir --mount=type=tmpfs,destination=/opt/noblogs/www/wp-content/cache $IMAGE_TAG ./docker/test.sh
+  artifacts:
+    paths:
+      - test-artifacts/screenshots/
+    expose_as: Screenshots
+    when: always
+    reports:
+      junit: test-artifacts/pytest.xml
 
diff --git a/docker/test.sh b/docker/test.sh
index 9201c786158a7834e4b0de40d66feca72e194534..c9c3d552fbb8b9e6a802afc9cbc6dfa13f12fc53 100755
--- a/docker/test.sh
+++ b/docker/test.sh
@@ -6,7 +6,16 @@ TESTSUITE_IMAGE="registry.git.autistici.org/noblogs/testsuite:main"
 podman run -d --expose 8443 --rm --env PROXY_DOMAIN=noblogs.org --env PROXY_BACKEND_ADDR=localhost:8080 --network=host registry.git.autistici.org/pipelines/images/test/ssl-reverse-proxy:main
 
 # Run the test suite using Podman, in the foreground.
-podman run --rm --pull=always --env TARGET_URL=${TARGET_URL} --env TARGET_ADDR=${TARGET_ADDR} --network=host ${TESTSUITE_IMAGE}
+# Mount a local temporary directory to hold artifacts.
+mkdir -p test-artifacts
+podman run --rm --pull=always \
+    --env TARGET_URL=${TARGET_URL} \
+    --env TARGET_ADDR=${TARGET_ADDR} \
+    --env SCREENSHOT_DIR=/artifacts/screenshots \
+    --network=host \
+    --mount type=bind,source=test-artifacts,destination=/artifacts \
+    ${TESTSUITE_IMAGE} -- \
+    --junitxml=/artifacts/pytest.xml
 rc=$?
 
 # Convert into permanent error.