Build a GitHub Actions Dashboard on Any Screen — No Code Required
Build a GitHub Actions Dashboard on Any Screen
Your CI/CD pipeline already knows everything — build status, test results, deploy outcomes, release metadata. The problem isn't missing information. It's that this information is scattered across too many surfaces:
- GitHub Actions tab (hidden behind 3 clicks)
- Slack bot notifications (muted within a week)
- Email digests (never opened)
- Deploy logs in Vercel/AWS/your hosting provider
- Monitoring dashboards you check after something breaks
Five tools. Five context switches. And still nobody notices a failed deploy until a customer reports it.
What if you consolidated all of that into a single screen — one glance, always current, zero interaction required?
This tutorial shows you how to push GitHub Actions workflow results to a physical display — phone, tablet, or wall-mounted TV — using one YAML file. Every pipeline stage lands on its own panel, updating in real time. Your team sees the full picture without opening a browser.
What you'll build
A 2×2 grid display where each panel shows a different pipeline stage, updating in real time as your workflow runs:
| Panel | Content | Visual |
|---|---|---|
| Panel 1 (top-left) | Build status | Green on success, red on failure |
| Panel 2 (top-right) | Test results | Test count + pass/fail breakdown |
| Panel 3 (bottom-left) | Deploy status | Environment + URL + timestamp |
| Panel 4 (bottom-right) | Release info | Version tag + author + changelog |
Every push to main triggers the workflow. Each stage pushes its result to the corresponding panel. Your team sees the pipeline status at a glance — no browser tabs, no refreshing.
Prerequisites
- Install Push To Display on any device — iOS, Android, or open the web dashboard
- Set your board layout to 2×2 Grid (Settings → Layout → 2×2 Grid)
- Create an API key from the web portal (Settings → API Keys → Generate)
- Add the key as a GitHub repository secret named
PUSHTODISPLAY_API_KEY
The complete workflow
Create .github/workflows/display-dashboard.yml in your repository:
name: CI/CD → Display Dashboard
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run build
id: build
run: |
echo "Building project..."
# Replace with your actual build command:
# npm run build / dotnet build / make build
echo "Build completed successfully"
- name: Push build result to display
if: always()
uses: pushtodisplay/action@v1
with:
api-key: ${{ secrets.PUSHTODISPLAY_API_KEY }}
panel-id: 1
background: ${{ steps.build.outcome == 'success' && '#0d7a3e' || '#c0392b' }}
blocks: |
[
{
"text": "${{ steps.build.outcome == 'success' && 'Build Passed ✓' || 'Build Failed ✗' }}",
"size": "large",
"weight": "bold",
"color": "#ffffff"
},
{
"text": "${{ github.event.head_commit.message }}",
"size": "small",
"color": "#ffffffcc"
},
{
"text": "${{ github.sha }} • ${{ github.actor }}",
"size": "small",
"color": "#ffffff99"
}
]
test:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v4
- name: Run tests
id: tests
run: |
echo "Running tests..."
# Replace with your actual test command:
# npm test / dotnet test / pytest
echo "tests_passed=42" >> "$GITHUB_OUTPUT"
echo "tests_failed=0" >> "$GITHUB_OUTPUT"
echo "tests_total=42" >> "$GITHUB_OUTPUT"
- name: Push test results to display
if: always()
uses: pushtodisplay/action@v1
with:
api-key: ${{ secrets.PUSHTODISPLAY_API_KEY }}
panel-id: 2
background: ${{ steps.tests.outcome == 'success' && '#0d7a3e' || '#c0392b' }}
blocks: |
[
{
"text": "${{ steps.tests.outcome == 'success' && 'Tests Passed' || 'Tests Failed' }}",
"size": "large",
"weight": "bold",
"color": "#ffffff"
},
{
"text": "${{ steps.tests.outputs.tests_passed }}/${{ steps.tests.outputs.tests_total }} passed",
"size": "medium",
"color": "#ffffffcc"
},
{
"text": "${{ steps.tests.outputs.tests_failed }} failed",
"size": "small",
"color": "${{ steps.tests.outputs.tests_failed == '0' && '#ffffff99' || '#ff6b6b' }}"
}
]
deploy:
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4
- name: Deploy to production
id: deploy
run: |
echo "Deploying..."
# Replace with your actual deploy command:
# vercel --prod / kubectl apply / aws deploy
echo "url=https://myapp.example.com" >> "$GITHUB_OUTPUT"
echo "environment=production" >> "$GITHUB_OUTPUT"
- name: Push deploy status to display
if: always()
uses: pushtodisplay/action@v1
with:
api-key: ${{ secrets.PUSHTODISPLAY_API_KEY }}
panel-id: 3
full-panel: ${{ steps.deploy.outcome == 'failure' && 'true' || 'false' }}
background: ${{ steps.deploy.outcome == 'success' && '#1a5276' || '#c0392b' }}
blocks: |
[
{
"text": "${{ steps.deploy.outcome == 'success' && 'Deployed ✓' || 'Deploy Failed ✗' }}",
"size": "large",
"weight": "bold",
"color": "#ffffff"
},
{
"text": "${{ steps.deploy.outputs.environment }}",
"size": "medium",
"weight": "semibold",
"color": "#ffffffcc"
},
{
"text": "${{ steps.deploy.outputs.url }}",
"size": "small",
"color": "#ffffff99"
}
]
announce:
runs-on: ubuntu-latest
needs: deploy
steps:
- name: Push release summary to display
uses: pushtodisplay/action@v1
with:
api-key: ${{ secrets.PUSHTODISPLAY_API_KEY }}
panel-id: 4
background: "#2c2c54"
align-y: center
blocks: |
[
{
"text": "🚀 Shipped",
"size": "large",
"weight": "bold",
"color": "#ffffff"
},
{
"text": "${{ github.event.head_commit.message }}",
"size": "medium",
"color": "#ffffffcc"
},
{
"text": "by @${{ github.actor }} • ${{ github.event.head_commit.timestamp }}",
"size": "small",
"color": "#ffffff99"
}
]How it works
The architecture is simple: no polling, no dashboard to refresh.
git push → GitHub Actions runs workflow
→ Each job calls pushtodisplay/action@v1
→ Action POSTs to PushToDisplay API
→ API routes content via SignalR to your device
→ Panel updates instantly on your screen
The panel-id parameter targets a specific quadrant of the 2×2 grid. Each job updates only its panel — the other three stay untouched. This gives you a persistent, always-current view of your entire pipeline.
Why consolidate workflow status onto one screen?
Most teams piece together CI/CD visibility from multiple disconnected tools — GitHub's workflow UI, Slack integrations, status badges in READMEs, and custom dashboards that need maintenance. The result: nobody has a single source of truth for "is our pipeline healthy right now?"
Consolidating onto one physical display solves this differently than another web dashboard:
- Ambient awareness — The screen is always on, always visible. No tab to open, no notification to dismiss.
- Multi-source, single surface — Build results, test metrics, deploy status, and release metadata live side by side instead of across 4 browser tabs.
- Passive consumption — Your team absorbs pipeline health peripherally, the same way you'd glance at a wall clock.
- No maintenance — Unlike Grafana dashboards or custom status pages, there's no infrastructure to host or queries to maintain. The workflow file IS the dashboard config.
Key patterns in this workflow
Color-coded status
The background field uses conditional expressions to show green for success and red for failure:
background: ${{ steps.build.outcome == 'success' && '#0d7a3e' || '#c0392b' }}Your team reads the board at a glance — green means go, red means investigate.
Full-panel mode for critical failures
When a deploy fails, it needs attention. Setting full-panel: true makes the failure message take over the entire panel space with larger, more prominent text:
full-panel: ${{ steps.deploy.outcome == 'failure' && 'true' || 'false' }}Dynamic content from step outputs
Pull real data from your pipeline — test counts, deploy URLs, commit messages — directly into the display:
"text": "${{ steps.tests.outputs.tests_passed }}/${{ steps.tests.outputs.tests_total }} passed"Rich multi-block content
Each panel shows multiple lines with different sizes and emphasis. The blocks array lets you compose a visual hierarchy — bold header, medium-weight details, and muted metadata.
Consolidate multiple workflows onto one board
The example above covers a single workflow, but the real power is consolidation across multiple sources. Each panel is independently addressable — different workflows, different repos, even different CI providers can all push to the same board.
Multi-repo setup: Have your frontend, backend, and infrastructure repos each push to a different panel on the same board. One screen shows the health of your entire stack.
Aggregate CI and CD: Trigger on workflow_run to collect results from separate build and deploy workflows into one board — even if they run on different schedules.
Mix sources: Use the REST API alongside the GitHub Action. Push Vercel deploy previews from a webhook, Datadog alerts from a serverless function, and GitHub Actions results from your workflow — all converging on the same 4-panel grid.
More customization ideas
Single-screen focus: Switch to Full Screen layout and target Panel 1 only. Every push replaces the previous message — great for a single big status display.
Environment color coding: Use different background colors per environment:
#1a5276— production (blue)#1e8449— staging (green)#7d3c98— preview (purple)
Compact density: Add density: compact for boards that accumulate multiple messages in list-flow mode — useful for a running log of deploys throughout the day.
Get started
- Install the app on any spare device (iOS · Android)
- Set layout to 2×2 Grid
- Create an API key from the dashboard
- Add the secret to your GitHub repo
- Copy the workflow above into
.github/workflows/display-dashboard.yml - Push to
mainand watch the panels light up
Stop checking 5 tools to answer "is our pipeline healthy?" — consolidate it into one screen your whole team can see.
Want more? Check out the GitHub Action docs, the CLI quick start, or the MCP Server for AI agent integration.