Playwright's HTML reporter writes playwright-report/index.html. When the run has no screenshots, videos or traces, that file is fully self-contained (our three-test example came out at about 510 KB), so a teammate can open it anywhere. The awkward part is getting it to them: zipping it into a chat, or downloading a CI artifact and running npx playwright show-report.
This guide publishes that one file to a permanent HTTPS URL with deed.page, a static host that takes a single PUT and needs no account. The script asks before it publishes, because anyone with the link can open the report.
Disclosure: this guide is written by the deed.page team.
npx playwright test --reporter=html
ls playwright-report/ # index.html, plus data/ only if there are attachments
Save it as publish-playwright-report.sh (download) and chmod +x it.
#!/bin/sh
set -eu
FILE=${1:?path to playwright-report/index.html}; SLUG=${2:?slug, e.g. my-app-e2e-7k2p}
DIR=$(dirname "$FILE")
if [ -d "$DIR/data" ] && [ -n "$(ls -A "$DIR/data" 2>/dev/null)" ]; then
echo "This report has attachments in $DIR/data. Use the manifest upload in https://deed.page/docs."; exit 1
fi
printf 'Publish %s to https://%s.deed.page/ ? Anyone with the link can open it. [y/N] ' "$FILE" "$SLUG"
read -r ans; [ "$ans" = "y" ] || { echo "Not published."; exit 0; }
DEEDPAGE_TOKEN=${DEEDPAGE_TOKEN:-$(cat ~/.config/deed-page/token 2>/dev/null || true)}
set --; if [ -n "$DEEDPAGE_TOKEN" ]; then set -- -H "Authorization: Bearer $DEEDPAGE_TOKEN"; fi
RESP=$(curl -sS -T "$FILE" -H "Content-Type: text/html" \
"https://deed.page/v1/sites?slug=$SLUG" -H "X-Client: playwright-report-script" "$@")
TOKEN=$(printf '%s' "$RESP" | sed -n 's/.*"token": *"\(deed_tok_[^"]*\)".*/\1/p')
if [ -n "$TOKEN" ]; then (umask 077 && mkdir -p ~/.config/deed-page && chmod 700 ~/.config/deed-page \
&& printf '%s' "$TOKEN" > ~/.config/deed-page/token && chmod 600 ~/.config/deed-page/token); fi
printf '%s\n' "$RESP" | sed 's/"token": *"[^"]*"/"token":"<saved>"/'
./publish-playwright-report.sh playwright-report/index.html checkout-e2e-7k2p
Publish playwright-report/index.html to https://checkout-e2e-7k2p.deed.page/ ? ... [y/N] y
{"ok":true,"url":"https://checkout-e2e-7k2p.deed.page/", ... "token":"<saved>"}
Answer anything but y and nothing is uploaded. The first publish returns an owner token once; the script writes it to ~/.config/deed-page/token (mode 600) and masks it in the output, so it never lands in your terminal log or CI output. Later runs to the same slug send that token and replace the report in place, so the link in your PR description keeps showing the latest run. Republishing an identical file comes back with "unchanged":true.
curl -X DELETE -H "Authorization: Bearer $(cat ~/.config/deed-page/token)" \
https://deed.page/v1/sites/checkout-e2e-7k2p
my-site are reserved.data/ folder. The script stops there instead of publishing a report with broken attachments; upload the folder with the manifest flow in the deed.page docs.We tested this script end to end on 2026-11-03 with @playwright/test: decline, publish, republish (unchanged), and delete (the URL returned 404 afterwards).