3 min read
Embedding Power BI Reports in Your Applications
With more organizations working remotely, the demand for embedded analytics has increased significantly. Power BI Embedded allows you to integrate interactive reports directly into your applications. Here is how to get started.
Understanding the Options
Power BI offers two embedding scenarios:
- Embed for your organization - Users sign in with their Power BI account
- Embed for your customers - Your app authenticates on behalf of users (App owns data)
For SaaS applications, “Embed for your customers” is typically the right choice.
Setting Up the Azure Resources
# Create a Power BI Embedded capacity
az powerbi embedded-capacity create \
--resource-group rg-analytics \
--name pbiembedded2020 \
--location australiaeast \
--sku-name A1 \
--sku-tier PBIE_Azure \
--administration-members "admin@contoso.com"
Registering an Azure AD Application
# Register the app
az ad app create \
--display-name "Power BI Embedded App" \
--reply-urls "https://localhost:5001/signin-oidc"
# Create a client secret
az ad app credential reset \
--id <app-id> \
--credential-description "Power BI Secret"
The Backend Service
Create a service to generate embed tokens:
using Microsoft.Identity.Client;
using Microsoft.PowerBI.Api;
using Microsoft.PowerBI.Api.Models;
using Microsoft.Rest;
public class PowerBIService
{
private readonly string _clientId;
private readonly string _clientSecret;
private readonly string _tenantId;
private readonly string _workspaceId;
private readonly string _reportId;
public PowerBIService(IConfiguration config)
{
_clientId = config["PowerBI:ClientId"];
_clientSecret = config["PowerBI:ClientSecret"];
_tenantId = config["PowerBI:TenantId"];
_workspaceId = config["PowerBI:WorkspaceId"];
_reportId = config["PowerBI:ReportId"];
}
private async Task<string> GetAccessTokenAsync()
{
var app = ConfidentialClientApplicationBuilder
.Create(_clientId)
.WithClientSecret(_clientSecret)
.WithAuthority(new Uri($"https://login.microsoftonline.com/{_tenantId}"))
.Build();
var scopes = new[] { "https://analysis.windows.net/powerbi/api/.default" };
var result = await app.AcquireTokenForClient(scopes).ExecuteAsync();
return result.AccessToken;
}
public async Task<EmbedConfig> GetEmbedConfigAsync()
{
var accessToken = await GetAccessTokenAsync();
var tokenCredentials = new TokenCredentials(accessToken, "Bearer");
using var client = new PowerBIClient(
new Uri("https://api.powerbi.com"),
tokenCredentials);
var report = await client.Reports.GetReportInGroupAsync(
Guid.Parse(_workspaceId),
Guid.Parse(_reportId));
var generateTokenRequest = new GenerateTokenRequest(
accessLevel: "View",
datasetId: report.DatasetId);
var embedToken = await client.Reports.GenerateTokenInGroupAsync(
Guid.Parse(_workspaceId),
Guid.Parse(_reportId),
generateTokenRequest);
return new EmbedConfig
{
ReportId = _reportId,
EmbedUrl = report.EmbedUrl,
EmbedToken = embedToken.Token,
TokenExpiry = embedToken.Expiration
};
}
}
public class EmbedConfig
{
public string ReportId { get; set; }
public string EmbedUrl { get; set; }
public string EmbedToken { get; set; }
public DateTime? TokenExpiry { get; set; }
}
The API Controller
[ApiController]
[Route("api/[controller]")]
public class PowerBIController : ControllerBase
{
private readonly PowerBIService _powerBIService;
public PowerBIController(PowerBIService powerBIService)
{
_powerBIService = powerBIService;
}
[HttpGet("embed-config")]
public async Task<ActionResult<EmbedConfig>> GetEmbedConfig()
{
var config = await _powerBIService.GetEmbedConfigAsync();
return Ok(config);
}
}
Frontend Integration
Use the Power BI JavaScript library:
<script src="https://cdn.jsdelivr.net/npm/powerbi-client@2.13.0/dist/powerbi.min.js"></script>
<div id="reportContainer" style="height: 600px;"></div>
<script>
async function embedReport() {
const response = await fetch('/api/powerbi/embed-config');
const config = await response.json();
const embedConfiguration = {
type: 'report',
id: config.reportId,
embedUrl: config.embedUrl,
accessToken: config.embedToken,
tokenType: models.TokenType.Embed,
settings: {
panes: {
filters: { visible: false },
pageNavigation: { visible: true }
}
}
};
const reportContainer = document.getElementById('reportContainer');
const report = powerbi.embed(reportContainer, embedConfiguration);
report.on('loaded', function() {
console.log('Report loaded');
});
report.on('error', function(event) {
console.error(event.detail);
});
}
embedReport();
</script>
Row-Level Security
For multi-tenant applications, implement RLS:
var generateTokenRequest = new GenerateTokenRequest(
accessLevel: "View",
identities: new List<EffectiveIdentity>
{
new EffectiveIdentity(
username: currentUser.Email,
roles: new List<string> { "TenantRole" },
datasets: new List<string> { report.DatasetId })
});
Cost Considerations
Power BI Embedded uses capacity-based pricing. For development:
- Use Power BI Premium Per User for testing
- Consider A1 SKU for production starting points
- Scale up/down based on usage patterns
Embedded analytics brings powerful visualizations directly to your users without requiring separate Power BI licenses.