From GitHub Actions to Authenticated URL: A Better Way to Share CI Artifacts

GitHub Actions stores build artifacts in a zip archive. To access them:

From GitHub Actions to Authenticated URL: A Better Way to Share CI Artifacts
TL;DR
Replace `actions/upload-artifact` (requires GitHub login, expires in 90 days) with `dsp publish` (permanent URL, company SSO, PM-accessible). One step change to your GitHub Actions workflow.

The problem with GitHub Actions artifact storage

GitHub Actions stores build artifacts in a zip archive. To access them:

  1. Go to the Actions run in GitHub
  2. Find the artifact section
  3. Click Download
  4. Extract the zip
  5. Open the HTML file locally

This works for engineers. It's unusable for everyone else.

Your PM can't access private repository Actions without a GitHub account. Your QA manager shouldn't need to navigate GitHub's CI interface to read a test report. Your VP shouldn't be extracting zip files to see a build summary.

And after 90 days, the artifact is gone. Any link shared in a Slack thread, Notion document, or Jira ticket goes dead.


The one-line change

Before:

- uses: actions/upload-artifact@v4
  with:
    name: research-dossier
    path: ./research-dossier/

After:

- name: Publish dossier
  run: |
    npm install -g @displaydev/cli
    dsp publish ./research-dossier/ --name "dossier-${{ github.run_id }}"
  env:
    DISPLAYDEV_API_KEY: ${{ secrets.DISPLAYDEV_API_KEY }}

The URL is permanent, requires a company email to access, and renders in the browser without downloading.


Full workflow example

name: Test and Publish
 
on: [push, pull_request]
 
jobs:
  test:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Lint
        run: npm run lint
      
      - name: Run tests
        run: npm test -- --coverage
        continue-on-error: true
      
      - name: Build
        run: npm run build
      
      - name: Publish test coverage report
        if: always()
        run: |
          npm install -g @displaydev/cli
          # dsp publish prints the URL on stdout line 1 and a status line on line 2;
          # head -n 1 captures just the URL.
          COVERAGE_URL=$(dsp publish ./coverage/lcov-report/ \
            --name "coverage-${{ github.sha }}" | head -n 1)
          echo "COVERAGE_URL=$COVERAGE_URL" >> $GITHUB_ENV
        env:
          DISPLAYDEV_API_KEY: ${{ secrets.DISPLAYDEV_API_KEY }}
      
      - name: Comment on PR
        if: always() && github.event_name == 'pull_request'
        uses: actions/github-script@v7
        with:
          script: |
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `📊 **Coverage report:** ${process.env.COVERAGE_URL}`
            })

Use cases this covers

Agent-authored artifacts: Multi-page research dossiers, market maps, and competitive landscapes generated by a coding agent in CI.

Build outputs: Preview builds for non-engineers. PMs and designers can review what's shipping without needing a local development environment.

Scheduled report generation: Nightly builds, weekly analytics exports, automated competitive monitoring reports, anything a scheduled workflow generates and stakeholders need to read.


Viewer experience

The PR comment appears with a URL. The QA lead clicks it, signs in with Google in one click, and sees the full interactive test report in their browser. No GitHub account, no zip file, no 90-day expiry.

The URL persists in Slack threads, Notion documents, and Jira tickets indefinitely.


Cost comparison

GitHub Actions artifact storagedisplay.dev
Viewer needs GitHub account
Viewer needs private repo access
Artifact expiry90 daysNever
Browser-renderable (no download)
Company SSO
Monthly cost$0 (included)€49 flat

FAQ

Can I publish only on failure?+

Yes. Use if: failure() in the step condition. The artifact is only published when the workflow fails.

How long are display.dev artifacts retained?+

Indefinitely, until you delete them. No expiry.

What about other CI systems (GitLab, CircleCI, Jenkins)?+

The display CLI works anywhere Node.js runs. For GitLab CI: yaml publish: stage: report script: - npm install -g @displaydev/cli - dsp publish ./report/ --name "ci-$CI_PIPELINE_ID" variables: DISPLAYDEV_API_KEY: $DISPLAYDEV_API_KEY Same pattern for CircleCI and Jenkins: install the CLI, call dsp publish.

Publish your first artifact in 15 seconds.

Free tier. No credit card. One-time password auth for viewers on free, Google + Microsoft SSO on Pro (€49/month flat).

Get started free →See pricing