Microsoft Power BI Integration for Digital Signage
Displaying Power BI dashboards on digital signage brings real-time business intelligence to your teams, visitors, and operations floor. This guide covers all integration methods, from simple web embedding to enterprise-grade automated solutions.
Why Power BI on Digital Signage?
Use Cases
| Environment | Application | Benefit |
|---|---|---|
| Corporate Lobby | Company KPIs, stock price, sustainability metrics | Transparency, culture |
| Sales Floor | Real-time sales, leaderboards, targets | Motivation, awareness |
| Operations/NOC | System status, alerts, performance | Rapid response |
| Manufacturing | Production metrics, quality data, OEE | Process visibility |
| Warehouse | Inventory levels, shipping status | Operational efficiency |
| Call Center | Queue stats, SLA performance, agent metrics | Performance management |
| Executive Suite | Financial dashboards, market data | Decision support |
Benefits of Signage vs. Desktop
| Factor | Desktop Viewing | Digital Signage |
|---|---|---|
| Visibility | Individual | Team-wide |
| Attention | Pull (user opens) | Push (always visible) |
| Context switching | Required | None |
| Ambient awareness | Low | High |
| Data culture | Personal | Organizational |
Integration Methods Overview
┌─────────────────────────────────────────────────────────────────────────┐
│ POWER BI SIGNAGE INTEGRATION METHODS │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ METHOD 1: PUBLISH TO WEB (Simplest) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Power BI │───▶│ Public URL │───▶│ Signage │ │
│ │ Report │ │ (iframe) │ │ Player │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ✓ No authentication needed │
│ ✗ Data publicly accessible │
│ │
│ METHOD 2: EMBED WITH SERVICE PRINCIPAL (Secure) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Power BI │───▶│ Azure AD │───▶│ Signage │ │
│ │ Report │ │ App Token │ │ Player │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ✓ Secure, authenticated │
│ ✓ Row-level security │
│ ✗ More complex setup │
│ │
│ METHOD 3: FULL-SCREEN KIOSK (Native) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Windows │───▶│ Power BI │───▶│ Display │ │
│ │ Player │ │ Desktop │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ✓ Native app experience │
│ ✓ Offline capability │
│ ✗ Windows-only, license needed │
│ │
│ METHOD 4: SCREENSHOT/IMAGE EXPORT (Scheduled) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Power BI │───▶│ Image File │───▶│ Signage │ │
│ │ Report │ │ (PNG/JPG) │ │ CMS │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ✓ Works with any signage player │
│ ✓ Minimal bandwidth │
│ ✗ Not real-time │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Method 1: Publish to Web (Public Embed)
The simplest method - creates a public URL anyone can access.
When to Use
- ✅ Non-sensitive data only
- ✅ Quick proof of concept
- ✅ Public-facing dashboards
- ❌ Not for confidential data
- ❌ Not for internal financials
Setup Steps
-
Open your Power BI report in Power BI Service
-
Click File → Embed report → Publish to web
-
Review the warning about public access
-
Copy the embed code (iframe)
<iframe
title="Sales Dashboard"
width="1920"
height="1080"
src="https://app.powerbi.com/view?r=eyJrIjoiYWJj..."
frameborder="0"
allowFullScreen="true">
</iframe>
- Add to your signage CMS as a web component/URL
Best Practices
| Practice | Implementation |
|---|---|
| Use full-screen URL | Add ?chromeless=true to hide toolbar |
| Set auto-refresh | Configure report refresh in Power BI |
| Optimize for display size | Design report at exact signage resolution |
| Test refresh behavior | Ensure page refresh doesn't show loading |
Customizing the URL
| Parameter | Purpose | Example |
|---|---|---|
chromeless=true | Hide navigation | ?chromeless=true |
navContentPaneEnabled=false | Hide page tabs | &navContentPaneEnabled=false |
filterPaneEnabled=false | Hide filters | &filterPaneEnabled=false |
Full URL example:
https://app.powerbi.com/view?r=eyJrIjoiYWJj...&chromeless=true&navContentPaneEnabled=false
Method 2: Secure Embed with Service Principal
For sensitive data requiring authentication without user interaction.
Architecture
┌─────────────────────────────────────────────────────────────────────────┐
│ SECURE EMBEDDING ARCHITECTURE │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 1. SETUP PHASE (One-time) │
│ ┌──────────────┐ │
│ │ Azure AD │──── Register App ────▶ App ID + Secret │
│ │ Portal │ │
│ └──────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Power BI │──── Add Service Principal to Workspace │
│ │ Admin Portal │ │
│ └──────────────┘ │
│ │
│ 2. RUNTIME FLOW │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Your Server │───▶│ Azure AD │───▶│ Access Token │ │
│ │ │ │ │ │ │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │ │ │
│ │ ▼ │
│ │ ┌──────────────┐ │
│ └──────────────────────────────▶│ Power BI API │ │
│ │ Embed Token │ │
│ └──────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Signage │ │
│ │ Player │ │
│ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Step 1: Register Azure AD Application
- Go to Azure Portal → Azure Active Directory → App registrations
- Click New registration
- Name: "Digital Signage Power BI"
- Supported account types: Single tenant
- Redirect URI: Leave blank for now
- Click Register
Record these values:
- Application (client) ID
- Directory (tenant) ID
Step 2: Create Client Secret
- In your app registration, go to Certificates & secrets
- Click New client secret
- Description: "Signage secret"
- Expiration: Choose appropriate (remember to rotate!)
- Copy the secret value immediately (shown only once)
Step 3: Grant API Permissions
-
Go to API permissions → Add a permission
-
Select Power BI Service
-
Choose Delegated permissions:
Dataset.Read.AllReport.Read.AllDashboard.Read.AllWorkspace.Read.All
-
Click Grant admin consent
Step 4: Enable Service Principal in Power BI
- Go to Power BI Admin Portal (admin.powerbi.com)
- Tenant settings → Developer settings
- Enable Service principals can use Power BI APIs
- Specify security group or entire organization
Step 5: Add Service Principal to Workspace
- Open your Power BI workspace
- Click Access → Add
- Search for your Azure AD app name
- Grant Member or Contributor role
Step 6: Generate Embed Token (Server-Side)
Node.js Example:
const axios = require('axios');
const qs = require('querystring');
// Configuration
const config = {
tenantId: 'your-tenant-id',
clientId: 'your-app-id',
clientSecret: 'your-client-secret',
workspaceId: 'your-workspace-id',
reportId: 'your-report-id'
};
// Get Azure AD token
async function getAzureToken() {
const url = `https://login.microsoftonline.com/${config.tenantId}/oauth2/v2.0/token`;
const response = await axios.post(url, qs.stringify({
grant_type: 'client_credentials',
client_id: config.clientId,
client_secret: config.clientSecret,
scope: 'https://analysis.windows.net/powerbi/api/.default'
}));
return response.data.access_token;
}
// Get embed token
async function getEmbedToken(azureToken) {
const url = `https://api.powerbi.com/v1.0/myorg/groups/${config.workspaceId}/reports/${config.reportId}/GenerateToken`;
const response = await axios.post(url,
{ accessLevel: 'View' },
{ headers: { Authorization: `Bearer ${azureToken}` }}
);
return response.data.token;
}
// Get embed URL
async function getEmbedUrl(azureToken) {
const url = `https://api.powerbi.com/v1.0/myorg/groups/${config.workspaceId}/reports/${config.reportId}`;
const response = await axios.get(url, {
headers: { Authorization: `Bearer ${azureToken}` }
});
return response.data.embedUrl;
}
// Main function
async function getEmbedConfig() {
const azureToken = await getAzureToken();
const embedToken = await getEmbedToken(azureToken);
const embedUrl = await getEmbedUrl(azureToken);
return {
embedToken,
embedUrl,
reportId: config.reportId
};
}
Step 7: Embed in Signage Player
HTML/JavaScript for signage player:
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/powerbi-client@2.22.0/dist/powerbi.min.js"></script>
<style>
html, body, #reportContainer {
height: 100%;
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<div id="reportContainer"></div>
<script>
// Get embed config from your server
fetch('/api/powerbi-embed-config')
.then(response => response.json())
.then(config => {
const embedConfig = {
type: 'report',
tokenType: powerbi.models.TokenType.Embed,
accessToken: config.embedToken,
embedUrl: config.embedUrl,
id: config.reportId,
settings: {
panes: {
filters: { visible: false },
pageNavigation: { visible: false }
},
background: powerbi.models.BackgroundType.Transparent
}
};
const reportContainer = document.getElementById('reportContainer');
const report = powerbi.embed(reportContainer, embedConfig);
// Auto-refresh every 5 minutes
setInterval(() => {
report.refresh();
}, 300000);
});
</script>
</body>
</html>
Token Refresh Strategy
Embed tokens expire (default 1 hour). Implement automatic refresh:
// Token refresh handler
let tokenRefreshInterval;
function setupTokenRefresh(report) {
// Refresh token every 50 minutes (before 1-hour expiry)
tokenRefreshInterval = setInterval(async () => {
const newConfig = await fetch('/api/powerbi-embed-config').then(r => r.json());
report.setAccessToken(newConfig.embedToken);
}, 50 * 60 * 1000);
}
Method 3: Power BI Desktop Kiosk Mode
For Windows-based players with Power BI Desktop installed.
Setup
- Install Power BI Desktop on Windows signage player
- Sign in with a licensed account
- Open your report (.pbix file or from service)
- Press F11 for full-screen mode
Automation with Task Scheduler
Create a batch script to launch Power BI in kiosk mode:
@echo off
REM launch-powerbi-kiosk.bat
REM Kill any existing Power BI instance
taskkill /IM PBIDesktop.exe /F 2>nul
REM Wait a moment
timeout /t 5
REM Launch Power BI with your report
start "" "C:\Program Files\Microsoft Power BI Desktop\bin\PBIDesktop.exe" "C:\Reports\SalesDashboard.pbix"
REM Wait for Power BI to load
timeout /t 30
REM Send F11 to go full-screen (requires AutoHotkey or similar)
REM This part requires additional scripting
Considerations
| Aspect | Notes |
|---|---|
| License | Requires Power BI Pro or Premium per User |
| Updates | Power BI Desktop auto-updates may interrupt |
| Authentication | User must remain signed in |
| Refresh | Configure scheduled refresh in Desktop |
Method 4: Screenshot/Image Export
Export dashboard as images on a schedule.
Using Power Automate
-
Create a flow triggered on schedule (e.g., every 15 minutes)
-
Add action: Power BI - Export to file
-
Configure export:
- Workspace
- Report
- Export format: PNG or PDF
-
Save to location accessible by signage CMS
Using Power BI REST API
import requests
import time
def export_report_to_image(access_token, group_id, report_id):
# Initiate export
export_url = f"https://api.powerbi.com/v1.0/myorg/groups/{group_id}/reports/{report_id}/ExportTo"
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
body = {
"format": "PNG",
"powerBIReportConfiguration": {
"pages": [{"pageName": "ReportSection1"}]
}
}
response = requests.post(export_url, headers=headers, json=body)
export_id = response.json()["id"]
# Poll for completion
status_url = f"https://api.powerbi.com/v1.0/myorg/groups/{group_id}/reports/{report_id}/exports/{export_id}"
while True:
status = requests.get(status_url, headers=headers).json()
if status["status"] == "Succeeded":
return status["resourceLocation"]
elif status["status"] == "Failed":
raise Exception("Export failed")
time.sleep(5)
# Download the exported file
def download_export(file_url, access_token, save_path):
headers = {"Authorization": f"Bearer {access_token}"}
response = requests.get(file_url, headers=headers)
with open(save_path, 'wb') as f:
f.write(response.content)
Signage CMS Integration
Point your signage CMS to the exported image location:
- Network share:
\\server\powerbi-exports\dashboard.png - Web server:
https://internal.company.com/exports/dashboard.png - Cloud storage: Azure Blob, S3, etc.
Design Best Practices for Signage
Resolution and Sizing
| Display | Recommended Report Size |
|---|---|
| 1080p Landscape | 1920 × 1080 px |
| 1080p Portrait | 1080 × 1920 px |
| 4K Landscape | 3840 × 2160 px |
| Video Wall 2×2 | 3840 × 2160 px |
In Power BI:
- Go to View → Page size
- Select Custom
- Enter exact pixel dimensions
Typography for Distance Viewing
| Viewing Distance | Minimum Font Size |
|---|---|
| 6 feet (2m) | 24pt |
| 12 feet (4m) | 48pt |
| 20 feet (6m) | 72pt |
| 30+ feet (10m) | 96pt+ |
Color and Contrast
| Element | Recommendation |
|---|---|
| Background | Dark for most environments (reduces glare) |
| Text | White or high-contrast colors |
| Positive values | Green |
| Negative values | Red |
| Neutral | Blue or gray |
| Contrast ratio | Minimum 4.5:1, prefer 7:1 |
Dashboard Layout
┌─────────────────────────────────────────────────────────────────┐
│ SIGNAGE DASHBOARD LAYOUT │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ HEADER / KPIs │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ Revenue │ │ Orders │ │ Target │ │ % │ │ │
│ │ │ $1.2M │ │ 4,521 │ │ 95% │ │ +12% │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────┐ ┌────────────────────────┐ │
│ │ │ │ │ │
│ │ PRIMARY CHART │ │ SECONDARY │ │
│ │ (Line/Bar) │ │ VISUAL │ │
│ │ │ │ │ │
│ │ │ ├────────────────────────┤ │
│ │ │ │ │ │
│ │ │ │ TABLE/LIST │ │
│ │ │ │ │ │
│ └──────────────────────────────┘ └────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ FOOTER: Last updated: 2:45 PM | Data source: SAP │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Auto-Refresh Configuration
Report-Level Refresh
In Power BI Service:
- Open report settings
- Enable Automatic page refresh
- Set refresh interval (minimum depends on license)
| License | Minimum Interval |
|---|---|
| Pro | 30 minutes |
| Premium | 1 second |
| Embedded | 1 second |
Dataset Refresh
For underlying data:
- Go to dataset settings
- Scheduled refresh → Add times
- Up to 8 refreshes/day (Pro) or 48 (Premium)
Signage-Level Refresh
| Method | Implementation |
|---|---|
| Page reload | Set CMS to reload URL every X minutes |
| JavaScript | Call report.refresh() API |
| Full restart | Schedule player reboot daily |
Troubleshooting
Common Issues
| Issue | Cause | Solution |
|---|---|---|
| Blank screen | Token expired | Implement token refresh |
| "Can't connect" | Network/auth issue | Check firewall, credentials |
| Slow loading | Large dataset | Optimize report, use aggregations |
| Layout broken | Resolution mismatch | Match report to display resolution |
| No refresh | Schedule not set | Configure auto-refresh |
| Login prompt | Session timeout | Use service principal |
Performance Optimization
- Use aggregations for large datasets
- Limit visuals to 6-8 per page
- Avoid complex DAX in real-time scenarios
- Pre-aggregate data where possible
- Use DirectQuery sparingly (Import preferred)
Frequently Asked Questions
Next Steps
- Data-Driven Content - Beyond Power BI
- API Reference - SignageStudio API
- Corporate Digital Signage - Enterprise solutions
- SignageStudio Data Integration - Platform features
This guide is maintained by MediaSignage, pioneers of digital signage technology since 2008.