Skip to the content.

Erlang C Staffing Planner — user guide

Calculate how many agents each interval needs, compare it to what you have rostered, and see where the day is short.

This guide takes about fifteen minutes end to end. The one step worth not skipping is Average handle time — it is the only field that will silently give you wrong answers if you get it wrong.


What you need

   
Power BI Desktop Current version
Interval data One row per interval, with contact volume and handle time
Roster data Optional. Agents scheduled per interval

Interval data usually comes out of the ACD or WFM platform — Five9, Genesys, NICE, Talkdesk, Amazon Connect, Cisco and similar all export it. Any grain works as long as it is consistent: 15, 30 or 60 minutes.


Step 1: Add the visual

If you bought the visual from Microsoft AppSource, there is no file to download. It installs from inside Power BI.

  1. In Power BI Desktop, open the Visualizations pane.
  2. Click the at the bottom of the icon list.
  3. Choose Get more visuals.
  4. Search for Erlang C Staffing Planner and click Add.

The Visualizations pane with the ... menu open, showing "Get more
visuals"

The icon then appears in the Visualizations pane and stays there for new reports. Updates arrive automatically.

If your organisation deploys visuals centrally

Some tenants block AppSource and have an administrator publish approved visuals instead. If Get more visuals shows an Organizational tab, or shows nothing at all, ask whoever administers Power BI in your organisation to add it.

Licences

Buying through AppSource gives you licences to assign, not a key to enter. Assign them per user in the Microsoft 365 admin center. After a licence is assigned it can take up to an hour to be recognised – refresh the browser, or restart Desktop.

Without a licence the visual still runs in evaluation mode, which calculates your own data with your own parameters over a limited number of intervals. See evaluation mode for what is and is not included.


Step 2: Load your data

Your table needs, at minimum:

Column Example Notes
Interval start 2026-03-02 09:30 Date/time. The start of the interval
Contacts 210 Contacts offered in that interval
Handle seconds 66394 Total seconds, not an average — see step 3
Queue Billing Optional
Scheduled agents 67 Optional

If your source gives you an average handle time rather than a total, that is fine — step 3 covers both.

Check the interval column

The visual identifies each interval by its timestamp, so the field you map to Interval has to tell two days apart. A Date/Time column does that on its own and is the simplest thing to use.

Power BI sometimes reads a timestamp as text instead. In the Data view, select the interval column and check the type in Column tools. If it says Text, use Transform data and set it to Date/Time.

The Column tools ribbon showing the data type for the selected interval
column

If your model splits the date and the time into separate columns, that works too, as long as the field you map still separates one day from the next. What does not work is mapping a bare time-of-day with the date discarded: every Monday 09:00 then keys to the same interval as every Tuesday 09:00, and a week silently folds into a single day.

The check takes five seconds. Hover any interval and read Queues in the tooltip. It should equal the number of queues you actually have. If you run three queues over five days and it says 15, your days have folded together.


Step 3: The one measure you must build

Average handle time cannot be a plain column. This is the single most common way to get a confidently wrong answer out of this visual.

Dropping a column called AHT into the field well makes Power BI average it — and an average of averages is not the average.

One interval handles 500 contacts at 200 seconds. The next handles 5 contacts at 900 seconds. The true weighted average is 207 seconds. Averaging the two averages gives 550. Offered load comes out nearly three times too high, and the visual will confidently recommend staffing for it.

Nothing will warn you. The chart looks entirely normal either way, so this is one to check yourself rather than wait to be told about.

If your data has total handle seconds

Right-click your table → New measure:

Weighted AHT =
DIVIDE(
    SUM( Interactions[HandleSeconds] ),
    SUM( Interactions[Contacts] )
)

DIVIDE rather than / so an interval with no contacts returns blank instead of an error.

If your data only has an average per interval

Reconstruct the total first, then divide:

Weighted AHT =
DIVIDE(
    SUMX( Interactions, Interactions[AvgHandleTime] * Interactions[Contacts] ),
    SUM( Interactions[Contacts] )
)

The WeightedHandleTime measure in the formula
bar

The screenshot is from the sample model, so the names differ from the examples above — the measure is WeightedHandleTime over a table called intervalsample. Call yours whatever suits your model; only the shape of the calculation matters.

Check it worked

Put Weighted AHT in a card visual with no filters. It should look like a plausible handle time for your operation — a few hundred seconds for voice. If it comes out in the thousands, the measure is summing rather than averaging.


Step 4: Add the visual and map the fields

Drop the visual on the canvas and fill the field wells:

Field well Drop in Required
Interval Your interval start column Yes
Forecast contacts Contacts (Sum) Yes
Average handle time (seconds) Weighted AHT Yes
Scheduled agents Scheduled (Sum) No
Queue or group Queue No

Until the first three are filled the visual tells you which one is still missing rather than drawing anything.

The field wells, with all nine filled
in

The screenshot shows nine wells because it also has the four what-if overrides from step 6 mapped. Only the five above matter for now.

The date hierarchy trap

Power BI creates an automatic date hierarchy and will drop your interval column in as Date Hierarchy — which throws away the time and collapses a week of half-hours into seven points.

