A trace is large and is only interesting when something went wrong, so recording on retry and uploading on failure is the arrangement that stays affordable.
# playwright.config.js: trace: 'on-first-retry'
- run: npx playwright test
- uses: actions/upload-artifact@v3
if: failure()
with:
name: playwright-trace
path: test-results/
retention-days: 7
if: failure() rather than always() is what stops a cancelled run uploading a partial artifact nobody will open. Setting retention-days explicitly matters because the default is ninety, and a browser suite uploading traces fills a storage quota faster than anybody expects.