Skip to content
All articles
Business

Scoping a web project that doesn't blow up

Fixed scope or hourly, acceptance criteria that are verifiable, change requests, what to cut first, and the red flags worth walking away from on both sides.

A. MeerPrincipal engineer
7 min read

Most failed web projects were not failed builds. They were failed scopes, agreed in a paragraph of good intentions and discovered to be three different projects around week five. The technical work is rarely the hard part. This is for both sides of the table, because a scope only holds if buyer and builder both understand what they signed.

Why scope blows up

Four causes account for nearly everything we have seen go wrong.

The deliverable was written as a noun. "A dashboard." "A booking system." "An admin panel." A noun has no boundary. Two reasonable people will picture work that differs by 200 hours and both will believe they read the same sentence. A verified behavior has a boundary: "an admin can filter bookings by date range and status, and export the filtered set as CSV."

Unstated integrations. The brief says "users can pay." It does not say Stripe Connect with split payouts to 40 vendors, tax handling in two countries, and an invoice PDF matching an accounting template. Each of those is real work, and each appears in week six as "obviously that was included."

Unowned content and data migration. Someone has to write 30 pages of copy, source the images, and clean the 8,000-row spreadsheet that becomes the products table. If the contract does not name that person and a date, the answer is "the developer, for free, at the worst possible time."

The approval loop nobody budgeted. Five business days of review, twice, is two weeks of calendar. It appears in no estimate and delays every downstream milestone.

Write scope as verifiable statements

The test for a scope line: could a stranger read it and tell you, without asking a question, whether it is done? If not, rewrite it.

Use counts, not adjectives. "12 screens, 3 roles, 2 integrations, 1 payment flow" is a scope. "A full-featured admin panel" is a mood. Counts also give you an honest place to negotiate: cutting from 12 screens to 9 is a conversation both parties can have.

Include an exclusions section. It feels awkward to write and it saves the relationship. Ours usually names: no native mobile apps, no SSO or SAML, no multi-language, no accessibility audit beyond keyboard and contrast basics, no legacy data migration, no email template design, no load testing above 200 concurrent users.

And name suppliers with dates. Who provides the Stripe account, the DNS access, the logo files, the copy, and by when. Late credentials are the most common cause of a slipped milestone that had nothing to do with code.

markdown
## Milestone 3 — Booking and Payments (est. 9 working days)

**Scope**
- Booking flow: search, availability, hold, confirm (4 screens)
- Stripe Checkout, card only, single currency (GBP)
- Confirmation email via Postmark, 1 transactional template
- Admin: view, filter, and cancel bookings (2 screens)

**Acceptance criteria**
1. A guest can complete a booking end to end on mobile and desktop.
2. A double-booked slot is rejected with a clear error; verified by an
   automated concurrency test in the repo.
3. A successful payment writes a booking row and sends one email.
   A failed payment writes no booking row.
4. Cancelling in admin issues a Stripe refund and emails the guest.
5. Deployed to staging and demoed on a recorded call.

**Excluded:** refund policies beyond full refund, multi-currency,
Apple Pay, waitlists, group bookings, promo codes.

**Client supplies by Mar 4:** Stripe live keys, Postmark account,
booking terms copy, cancellation policy text.

**Payment:** 25% of contract on written acceptance of criteria 1-5.

Fixed, hourly, or hybrid

Each model moves the risk somewhere. Nobody removes it.

Fixed price optimizes for the buyer's budget certainty. The builder carries all estimation risk, so a competent builder prices in a 25 to 40 percent buffer. On a vague brief, fixed price is a fight scheduled for a later date: every ambiguity resolves in whichever direction costs money, and someone has to lose it.

Hourly optimizes for flexibility. The buyer carries the risk and needs visibility: weekly hour reports, a demo cadence, a not-to-exceed ceiling. It works well with clients who have shipped software before, badly with clients who have not.

Hybrid is what we use most. A paid discovery of one to two weeks, typically 8 to 12 percent of expected build cost, produces what makes a fixed price honest: a screen inventory, a data model, integration specifics confirmed against real API docs, and a milestone plan with acceptance criteria. The build is then fixed against that document. If discovery reveals the project is twice the size anyone thought, both sides learn it for a few thousand rather than for the full budget. Maintenance goes on a monthly retainer afterward, typically 10 to 20 percent of build cost annualized, covering dependency updates, monitoring, and a defined response window.

Change requests without the drama

Changes are normal. Unrecorded changes are what kills projects.

Keep a written change log in the repo. Quote every change in hours and in calendar days before work starts, because those numbers differ and clients care about the second one. The response to a mid-project request is never "no" and never a silent yes. It is "yes, and here is what moves."

yaml
- id: CR-011
  raised: 2026-03-09
  by: Priya (client)
  request: Add CSV import for existing customer list
  estimate_hours: [10, 14]
  calendar_impact: +3 working days on Milestone 4
  cost: fixed-price addendum, £1,150
  alternative: manual import by us at go-live, 2 hours, no schedule impact
  decision: approved 2026-03-10, alternative declined

Bake in a small change budget, say 8 hours a month, for trivial requests. Copy tweaks, a color, an extra table column. Nobody wants a signed addendum to change a button label, and the goodwill is worth more than the hours.

Estimation you can improve

Estimate at the task level, not the feature level. "Checkout" is a guess. "Cart persistence, Stripe session creation, webhook handler, idempotency, failure states, receipt email, admin refund" is seven estimates whose errors partly cancel.

Use ranges, always, and add two line items people habitually omit: integration time and review time. Then track estimate against actual on every task. Two projects of that data and your numbers start being useful rather than aspirational.

The honest multiplier for a third-party API you have never used personally is 2x to 3x. Not because the API is bad, but because you will meet its sandbox limits, its webhook retry semantics, and its account verification delay for the first time on this project.

What to cut when the deadline is real

In order:

  1. Internal admin tooling. Do it with SQL or a scripted task for now.
  2. Breadth of edge cases. Make the core path excellent and handle the rare paths with a clear error.
  3. Custom before configured. Use the hosted checkout, the off-the-shelf CMS, the library component.
  4. Reporting and analytics dashboards. Export the data, chart it later.
  5. Anything that is not payments correctness, auth correctness, or data integrity. Those three are never on the cut list.

Red flags, both directions

Buyers should walk when: there is no written scope, an estimate arrives 20 minutes after a two-page brief, no staging environment appears in the plan, no named person owns the work, or the builder will not put exclusions in writing.

Builders should walk when: no decision maker is in the room and approvals route through someone unnamed, the brief is "just like Airbnb but simpler," payment terms have no deposit, or the deadline comes from a marketing date with zero slack and no scope flexibility to protect it.

How we work

We quote discovery separately, and we do not give fixed prices on briefs we have not decomposed. Milestones carry acceptance criteria written before work begins, exclusions live in the same document, and change requests get logged with hours and dates attached. It makes the first conversation longer and every conversation after it shorter. Clients who have been burned before recognize the format immediately. The ones who have not usually notice around week four, when the thing they approved is the thing that shows up on staging.

A. Meer · Principal engineer

Part of the NorthStackHub delivery team. Writes here when a client build turns up a decision worth documenting — usually after the second time we have had to explain it on a call.

Meet the team

Facing the same problem?

We scope this kind of work every week. Describe what you are building and we will send back an approach, a timeline and a number — no charge for the thinking.

Replies within 4 business hours · No obligation · You keep the scope document