Excelgoodies logo +31 97 010285556

LEARN THIS HANDS ON

Power BI Reporting

. Live Online FILLING FAST
View all upcoming batches
Power BI and AVG: Is Your Dashboard Leaking Personal Data?

Power BI and AVG: Is Your Dashboard Leaking Personal Data?

The sales performance dashboard looks great in the Monday stand-up, until someone zooms in and realises you can guess which underperforming bar belongs to which salesperson. Your model only has employee IDs, but combined with filters and drill-through, identities suddenly become obvious. This post shows how to spot those AVG (GDPR) privacy leaks in Power BI and how to redesign your model, visuals, and sharing so your dashboards stay useful without exposing personal data.


The Scenario: Sales Dashboard Meets Privacy Officer

You’re building a sales performance report for a commercial team:

  • Fact table with daily sales per order
  • Dimensions for Customer, Product, Region, Salesperson
  • Salesperson dimension has: SalespersonID, Name, Email, Manager, HireDate

The request from management:

  • Leaderboard of top/bottom salespeople
  • Trend lines by salesperson
  • Drill-through to see details per rep

The report works. People love it.

Then the privacy officer joins a demo and asks:

“Can you see individual performance per salesperson? Is this shared with everyone in the organisation?”

You answer “Yes, but it’s just internal.”

Now you’re in AVG territory:

  • Named individuals
  • Performance data
  • Broad sharing via Power BI Service

Let’s walk through how to turn this into a compliant, privacy-aware setup without killing the usefulness of the report.


Step 1 – Identify Personal Data in Your Power BI Model

Before you fix anything, you need to know what counts as personal data under AVG.

Obvious personal data

Fields that directly identify a person:

  • Names (FirstName, LastName, FullName)
  • Contact details (Email, Phone, Mobile)
  • Employee identifiers (EmployeeID, UserPrincipalName, login names)
  • National identifiers (BSN, tax numbers) – these should almost never be in BI

Less obvious, but still personal

Even if you removed names, a person can be identifiable when:

  • There is a unique code that only a few people know (e.g. SalespersonID that HR uses)
  • You combine data with other systems (e.g. same IDs in CRM)
  • There are very small groups (e.g. only one salesperson in a tiny region)

In our sales dashboard scenario, the risky fields are:

  • Salesperson[Name]
  • Salesperson[Email]
  • Salesperson[EmployeeNumber]
  • Detailed performance measures at individual level

Create a quick checklist for each table:

  • Does this column identify a person directly?
  • Could this column identify a person when combined with other data?
  • Is this column needed for the business question?

If the answer to the last question is “no”, that column should not be in the model at all.


Step 2 – Decide: Individual vs Aggregated Reporting

AVG doesn’t forbid all personal data in reporting. It forces you to justify it.

For each measure and visual, ask two questions:

  1. Do we really need to see this at individual level?
  2. Who needs to see it at that level?

In our scenario, we can split the requirements:

  • Team-level report for all sales staff:

    • Total sales by region, product, channel
    • Rankings by region or team, not by person
    • No names, no emails
  • Manager report for line managers and HR:

    • Individual performance per salesperson
    • Drill-through to underperformers
    • Possibly HR metrics (tenure, absence) if justified

This naturally leads to:

  • One aggregated report: no personal data, broad audience
  • One sensitive report: personal data, limited audience

Trying to satisfy both use cases in one report is where most leaks start.


Step 3 – Anonymise and Aggregate Where You Can

Where you don’t need individual identities, strip them out or mask them.

Option 1: Remove identities from the model

For the team-level report, simply don’t load names and emails.

In Power Query, keep only what you need:

let
    Source = Sql.Database("SQLSERVER01", "SalesDW"),
    SalespersonRaw = Source{[Schema="dbo",Item="DimSalesperson"]}[Data],
    Salesperson = Table.SelectColumns(
        SalespersonRaw,
        {"SalespersonKey", "Region", "Team"} // no Name, Email, EmployeeNumber
    )
in
    Salesperson

Now your visuals can’t show what isn’t there.

Option 2: Use pseudonyms or grouping

If you still need some notion of “person” but not who exactly, you can:

  • Group by role or level (e.g. Senior, Junior)
  • Show rankings without names (e.g. Rep 1, Rep 2)

Example in Power Query to create pseudonyms:

let
    Source = Sql.Database("SQLSERVER01", "SalesDW"),
    SalespersonRaw = Source{[Schema="dbo",Item="DimSalesperson"]}[Data],
    IndexAdded = Table.AddIndexColumn(SalespersonRaw, "PseudoID", 1, 1, Int64.Type),
    Pseudonymized = Table.TransformColumns(
        IndexAdded,
        {{"PseudoID", each "Rep " & Text.From(_), type text}}
    ),
    Result = Table.SelectColumns(Pseudonymized, {"SalespersonKey", "PseudoID", "Region", "Team"})
in
    Result

Your visuals can now show PseudoID instead of real names.

Option 3: Aggregate before loading

Instead of loading row-level transactions, load pre-aggregated data:

SELECT
    s.Region,
    s.Team,
    CAST(s.SaleDate AS date) AS SaleDate,
    SUM(s.SalesAmount) AS TotalSales,
    COUNT(DISTINCT s.SalespersonKey) AS SalespeopleCount
FROM FactSales s
GROUP BY
    s.Region,
    s.Team,
    CAST(s.SaleDate AS date);

This way, your Power BI model never even sees individual-level performance.


Step 4 – Use Row-Level Security for Legitimate Individual Reporting

For the manager report, you may have a legitimate reason to show individual performance. Here the leak risk moves from data content to data access.

