HubSpot Reporting for Recruiters: Dashboards That Work

Recruitment firms come to HubSpot reporting frustrated, and the frustration is almost always blamed on the tool. The tool is rarely the problem. The problem is almost always what was built before anyone opened the report builder.
HubSpot reporting for recruiters: the exact dashboards, metrics, and custom report configs that actually reflect how recruitment firms operate.
HubSpot Reporting for Recruiters: Dashboards That Work
Recruitment firms come to HubSpot reporting frustrated, and the frustration is almost always blamed on the tool. The tool is rarely the problem. The problem is almost always what was built before anyone opened the report builder.
Why Most Recruitment Firms Get HubSpot Reporting Wrong From the Start
The pattern I see repeatedly: a firm implements HubSpot, builds a deal pipeline that mirrors their recruitment stages - Briefed → Candidates Sent → Shortlisted → Placed - and it looks correct. Six months in, someone asks "what's our average time-to-fill?" and there's no way to answer it from the data that exists.
The root cause is using deal stage as a proxy for both vacancy status and candidate progression without a defined property schema. The two things become tangled. You can no longer distinguish "this deal moved to Shortlisted because a candidate was shortlisted" from "this deal moved to Shortlisted because the client reviewed the CVs." The stage label carries the meaning. The data doesn't.
A specific failure mode worth naming: no Source of Application property on Contact or Deal at point of entry means source-of-hire attribution is permanently lost. You cannot retrospectively tag it. The data was never captured, so no report can surface it.
Most firms respond by going looking for the right report. The right report is structurally impossible to build because the upstream schema doesn't support it. HubSpot's custom report builder joins objects via defined associations. If those associations weren't built into your pipeline setup, you cannot pull those metrics now. That is a data modelling problem, not a dashboard configuration problem.
The Three Reporting Layers a Recruitment Firm Actually Needs
Before touching any report configuration, it's worth being clear about who the reports are for. There are three distinct layers, and conflating them is the second most common mistake after the schema problem.
BD and client reporting - pipeline value by stage, vacancy win rate (vacancies briefed vs. filled), client conversion rate from prospect to retained or exclusive. Audience: BD director, MD.
Delivery reporting - candidate pipeline velocity, time-in-stage per vacancy, drop-off point analysis showing where candidates fall out of the process. Audience: delivery lead, billing manager.
Activity reporting - calls made, CVs submitted, interviews booked, offers extended per consultant per week. Audience: line managers, ops.
A delivery consultant looking at a dashboard that includes weighted pipeline revenue is seeing noise. A BD director looking at average CV-to-interview conversion is also seeing noise. One dashboard built to serve both audiences serves neither.
The conflation problem shows up in a specific way: a firm builds one pipeline where "Shortlisted" means both "client has been given CVs" and "candidate has been shortlisted." When you filter by stage in a report, you're pulling both meanings into the same row. The numbers look plausible. They're meaningless.
Separating reporting by audience also means separating dashboard permissions where possible. Consultants don't need visibility of margin figures or total pipeline revenue. That's occasionally a data privacy issue, and it's always a distraction from the metrics that are actually relevant to them.
Setting Up Pipelines and Properties So Reports Are Actually Possible
The two-pipeline structure
What I'd do from the outset is build two separate pipelines in HubSpot Deals:
BD pipeline - stages map to client and vacancy development: Prospecting → Briefed → T&Cs Agreed → Vacancy Filled / Lost. This tracks the commercial relationship with the client.
Candidate pipeline - stages map to candidate progression: Identified → Submitted → Interviewed → Offered → Placed / Rejected. This tracks each placement attempt.
Both pipelines associate to the same Company record in HubSpot. That association is what makes the BD-to-placement conversion report possible later. If the two pipelines are pointing at different company records, or if the company association is missing from one of them, that report becomes impossible to build without manual reconciliation.
The custom properties you need before you start
On Deals in the candidate pipeline, you need at minimum:
Source of Application - dropdown, populated at point of submission. Options: job board, referral, database search, LinkedIn, direct application. Agree the list before you create the property - changing dropdown options later doesn't update historical records.
Placed Date - date property, set when the deal moves to Closed Won. HubSpot's native Close Date field works, but a custom Placed Date property is cleaner if your close date is being used for other purposes.
Vacancy ID - single-line text or number, cross-referencing the BD pipeline deal or, for firms using Bullhorn, the Bullhorn vacancy ID. This is the join key if you ever need to reconcile data between systems.
Fee Value - currency property, separate from the Deal Amount field. For contingency-based firms, deal amount is often blank or estimated at creation. Fee Value gets populated at placement and gives you accurate revenue reporting.
On associations: set up a custom association label between Contacts and Deals - Candidate: Placed alongside the default association. This is the thing most firms skip, and it's the point where HubSpot reporting for recruiters breaks down in practice. Without a custom association label, you cannot filter in the custom report builder to distinguish "candidate associated to this deal" from "client contact associated to this deal." HubSpot's default association model doesn't carry that distinction natively. There is no workaround for this - you either have the association label or you don't.
One more thing worth flagging on the candidate pipeline: time-in-stage tracking only works correctly if stage names are consistent and the deal has actually moved through stages sequentially. Deals bulk-created directly at a later stage will show 0 days for every earlier stage. That's a data quality issue that will permanently skew your time-in-stage averages if it's widespread.
The Five Reports Worth Building in HubSpot for a Recruitment Firm
1. Time-in-stage by pipeline
Use the deal stage duration report in the custom report builder, filtered to the candidate pipeline only. Group by pipeline stage, with average days in stage as the metric. Filter by Deal Owner to cut it by consultant.
Worth knowing: this report shows current stage duration for deals still in that stage, plus completed stage duration for deals that have moved on. Deals created directly at a later stage - bulk imports, for example - will show 0 days for earlier stages. That's a data quality problem, not a report configuration problem.
2. Source-of-hire attribution
Built from the Source of Application property on Deals in the candidate pipeline. Build it as a funnel breakdown: total submissions by source, through to Placed. This tells you which source produces candidates that actually complete the process versus sources that drop out at interview stage.
This report requires Source of Application to have been populated consistently from day one. If it wasn't, you'll get a large "unknown" or blank category that makes every percentage in the report unreliable. There's no way to recover that data retrospectively.
3. BD-to-placement conversion by client
Cross-reference Associated Company data against Closed Won deals in both pipelines. The metric: of the vacancies a client briefed (BD pipeline Closed Won), what percentage resulted in a placement (candidate pipeline Closed Won, same associated company)?
This is the report recruitment MDs actually want. It identifies which clients fill their vacancies and which ones consume consultant time without converting. It requires both pipelines to be associated to the same Company record - which is why the two-pipeline structure matters from the start.
4. Consultant activity vs. outcome
Calls and meetings logged in HubSpot's activity log, compared against placements made in the same period, by Deal Owner. This report surfaces the ratio of activity to result. A consultant making 50 calls a week and placing once is a different problem from a consultant making 15 calls and placing twice.
The caveat: this only works if call logging is actually being done in HubSpot. If consultants are dialling from their mobile and not logging the call, the activity data is incomplete. That's a behaviour problem, not a system problem. The report will look like certain consultants are doing very little activity when they're actually just not logging it. Don't mistake the reporting gap for a performance gap without checking first.
5. Vacancy fill rate over time
Uses the Placed Date custom property on candidate pipeline deals, calculated against the Create Date of the associated BD pipeline deal or the vacancy creation date if you're using a Vacancy ID. HubSpot doesn't have a native "time-to-close from vacancy open" metric - you're building it from two date properties and the custom report builder.
Set Placed Date as the x-axis in a line chart and trend it over time. This is useful for demonstrating delivery speed improvement or deterioration across quarters, and it's one of the first things a client MD will ask for once the basic dashboards are live.
Where HubSpot's Reporting Genuinely Falls Short for Recruiters
HubSpot is not built for recruitment. There is no native object for a vacancy, a placement, or a candidate. Everything is adapted from generic CRM objects, and the reporting reflects that. Being clear about the limitations upfront saves a lot of time later.
Limitation 1: cross-object joins require defined associations. If the association doesn't exist in your schema, the join is impossible in the custom report builder. There is no workaround. You either built the association into the pipeline setup or you didn't. This catches firms who configured their pipelines quickly, without thinking about what they'd need to report on six months later.
Limitation 2: forecast reports are revenue-weighted. For contingency recruitment firms where fee value isn't confirmed until a placement is made, deals can sit at £0 for months. The weighted pipeline figure in HubSpot's forecast view will consistently understate what's actually in play. It's not a bug - it's how the feature is designed - but it makes the forecast view actively misleading for contingency desks.
Limitation 3: some standard report types lock to a single pipeline. If you want to compare candidate conversion rates across permanent and contract pipelines in one view, you need the custom report builder, not the standard reports. Some firms build their dashboards using standard reports, get everything looking right, and then discover they need to rebuild reports they thought were finished when they try to create a cross-pipeline view.
A specific failure mode that comes up more than it should: firms use Deals Created to track new vacancies and later realise they can't filter by vacancy type - perm, contract, interim - because they never created a Vacancy Type property. The data is buried in the deal name, where it's not queryable in any report. By the time this is discovered, there may be hundreds of deals with no structured vacancy type data.
When to Bring in a Third-Party Reporting Layer
The practical threshold where HubSpot's dashboard builder starts producing workarounds rather than clarity: more than 5 consultants, running perm and contract simultaneously, needing blended BD and delivery reporting in the same view. At that point, pulling data out of HubSpot and presenting it elsewhere is often cleaner than trying to configure your way around the native limitations.
Two options worth naming:
Databox - integrates directly with HubSpot via a native connector. Pulls HubSpot metrics into KPI-style dashboards that are readable by people who don't log into HubSpot - MDs, ops, board. Good for weekly performance snapshots. The limitation is that it reads HubSpot's data model as-is. If the properties aren't clean in HubSpot, Databox can't fix them. It will faithfully report your bad data in a much nicer format.
HubSpot to Google Sheets via the native integration - useful for firms that already work in Sheets and want to build custom calculations the HubSpot report builder can't handle, such as blended margin or banded fee calculations. The sync is list-based rather than real-time, so it's suited to weekly reporting, not live dashboards.
For firms running HubSpot and Bullhorn in parallel: the cleanest approach is usually to keep candidate data in Bullhorn and BD data in HubSpot and report on each system separately. Trying to join the two in HubSpot's dashboard requires a custom integration and a very clean Vacancy ID cross-reference throughout both systems. It is achievable, but it adds meaningful complexity and ongoing maintenance overhead. Worth being honest about that before committing to the approach.
A Practical Checklist Before You Build Any HubSpot Report
This is what I check before touching the report builder on any new client engagement. If the answer to any of these is no, the reports that follow will either be wrong or incomplete.
Correct pipeline structure exists. BD pipeline and candidate pipeline are separate, stage names are consistent, and - critically - no stage names have been renamed mid-project. Renaming a stage in HubSpot breaks historic stage duration data for any deal that passed through that stage before the rename. The old name disappears from the record.
Required custom properties are created and labelled consistently. Source of Application, Placed Date, Vacancy Type, Fee Value. Check that dropdown options match across the team. One person writing "LinkedIn" and another writing "linkedin" produces two different filter values in every report that uses that property.
Association types between objects are defined. Custom association labels are in place between Contacts and Deals (Candidate: Placed), and between BD pipeline deals and candidate pipeline deals where relevant. If this wasn't set up at the start, it cannot be applied retroactively to historical records.
Historical deal data has been populated. Blank fields don't appear as zero in reports - they disappear from the dataset entirely. A deal with no Source of Application value won't show as "unknown" by default. It simply won't appear in the source breakdown. This skews every percentage in any report that uses that field, and the skew gets worse the older the data is.
Correct team and owner filters are in place. Consultant-level reports need to be scoped to the correct team. A cross-team view at consultant level is usually displaying the wrong data and occasionally a data privacy issue if margin or salary figures are visible to people who shouldn't see them.
If you're not sure whether your current HubSpot setup passes this checklist, the Revenue Audit at stacklogic.co.uk/services covers this as part of the initial assessment - looking at pipeline structure, property schema, and association configuration before making any recommendations about what to build.