Professional services teams track customer-side blockers in a shared log that names a client owner, the date raised, the needed-by date, and the deliverable each one holds up. The lead reviews the log with the client, oldest items first, at every meeting, and counts days past the needed-by date, so each delay is dated and attributed.
What makes a customer-side blocker different from an internal one?
A customer-side blocker is work only the client can do that holds up your software rollout. Your team doesn't own it, can't assign it, and can't finish it by working harder. A customer-side blocker needs a named owner on the client side, a view the client can see, and dates showing who waited on whom.
In software rollouts these blockers tend to look like this:
- Access, credentials, or an SSO setup that sits with the client's IT team
- A security or procurement review the client has to finish
- A data extract, field mapping, or sample file
- Test sign-off or user acceptance on a deliverable
- A decision on a configuration or workflow choice
- Time from a subject matter expert who is hard to schedule
The risk is that these stay invisible. Planhat's onboarding guide names untracked customer dependencies as one of the most common onboarding failure modes. AppMaster's onboarding tracker guide makes a similar point: silent blockers, such as waiting for credentials or a security team's approval, create the costliest delays. Often the problem only shows after a deadline has passed.
Which fields should a customer blocker log capture?
A customer blocker log needs fields that answer what is needed, who on the client side owes it, when it is needed, and what it holds up. Add the dates that let you measure delay later, including when your own team held the next step. Leave out anything you won't keep up to date.
| Field | What to record | Why it matters |
|---|---|---|
| Blocker | What is needed, written as a thing to deliver: "[System] admin access for [role]" | Makes the request specific enough to finish |
| Owner side | Customer or us | Keeps client delay separate from your own |
| Customer owner | A named person, not a team or a shared inbox | Someone has to be able to say yes |
| Our contact | The team member who follows up | Makes clear who chases |
| Raised on | The date you first asked | Starts the age count |
| Needed by | The date the work must arrive to protect the plan, agreed with the client | Starts the delay count |
| Deliverable or milestone held up | The specific deliverable it blocks | Shows the impact |
| Impact if late | One plain sentence on what slips | Helps the client prioritize |
| Status | See the statuses below | Lets you filter and sort |
| Next action and who acts next | The next step and the person taking it | Prevents the "I thought you had it" stall |
| Next follow-up date | When you will check again | Keeps follow-up from depending on memory |
| Waiting on us: moved in, moved out | Each date the item moved to "Waiting on us" and the date it moved back | Lets you take your own days out of the delay count |
| Resolved on | The date the work arrived and was usable | Ends the delay count |
| Evidence | A link to the original request and the reply | Backs up the dates if anyone disputes them |
Several of these fields come straight from current practice. AppMaster recommends marking each item as internal or customer-side and recording when the blocker started, who acts next, and the next follow-up date. Lark's issue tracking guide argues for one central log where every issue has an owner, a priority, and a deadline.
Give each blocker exactly one status at a time:
- Open: logged, request not yet sent
- Waiting on customer: request sent, and the client owes the next step
- Waiting on us: the client replied and your team owes the next step
- Resolved: the work arrived and is usable
- Withdrawn: no longer needed because the plan changed
Whether an item is past due comes from its needed-by date, not from a separate status. Filter for "Waiting on customer" items with a needed-by date before today to see what is late.
A "Waiting on customer" status is the one AppMaster suggests. ClickUp's blocker page describes custom statuses for blocked work in ClickUp.
A filled-in entry looks like this:
Blocker: [System] sandbox credentials for [role] Owner side: Customer | Customer owner: [Name, title] | Our contact: [Name] Raised on: [Date] | Needed by: [Date] Holds up: [Deliverable or milestone] Impact if late: [Milestone] moves by the same number of days this arrives late. Status: Waiting on customer | Next action: [Name] to confirm ticket number with [IT contact] | Next follow-up: [Date] Waiting on us: [Date moved in] to [Date moved out] Evidence: [Link to request]
Where should the customer blocker log live?
A customer blocker log should live in the delivery tool your team already treats as the source of truth, with a filtered view the client can see. Keep one record and show it to both sides. Don't keep a private tracker and a separate client spreadsheet that drift apart.
In practice, pick one of these:
- Your PSA or project tool with an "Owner side" field and a saved filter showing only customer-owned items, shared with client contacts
- A client portal or shared plan that pulls from the same tasks
- A shared tracker the client can edit, if the client has no access to your tool
When choosing, check whether the client can actually get in. monday.com's issue tracking comparison notes that external stakeholders without Asana accounts struggle to file issues. That friction applies to any tool that needs a login. Planhat recommends a task list the customer can see, so their accountability is visible. AppMaster advises keeping internal work separate from the updates the customer needs to see.
If client logins are the obstacle, ask by email instead. Unblockd supports asks to the sponsor by email with one-tap answers (no account), or answered by replying to the email.
Check these settings before you share the client view:
- Internal notes and commercial comments are hidden from the client view
- The client view is sorted by needed-by date, then by age
- Each customer owner can see their own items without searching for them
How often should you review customer-side blockers?
Review customer-side blockers at a steady rhythm: check follow-up and needed-by dates yourself between meetings, walk the client through the customer-owned list, oldest first, at every standing client meeting, and reconcile the dates at each milestone. That routine keeps every customer-side blocker with a named owner, a next step, and a current date.
AppMaster suggests sorting blockers by age and reviewing anything that hasn't changed for a few business days. Turn that into one rule: any customer-owned item that has not changed since its last follow-up date gets a follow-up that day and a new follow-up date.
A simple routine:
- Between meetings: filter for customer-owned items whose next follow-up date has arrived without a change, or whose needed-by date is close. Send the follow-up and set a new follow-up date.
- In the client meeting: open the client view and go through the oldest items first. For each one, confirm the owner, the next step, and a date.
- At each milestone: check the resolved-on and waiting-on-us dates against the evidence and total the customer delay days for that milestone.
Wording for the meeting:
"Here are the items we need from your side, oldest first. For [blocker], [owner] is listed. Is that still right, and what date can we put next to it? If it lands after [needed-by date], [milestone] moves with it."
How do you measure time blocked by the customer?
Measure time blocked by the customer as customer delay: the days from the needed-by date to the resolved-on date, or today, minus any days after the needed-by date when the item sat in "Waiting on us". Track age, from the raised-on date, alongside it. Count customer delay only when the blocker sits on a milestone's path.
The calculation for each blocker:
Customer delay days = (resolved-on date, or today) minus needed-by date, minus days in "Waiting on us" after the needed-by date Age = (resolved-on date, or today) minus raised-on date
Steps that keep the count fair:
- Agree the needed-by date in writing when you raise the blocker. A date you set alone is easy to dispute.
- Record resolved-on as the date the work became usable. If the credentials arrive but don't work, the blocker stays open.
- Take out the days in "Waiting on us". Use the moved-in and moved-out dates on the entry to subtract every day after the needed-by date when your team held the next step. Those days are yours, not the client's.
- Count overlapping blockers once. For each milestone, count the calendar days on which at least one customer blocker on its path was past due and waiting on the customer. Don't add up each blocker's days separately.
- Keep the evidence link with every entry. The dates mean little if nobody can see the request and the reply.
A milestone ledger can stay this simple:
Milestone: [Name] | Planned date: [Date] | Forecast date: [Date] Customer delay days: [Number] (from [blocker IDs]) Days waiting on us: [Number] (from [blocker IDs])
The milestone ledger is the dated evidence you bring to the sponsor when a milestone date has to move. It shows which days the plan waited on the client and which days it waited on your team, with a link to each request behind them.
This record matters beyond the schedule. Precursive's implementation services guide gives an example of $100m in ARR booked but only $40m recognized because of delivery delays. Planhat lists customer response rate and on-time go-live among its onboarding KPIs. A dated blocker log gives you the facts behind both.
How do you set the log up at kickoff?
Set up the customer blocker log at kickoff by agreeing on the client-side dependencies, their owners, and their needed-by dates before any of them is late. Raising expected dependencies early turns later follow-ups into reminders the client already agreed to, not surprises, and gives every needed-by date a written starting point.
Planhat recommends agreeing customer-side dependencies at kickoff and keeping a running risk and blocker log.
Wording for the kickoff:
"To hit [go-live date], we need a few things from your side: [access], [data], [sign-off on deliverable]. Can we name an owner and a needed-by date for each now? We'll keep them in a shared list you can see, and review it with you at each check-in."
When does a customer blocker log backfire?
A customer blocker log backfires when the client reads it as a list of blame, or when it treats as customer-owned a delay your own unclear request caused. Then the dates get disputed and the log stops being trusted. Clear requests, honest use of "Waiting on us", and shared facts about the plan keep the log trusted.
Prevent that like this:
- Write every request so the client could act on it without a call: what, why, by when, and in what format.
- Use "Waiting on us" honestly whenever the next step is yours, including when your request needed rework.
- Present the log as shared facts about the plan: "this is what moves if this arrives late". Never frame it as "you are late".
The log records and dates the delays. It doesn't settle them. What you do with the totals belongs in your contract and sponsor conversations.
What should you set up first?
Set up the customer blocker log first by adding an "Owner side" field and a "Waiting on customer" status in the project tool you already use. Move every open client-owned item into a filtered view with a named owner and a needed-by date, then share that view with the client before your next standing meeting.