Custom Azure DevOps Time Reports Anyone Can Build
"How many hours went into the payments area last sprint, broken down by person?" It's the kind of question a dev lead gets asked on Monday and is expected to answer by Tuesday. In Azure DevOps, the honest answer is often: give me a week and a Power BI workspace.
This article covers why Azure DevOps time reporting is harder than it should be, what a usable time report actually requires, and a field-picking approach that answers the common questions — by iteration, by area path, by tag, by person — without any technical setup, spreadsheets, or query-writing.
Why simple time questions are hard in Azure DevOps
Azure DevOps is a work tracker, not a time tracker. That one distinction drives everything that follows.
Completed Work is a snapshot, not a ledger
The closest thing to native time data is the trio of effort fields on task work items (available in the Agile and CMMI process templates): Original Estimate, Remaining Work, and Completed Work. Completed Work is a single running number, overwritten in place every time someone updates it.
That design has three consequences for reporting:
- No dates. You can see that a task accumulated 14 hours, but not whether those hours landed in March or June. Date-ranged questions — the basis of almost every timesheet, invoice, and sprint report — have no native answer.
- No person attribution. If a task changes hands, the field doesn't record who contributed which hours. The current assignee inherits the whole number.
- No entries. There's nothing to audit, approve, or correct line by line. One typo replaces the entire history.
The native reporting stack assumes you'll build the report
When teams outgrow the effort fields, the documented paths are all build-it-yourself paths:
- Work item queries can show effort columns and export results to CSV — but you're exporting snapshots of a cumulative field, with no time dimension and limited grouping.
- Analytics views are curated datasets designed as a feed for Power BI, not as reports in themselves.
- The Analytics OData API is genuinely powerful — and it's built for developers, not the people who read reports. To get hours by person and iteration, you write something like:
`` https://analytics.dev.azure.com/{org}/{project}/_odata/v3.0-preview/WorkItems? $apply=groupby( (AssignedTo/UserName, Iteration/IterationName), aggregate(CompletedWork with sum as SumCompleted) ) ``
- Power BI turns Analytics data into real dashboards — after you model the data, schedule refreshes, sort out licensing, and commit to maintaining the report as your process fields evolve.
And here's the catch even for teams that push through: because Completed Work is cumulative, the OData query above still can't answer "hours logged in June." For that you'd query daily work-item snapshots and compute deltas between them yourself.
None of this is a flaw in Azure DevOps. It's a boards-and-pipelines platform with a BI-grade analytics layer bolted to the side. But it means the effort-to-insight ratio for a simple time question is wildly out of proportion.
What a time report actually needs
Strip the tooling away and the requirements are short:
- Dated entries — who, when, how long, against which work item.
- Grouping on fields your team already uses — iteration, area path, tags, person.
- Filters and date ranges — this sprint, last month, one team, one client area.
- Saved views — so the month-end report is a click, not a rebuild.
- Export — CSV/Excel for finance, invoicing, or anyone outside DevOps.
Nothing on that list requires a query language. The data model is a flat table of time entries; the reports are pivots over it. The only reason raw data and query-writing enter the picture in Azure DevOps is that the platform never stores the entries in the first place.
Field-picking: Azure DevOps time reports anyone can build
This is the approach Hourdeck — Time Tracking & Timesheets for Azure DevOps takes. Hourdeck stores real, dated time entries against your work items, then makes reporting a matter of picking fields — the same area paths, iterations, tags, and people you already have in DevOps. No endpoint, no $apply, no dataset refresh.
Time report by iteration
Pick Iteration as your grouping and you get hours per sprint. Add Person as a second level and the Monday question from the intro — hours by iteration, by person — is a two-click pivot. Useful for sprint reviews, capacity retros, and sanity-checking estimates against actuals.
Slice by area path, tags, or person
The same picker works across every dimension:
- Area path maps naturally to products, components, or client engagements — one grouping choice gives you hours per client area.
- Tags capture cross-cutting work: incidents, tech debt, a compliance push.
- Person answers utilization and workload-balance questions without exporting anything.
Because these are DevOps' own fields, there's no mapping layer to maintain. Rename an area path in DevOps and your report follows.
Save the view, export to Excel
Any pivot can be saved as a named view, so recurring reports — month-end billables, sprint actuals, per-client hours — are one click each cycle. Every view exports to CSV/Excel for the people who live in spreadsheets.
Four ways to answer "hours by iteration, by person"
| Approach | You write | Dated, per-person entries | Group by iteration / area / tags / person | Excel/CSV out | Ongoing maintenance |
|---|---|---|---|---|---|
| Work item query on effort fields | Column picks | No — cumulative snapshot | Limited | Yes (rows only) | Low, but can't answer the question |
| Analytics views + Power BI | Data model + DAX | Daily snapshots; you compute deltas | Yes, once modeled | Yes | High — model, refresh, licensing |
| Analytics OData API | OData queries; developer-oriented | Snapshots; deltas are manual | Yes, per query | You build it | Medium — queries break as fields change |
| Field-picking time reports (Hourdeck) | Nothing — pick fields | Yes — native time entries | Built in | One click | None |
Azure DevOps billable hours, without a data project
Azure DevOps has no concept of billability — there's no field to build on even if you were willing to write the OData. Any billable-hours answer has to come from a layer that stores it per entry.
In Hourdeck, time entries carry billability, and two mechanisms keep the numbers defensible before they reach an invoice:
- Approvals — a lead signs off on timesheets, so exported hours are reviewed hours.
- Evidence-aware billability checks — entries are checked against the work evidence around them (commits, comments, work-item activity), flagging time that doesn't line up before a client ever sees it.
Filter a saved view to billable entries, group by area path or client, export — that's the invoicing report.
Where the data comes from
A report is only as good as the entries behind it, and entries only happen if logging time is nearly free. Hourdeck lives entirely inside Azure DevOps — an extension hub plus a Time tab on every work item — so nobody switches tools to log or report. One-click timers and a weekly timesheet handle day-to-day capture, and an AI assistant drafts your week from your own commits, comments, and work-item activity, so filling a timesheet becomes reviewing one. If your history lives in another time tracker, a one-click import brings it along so reports don't start from zero.
If your team is answering time questions with OData queries — or not answering them at all — try the field-picking approach instead. Hourdeck is free for up to 3 users with no time limit, and larger teams get a one-month free trial. Install it, log a week, and see whether "hours by iteration, by person" becomes a two-click question.
Frequently asked questions
Does Azure DevOps have built-in time tracking?
Not in the timesheet sense. Task work items in the Agile and CMMI process templates carry effort fields (Original Estimate, Remaining Work, Completed Work), but Completed Work is a single cumulative number that's overwritten on each update — there are no dated, per-person time entries to report on, approve, or export.
How do I create a time report by iteration in Azure DevOps?
Natively, you'd aggregate the Completed Work field by iteration through an Analytics OData query or a Power BI model on Analytics views — and because the field is cumulative, date-ranged totals require comparing daily snapshots. A time-tracking layer like Hourdeck stores dated entries against work items, so a by-iteration report is a field pick: group by Iteration, optionally add Person, and save the view.
Can I export Azure DevOps time data to Excel?
Work item query results export to CSV, but they contain snapshot effort values rather than dated time entries, so the export can't show hours per week, per person, or per date range. With Hourdeck, any saved report view — grouped by iteration, area path, tags, or person — exports to CSV/Excel in one click.
How do I track billable hours in Azure DevOps?
Azure DevOps has no billability field, so there's nothing native to report on. You need a layer that stores billability per time entry. Hourdeck marks entries billable, routes timesheets through approvals, and runs evidence-aware checks against commits, comments, and work-item activity, so the billable-hours export is reviewed and defensible before invoicing.
Do I need Power BI or OData to report on time in Azure DevOps?
Only if you're building reports from the platform's own analytics stack, which hands you raw data and assumes you'll model it yourself. If time is captured as dated entries inside Azure DevOps — as Hourdeck does via its extension hub and per-work-item Time tab — the common reports are pivots you build by picking fields, with no query language involved.
Try Hourdeck free
Hourdeck — Time Tracking & Timesheets for Azure DevOps. Free for up to 3 users.