Click the dropdown on the field chip in the well and pick the plain field name instead:

Left: the well expanded into Year, Quarter, Month, Day. Right: the chip
dropdown with the plain field ticked instead of Date
Hierarchy

On the left is the broken state — if your well looks like that, the visual is being handed a hierarchy rather than timestamps. On the right is the fix.

To turn it off everywhere: File → Options and settings → Options → Data Load → Auto date/time, unchecked.


Step 5: Set your staffing parameters

Open the Format pane. Under Staffing parameters:

Service level (SLA) — the two halves of your service target:

Setting Default Means
Answer this share of contacts 80% The percentage half
Within this many seconds 20s The time half

Together: “80% answered within 20 seconds.”

Staffing and intervals:

Setting Default Means
Shrinkage 30% Paid time not available for contacts: breaks, training, absence, meetings
Maximum occupancy 85% Ceiling on the share of productive time spent handling contacts
Interval length 30 minutes Must match your data’s grain

Set interval length to match your data

If your rows are 15 minutes apart, set 15. If they are hourly, set 60. This is not detected automatically, and it is not a preference — it tells the calculation how long each interval lasts.

Get it wrong and every number on the chart is wrong, with nothing to indicate it. Staffing for a 30-minute interval labelled as 15 comes out roughly half what you need. It is worth checking before you trust the first chart you draw.

About maximum occupancy

Occupancy is the share of an agent’s productive time spent actually handling contacts. Sustained occupancy above roughly 85% is a well-documented driver of burnout and attrition, so this setting is a ceiling, not a target — staffing is raised until occupancy falls below it.

This is usually why the numbers differ from an online Erlang calculator. Many of those solve only for service level and will happily return an answer implying 90%+ occupancy. This one adds agents until occupancy is under your ceiling, even when service level was already met. If you want to compare like for like, raise the ceiling and the answers converge.


Step 6: Let report readers change the parameters

The Format pane is author-only. Someone reading your published report cannot open it — so out of the box they cannot ask “what if shrinkage were 35%?”, which is often the whole reason they opened the report.

Four optional field wells fix that. Bind a what-if parameter to one and the reader gets a slicer.

Creating a what-if parameter

  1. Modeling tab → New parameterNumeric range.
  2. Fill it in. For shrinkage:

       
    Name Shrinkage %
    Data type Whole number
    Minimum 0
    Maximum 100
    Increment 1
    Default 30
  3. Leave Add slicer to this page ticked.
  4. Click Create.
  5. Drag the measure Power BI just created — Shrinkage % Value, not the column — into the visual’s Shrinkage % field well.

The completed parameter dialog: whole number, 0 to 100, increment 1, default
30

Step 5 is the one people get wrong, because Power BI creates three objects and they sit together under the same name:

What Named Use it?
A table Shrinkage % No
A column inside it Shrinkage % No
A measure Shrinkage % Value Yes

The measure looks like this:

Shrinkage % Value = SELECTEDVALUE('Shrinkage %'[Shrinkage %], 30)

SELECTEDVALUE reads whatever the slicer is set to, falling back to your default when nothing is selected.

In the Data pane the two sit together under the same table name and are easy to confuse. The measure carries a calculator icon; the column does not. Dropping the column in gives you the whole parameter range at once rather than the selected value.

Move the slicer; staffing recalculates.

The report with the parameter slicers down the right-hand
side

A layout that works

Four parameters is a lot of slicers. An arrangement that keeps them out of the way:

That keeps every assumption visible and adjustable without crowding the chart, and it is the layout the sample report uses.

The four override wells

Field well Overrides Suggested range
Target service level % The share half of your SLA 50 to 99
Answer within (seconds) The seconds half 10 to 120
Shrinkage % Shrinkage 0 to 60
Maximum occupancy % The occupancy ceiling 60 to 95

Whatever you do not map keeps its Format-pane value, so you can expose just shrinkage and leave the rest fixed.

Use whole numbers, not decimals

These take 80, not 0.8. Build your parameter over 0 to 100, not 0 to 1. The Suggested range column above is about what values are sensible to expose to a reader, not what the field accepts — the field accepts whole numbers, and a narrower slider is a courtesy, not a requirement.

A parameter built over 0–1 is the easy mistake and would otherwise compute staffing for a 0.8% service-level target quite happily. The visual catches it and tells you to multiply by 100 rather than calculating with it. Zero is allowed — 0% shrinkage is a real setting.

There is no override for interval length

Interval length describes your data rather than your assumptions, so it stays in the Format pane where you set it once. Readers can change the four settings above; they cannot change what an interval is.


Reading the chart

The staffing profile: required against scheduled, with shortfalls hatched and
surpluses shaded

Mark Means
Solid line Required scheduled agents — the answer, after shrinkage
Dashed line Scheduled agents — what you have rostered
Shaded band The gap. Red and hatched when short, green when surplus
Faint dotted line Required productive agents, before shrinkage. Off by default

Shortfalls are hatched as well as coloured, so they survive being printed in black and white, projected badly, or read by someone with colour-vision deficiency. If you export the report, the understaffed intervals still stand out.