Row-Level Security (RLS) is your main tool.

Design RLS around roles and responsibilities

In our scenario:

  • Salespeople should only see their own performance
  • Managers should see their team’s performance
  • HR or leadership might see all salespeople

You can model this with a DimUser table linked to Salesperson.

Example structure:

  • DimUser:

    • UserPrincipalName
    • Role (Sales, Manager, HR)
    • SalespersonKey (for individual mapping)
    • Team (for manager mapping)
  • DimSalesperson:

    • SalespersonKey
    • Team
    • Name

Sample RLS DAX filters

  1. Salesperson role – see only own data
-- On DimSalesperson
UserPrincipalName = USERPRINCIPALNAME()

If you have a bridge table:

-- RLS on DimUser
DimUser[UserPrincipalName] = USERPRINCIPALNAME()
  1. Manager role – see only their team
-- RLS on DimUser
DimUser[UserPrincipalName] = USERPRINCIPALNAME()
    && DimUser[Role] = "Manager"

Then rely on relationships so that only matching teams in DimSalesperson are visible.

  1. HR role – see all

You can create a separate role with no filter on DimSalesperson, but assign it only to a small, controlled group.

Common RLS mistakes that cause leaks

  • Testing RLS only in Desktop, not in Service
  • Giving “Build” permission on the dataset to too many people
  • Using shared links or “Publish to web” on sensitive reports
  • Assuming that hiding a page or visual equals security (it doesn’t)

Always test with “View as” in Power BI Service and with real user accounts where possible.


Step 5 – Watch Out for Re-identification in Visuals

Even if your data model is anonymised, visuals can still leak identity indirectly.

Small groups and outliers

If there is only one salesperson in Region = North and you show Sales per Region, then everyone who knows the org structure knows whose performance that is.

Mitigation options:

  • Don’t show metrics for groups smaller than a threshold
  • Combine small groups into an “Other” bucket

Example DAX measure to suppress small groups:

Sales (Suppressed) = 
VAR DistinctSalespeople = DISTINCTCOUNT(Sales[SalespersonKey])
RETURN
IF(
    DistinctSalespeople < 3,
    BLANK(),
    [Total Sales]
)

Use this measure in visuals instead of raw [Total Sales].

Drill-through and tooltips

The main report might be aggregated, but:

  • Drill-through pages might show detailed rows
  • Tooltips might reveal names or IDs

In our scenario, the team-level report should:

  • Disable drill-through to individual-level pages
  • Use generic tooltips (no names, no IDs)

Keep the detailed drill-through pages in the manager report only.


Step 6 – Tidy Up Sharing, Exports, and Lineage

A lot of AVG risk in Power BI is not the model, but what people do with it.

Control sharing in Power BI Service

For the aggregated team report:

  • Publishing to a wide audience is usually fine if no personal data is present

For the manager report:

  • Use dedicated workspaces with controlled access
  • Turn off “Reshare” for users who don’t need it
  • Avoid using “Publish to web” under all circumstances

Restrict exports

Exports can break all your careful RLS and aggregation if misconfigured.

Check per report:

  • Who can export data to Excel/CSV?
  • Is export limited to summarised data only?
  • Are there any sensitive columns that shouldn’t be exportable?

If your organisation allows it, consider:

  • Summarised-only export for sensitive reports
  • No export at all for HR-like dashboards

Document your data flows

Have a simple document (even a PowerPoint slide) that shows:

  • Source systems and which personal data they contain
  • Which datasets and reports use personal data
  • Which roles have access to which reports

This isn’t just for audits; it helps you avoid accidental reuse of sensitive datasets in new reports.


Step 7 – Build Privacy into Your Power BI Development Process

To avoid fighting fires later, make privacy checks a standard part of your workflow.

Add a privacy checklist to your PBIX template

For every new report:

  • Does the dataset contain personal data?
  • Is personal data necessary for the business question?
  • Is there a non-personal alternative (aggregation, anonymisation)?
  • Who should see personal-level data, if any?
  • Is RLS configured and tested?
  • Are exports and sharing settings appropriate?

Agree on standard patterns

With your team, define:

  • A standard way to model user roles and RLS
  • Naming conventions for sensitive datasets (e.g. prefix HR_, PII_)
  • Default settings for exports and sharing on sensitive reports

In our sales dashboard scenario, this would mean:

  • Two separate PBIX files: Sales_Team_Aggregated.pbix and Sales_Manager_Detail.pbix
  • Clear naming in workspaces so users know which is which
  • RLS and sharing configured to match the intended audience

One Concrete Takeaway

Before you publish your next Power BI report, do a quick pass over your model and visuals and ask: “Could someone reasonably identify a specific person from this?” If the answer is anything other than a clear “no”, either aggregate or anonymise the data, and lock down access with RLS and sharing controls before your privacy officer asks the question for you.

Editor's Note

This article reflects how Power BI teams can move from ad-hoc, person-level reporting to structured, privacy-aware designs that separate aggregated and sensitive views, especially in organisations where AVG/GDPR compliance and internal transparency need to coexist.

Professionals who want to apply these patterns to their own data can explore Excelgoodies' Power BI Reporting programme - taught live by instructors, with certification awarded once a real project is running at work.

Insights compiled through ongoing industry research and discussions within the Excelgoodies Analytics Community.

Power BI

New

Next Batches Now Live

Power BIPower BI
SQLSQL
Power AppsPower Apps
Power AutomatePower Automate
Microsoft FabricMicrosoft Fabrics
AzureAzure Data Engineering
Explore Dates & Reserve Your Spot → Reserve Your Spot →