1 min read
Power BI Embedded: Analytics in Your Applications
I wrote “Power BI Embedded: Analytics in Your Applications” to share practical, production-minded guidance on this topic.
Embedding Options
embed_for_customers:
description: External users access embedded content
licensing: App owns data (capacity-based)
authentication: Your app authenticates
use_case: Customer-facing portals
embed_for_organization:
description: Internal users with Power BI licenses
licensing: User owns data (per-user)
authentication: Azure AD
use_case: Internal applications
Setting Up Embedded Analytics
Register Azure AD Application
# Create app registration
az ad app create \
--display-name "PowerBI-Embedded-App" \
--reply-urls "https://myapp.com/callback" \
--required-resource-accesses @manifest.json
// manifest.json - Required permissions
{
"resourceAppId": "00000009-0000-0000-c000-000000000000",
"resourceAccess": [
{
"id": "4ae1bf56-f562-4747-b7bc-2fa0874ed46f",
"type": "Scope"
},
{
"id": "7f33e027-4039-419b-938e-2f8ca153e68e",
"type": "Scope"
}
]
}
Create Embedded Capacity
# Create Power BI Embedded capacity
az powerbi embedded-capacity create \
--resource-group analytics-rg \
--name myembeddedcapacity \
--location eastus \
--sku-name A2 \
--sku-tier PBIE_Azure \
--administration-members "admin@company.com"
Embedding Reports
JavaScript SDK
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.powerbi.com/libs/powerbi-client/2.19.1/powerbi.min.js"></script>
</head>
<body>
<div id="reportContainer" style="height: 600px;"></div>
<script>
// Get embed token from your backend
async function embedReport() {
const response = await fetch('/api/embed-token');
const embedConfig = await response.json();
const reportContainer = document.getElementById('reportContainer');
const report = powerbi.embed(reportContainer, {
type: 'report',
id: embedConfig.reportId,
embedUrl: embedConfig.embedUrl,
accessToken: embedConfig.token,
tokenType: 1, // Embed token
settings: {
filterPaneEnabled: false,
navContentPaneEnabled: false,
background: models.BackgroundType.Transparent
}
});
report.on('loaded', function() {
console.log('Report loaded');
});
report.on('error', function(event) {
console.error('Error:', event.detail);
});
}
embedReport();
</script>
</body>
</html>
Backend Token Generation (C#)
using Microsoft.PowerBI.Api;
using Microsoft.PowerBI.Api.Models;
using Microsoft.Rest;
public class PowerBIEmbedService
{
private readonly string _workspaceId;
private readonly string _reportId;
private readonly PowerBIClient _client;
public PowerBIEmbedService(IConfiguration config)
{
_workspaceId = config["PowerBI:WorkspaceId"];
_reportId = config["PowerBI:ReportId"];
var credential = new ClientCredential(
config["AzureAd:ClientId"],
config["AzureAd:ClientSecret"]
);
var authResult = await AuthenticationContext
.AcquireTokenAsync("https://analysis.windows.net/powerbi/api", credential);
_client = new PowerBIClient(
new Uri("https://api.powerbi.com"),
new TokenCredentials(authResult.AccessToken)
);
}
public async Task<EmbedConfig> GetEmbedConfig(string username, string[] roles = null)
{
var report = await _client.Reports.GetReportInGroupAsync(
Guid.Parse(_workspaceId),
Guid.Parse(_reportId)
);
var generateTokenRequest = new GenerateTokenRequestV2
{
Reports = new List<GenerateTokenRequestV2Report>
{
new GenerateTokenRequestV2Report(Guid.Parse(_reportId))
},
Datasets = new List<GenerateTokenRequestV2Dataset>
{
new GenerateTokenRequestV2Dataset(report.DatasetId)
}
};
// Apply RLS if roles specified
if (roles != null && roles.Length > 0)
{
generateTokenRequest.Identities = new List<EffectiveIdentity>
{
new EffectiveIdentity(
username,
datasets: new List<string> { report.DatasetId },
roles: roles.ToList()
)
};
}
var embedToken = await _client.EmbedToken.GenerateTokenAsync(generateTokenRequest);
return new EmbedConfig
{
ReportId = report.Id.ToString(),
EmbedUrl = report.EmbedUrl,
Token = embedToken.Token,
TokenExpiry = embedToken.Expiration
};
}
}
Interactive Features
Filtering Reports
// Apply filters programmatically
const filter = {
$schema: "http://powerbi.com/product/schema#basic",
target: {
table: "Sales",
column: "Region"
},
operator: "In",
values: ["North", "South"]
};
report.setFilters([filter]);
// Date range filter
const dateFilter = {
$schema: "http://powerbi.com/product/schema#advanced",
target: {
table: "Sales",
column: "Date"
},
logicalOperator: "And",
conditions: [
{ operator: "GreaterThanOrEqual", value: "2022-01-01" },
{ operator: "LessThan", value: "2022-04-01" }
]
};
report.setFilters([dateFilter]);
Handling Events
// Selection event
report.on('dataSelected', function(event) {
const data = event.detail;
console.log('Selected data:', data.dataPoints);
// Navigate to detail page
if (data.dataPoints.length > 0) {
const customerId = data.dataPoints[0].identity[0].equals;
window.location.href = `/customer/${customerId}`;
}
});
// Page change event
report.on('pageChanged', function(event) {
console.log('New page:', event.detail.newPage.displayName);
});
// Button click event (for bookmarks)
report.on('buttonClicked', function(event) {
console.log('Button clicked:', event.detail);
});
Row-Level Security
Define Roles in Power BI
// In Power BI Desktop, create role "RegionalManager"
[Region] = USERNAME() OR [ManagerEmail] = USERPRINCIPALNAME()
Apply RLS in Embed Token
var identity = new EffectiveIdentity(
username: "user@company.com",
datasets: new List<string> { datasetId },
roles: new List<string> { "RegionalManager" }
);
// For dynamic RLS
var identity = new EffectiveIdentity(
username: userEmail,
datasets: new List<string> { datasetId },
roles: new List<string> { "SalesRep" },
customData: region // Pass custom data for RLS filter
);
Performance Optimization
// Pre-load reports
powerbi.preload({
type: 'report',
embedUrl: embedUrl
});
// Use bootstrap for faster initial load
const config = {
type: 'report',
embedUrl: embedUrl,
settings: {
background: models.BackgroundType.Transparent
}
};
const report = powerbi.bootstrap(container, config);
// Later, apply token when available
report.setAccessToken(accessToken);
Best Practices
performance:
- Use Premium/Embedded capacity
- Pre-load reports when possible
- Minimize visual count per page
- Use aggregations for large datasets
security:
- Always use embed tokens (not AAD tokens for external)
- Implement RLS for data security
- Set short token expiry
- Validate user permissions server-side
user_experience:
- Handle loading states
- Provide error feedback
- Enable mobile layout for responsive
- Consider white-labeling options
Conclusion
Power BI Embedded enables rich analytics in any application:
- Interactive reports and dashboards
- Secure multi-tenant access
- Programmatic control and customization
- Scalable capacity-based pricing
It’s the foundation for analytics-powered applications.