The summary metrics

Metric Means
Forecast SLA The service level your roster is expected to deliver overall. Red when below target
Understaffed Intervals where scheduled staffing is below requirement
Largest deficit The worst single-interval shortfall
Peak required The highest scheduled requirement in range
Intervals on target The share of intervals that individually clear the target

Forecast SLA and Intervals on target answer different questions. One says what service level the day will deliver; the other says how many intervals clear the bar. A day can have two thirds of its intervals on target and still miss badly overall, if the misses land where the volume is.

Forecast SLA is weighted by contacts, because service level is a ratio of contacts answered in time to contacts offered. A quiet overnight interval sitting at 100% does not get to cancel out a morning peak sitting at 40%.

The assumptions line

Under the metrics, the parameters that produced the numbers:

80% in 20s · 30% shrinkage · 85% max occupancy · 30-min intervals

It follows whatever actually drove the calculation, so a reader moving a what-if slicer watches the assumptions move with it. A staffing number is not a fact on its own — it is a fact given those parameters.

Tooltips

Hover any interval for the full calculation: contacts, handle time, offered load in Erlangs, required productive agents, required scheduled agents, scheduled agents, the gap, expected service level and occupancy.

A tooltip on a three-queue interval, with the per-queue
breakdown

Every figure that went into the answer is there, so you can reconcile any interval against a spreadsheet by hand — useful when someone questions a staffing number.


Checking the maths yourself

Pick your busiest interval and work it through:

  1. Read contacts and weighted AHT from the tooltip.
  2. Offered load = contacts × AHT ÷ interval seconds. For 300 contacts at 280 seconds in a 30-minute interval: 300 × 280 ÷ 1800 = 46.7 Erlangs.
  3. Required productive agents will be somewhat above that — typically 10 to 20 percent higher at an 80/20 target.
  4. Required scheduled = that divided by 1 − shrinkage.

If required staffing comes out at three times offered load, or below it, the AHT measure is the first thing to check.


Working with queues

Mapping a queue field calculates each queue separately and adds the resulting agent counts together.

This is the no-pooling assumption: each queue is staffed by its own people. It matches how most contact centres actually schedule, and it errs towards more staff rather than fewer.

If your agents genuinely handle all queues from one pool, do not map the queue field. Pooling more traffic into one queue needs fewer total agents, so calculating them separately will overstate what you need.

Service level and occupancy are shown per queue rather than combined. A single service-level figure across three separately staffed queues would be misleading, so hover a multi-queue interval and the tooltip breaks it down queue by queue.


Formatting

The Format pane, with the Legend card expanded

Every text element takes font, size, bold, italic, underline, alignment and colour: X axis, Y axis, axis titles, legend, data labels, summary metrics and the assumptions line.

Colour has a Match report theme switch, on by default, so text follows your report’s own colour and stays readable on a dark theme. Turn it off to choose your own.

Other cards:

Custom date formats

Under X axis → Label format → Custom:

Doubled tokens pad with a leading zero; single ones do not. Shown for Monday 2 March 2026, 09:05:

Token Gives Token Gives
yyyy yy 2026, 26 HH H 09, 9
MMMM MMM March, Mar hh h 09, 9
MM M 03, 3 mm m 05, 5
dddd ddd Monday, Mon ss s 00, 0
dd d 02, 2 tt AM

Put literal text in single quotes. HH'h'mm gives 14h30; without quotes the h is read as a token. '' is an apostrophe.


Troubleshooting

Required staffing looks far too high. Almost always the AHT measure. Put it in a card and check it reads as a plausible handle time. See step 3.

Only a handful of points on the chart, one per day. The interval field is bound to the Date Hierarchy. Use the field chip dropdown to pick the plain field.

Staffing changes when I switch interval length, but the data did not. Correct — that setting tells the visual how long each interval is. Set it to match your data’s grain.

Scheduled staffing doubles when I change interval length. Your scheduled measure is summing rather than levelling. Scheduled agents is a headcount at a moment, not a quantity that accumulates.

“This field takes whole-number percentages.” A what-if parameter is returning a decimal. Build it over 0–100, not 0–1.

A gap in the scheduled line. Those intervals have no roster value. A blank is treated as unknown, not as zero agents, so the line breaks rather than dropping to the floor.

“Queue grouping requires a licence.” Splitting by queue needs a licence. Without one, remove the queue field — the visual then treats your traffic as a single pooled queue, which asks for fewer agents than staffing the queues separately would. Or assign yourself a licence in the Microsoft 365 admin centre.


What this visual does not do

This release sizes staffing for a forecast you already have. It does not:

Erlang C assumes Poisson arrivals, exponentially distributed handle times, no abandonment, and infinite queue patience. Real queues abandon, which makes Erlang C generally conservative — it tends to recommend slightly more staff than a model with abandonment would. That is usually the safer direction for a staffing plan, but it is worth knowing.


Privacy

All calculations run inside Power BI on your machine. The visual makes no network requests, requests no web-access permissions, and sends no data anywhere. Your contact volumes never leave your tenant.