The single biggest determinant of whether a web-agency proposal closes is not the design quality, the case studies, the price, or the founder’s LinkedIn presence. It is whether the agency walked into the first call already understanding the prospect’s stack — and proposed work that fits that stack.
This is not a soft observation. The data, from agency CRMs we have seen, is consistent: proposals that reference the prospect’s existing CMS and at least two other detected technologies close at roughly 38–48%. Proposals that don’t close at 12–18%. The 3x gap is not a function of agency quality. It is a function of preparation.
The reason this works is simple economics on the prospect’s side. A prospect on Webflow does not want to hear about a custom React rebuild — they want a Webflow agency. A prospect on Shopify Plus does not want a Magento migration — they want headless Shopify expertise. A prospect on WordPress with WooCommerce wants to know whether you can fix their checkout, not whether you can rebuild it on Next.js. Generic agency pitches force the prospect to do the translation work in their head; stack-specific pitches do that work for them.
The other reason this works is on the agency’s side. Knowing the stack pre-call lets you triage prospects into the right service tier before you waste 90 minutes on a discovery call. A WordPress prospect goes into the maintenance + Webflow-migration funnel; a Webflow prospect goes into the CMS-build funnel; a Shopify prospect goes into the headless-commerce funnel. Each funnel has different pricing, different scope, different sales cycle, and different close rate. Routing prospects correctly at the lead stage is the highest-leverage operational change a 5–50 person agency can make.
This post is the playbook for building a lead-qualifier pipeline that auto-classifies inbound prospects by their detected tech stack and routes them into the appropriate service tier. The reference implementation costs roughly $30–$80/month for a typical agency lead volume and replaces an analyst doing it manually at 30+ minutes per lead.
The “first-call alpha” problem
A typical agency discovery call goes like this. A prospect fills out a contact form. An AE schedules a 30-minute intro call. The first 10 minutes of the call are spent asking “so, tell me about your current site” — what platform, what tools, what hosting, what analytics. The middle 15 minutes are spent generically pitching agency services. The last 5 minutes are spent setting up a follow-up call with a “more technical person” because the AE could not answer specific questions.
Three things are wrong with this pattern:
- The first 10 minutes were unnecessary. The prospect’s stack is a public HTTPS request away. Asking them to summarize it is asking them to do free work that the agency could have done in 10 seconds.
- The middle 15 minutes were generic because the AE didn’t know the stack. They couldn’t propose specific work — only categorical work.
- The follow-up “more technical person” call signals that the AE doesn’t operate at the technical level of the prospect. This is the moment most prospects mentally downgrade the agency.
The fix is to know the stack before the call. The agencies that have implemented this consistently report two things: their average proposal value goes up (because the proposal references specific work on the prospect’s actual stack), and their close rate goes up (because the prospect feels the agency gets it).
The four stack-driven service tiers
Most digital agencies sell across multiple service tiers. The tiers map cleanly to detected stacks:
| Detected stack | Most-fit service | Typical deal size | Sales cycle | |—|—|—|—| | WordPress + WooCommerce | Maintenance retainer + headless rebuild upsell | $3-12k/month retainer, $40-120k rebuild | 4-8 weeks | | Webflow + Memberstack | CMS extension + design refresh | $15-50k project | 2-4 weeks | | Shopify (basic) | Theme work + app integration | $10-30k project | 2-3 weeks | | Shopify Plus + headless | Headless rebuild + ongoing eng retainer | $80-300k project + retainer | 8-16 weeks | | Custom React/Next.js + headless CMS | Eng staff aug + design system | $20-60k/month retainer | 6-12 weeks | | Squarespace / Wix | Migration to Webflow or WordPress | $8-25k project | 2-6 weeks | | Magento / BigCommerce | Replatform to Shopify Plus | $60-200k project | 12-20 weeks | | Drupal | Maintenance retainer or replatform | $4-15k/month retainer | 8-16 weeks |
Each tier has different scope, different pricing, different team allocation, and a different qualification path. An inbound that turns out to be on Squarespace looking for a basic refresh should not consume the same sales cycle as an inbound on Shopify Plus considering a headless rebuild.
The tier classification is purely a function of the detected stack, plus a few firmographic signals (employee count, funding stage). The classification can run in 30 seconds, automatically, the moment a prospect submits a contact form.
Architecture
Prospect submits contact form
|
v
Web hook fires --> agency lead-qualifier service
|
v
Detect tech stack of submitted domain ---> wappalyzer-replacement actor
|
v
Apply tier-classification rules
|
v
Route lead into appropriate CRM pipeline
|
v
Auto-generate "first call brief" PDF for the AE
|
v
Notify the right AE (junior for low tier, senior for top tier)
The whole pipeline is a small web service — Flask or Express, hosted on Fly.io or Render — plus the actor for detection.
Implementation
Step 1: The web hook
Whatever your contact form runs on (Typeform, HubSpot Forms, Formspree, custom), fire a web hook to your qualifier service when a submission comes in.
from flask import Flask, request
import os
from apify_client import ApifyClient
app = Flask(__name__)
client = ApifyClient(os.environ["APIFY_TOKEN"])
@app.post("/webhook/new-lead")
def new_lead():
payload = request.json
company_domain = payload["fields"]["company_website"]
contact_email = payload["fields"]["email"]
contact_name = payload["fields"]["name"]
monthly_revenue_band = payload["fields"].get("monthly_revenue_band")
stack = detect_stack(company_domain)
tier = classify_tier(stack, monthly_revenue_band)
crm_lead_id = create_crm_lead(payload, stack, tier)
brief = generate_brief(payload, stack, tier)
notify_assigned_ae(tier, crm_lead_id, brief)
return {"status": "ok", "tier": tier}
Step 2: Detect stack
def detect_stack(domain: str) -> list[dict]:
domain = domain.replace("https://", "").replace("http://", "").rstrip("/")
run = client.actor("nexgendata/wappalyzer-replacement").call(
run_input={"urls": [f"https://{domain}"], "render_js": True}
)
items = list(client.dataset(run["defaultDatasetId"]).iterate_items())
return items[0]["technologies"] if items else []
For a single-URL detection the actor returns in 5–15 seconds, well within the latency budget of a synchronous web hook handler.
Step 3: Tier classification
The classification rules are agency-specific. Here is a representative ruleset for a digital agency that does CMS, ecommerce, and bespoke engineering work.
def classify_tier(stack: list[dict], monthly_revenue_band: str = None) -> str:
tech_names = {t["name"] for t in stack}
# Top tier: enterprise ecommerce
if "Shopify Plus" in tech_names or "Magento" in tech_names:
return "tier_1_enterprise_ecommerce"
# Top tier: bespoke modern stack
if any(fw in tech_names for fw in ["Next.js", "Remix", "Nuxt"]) and \
any(cms in tech_names for cms in ["Sanity", "Contentful", "DatoCMS", "Storyblok"]):
return "tier_1_headless_modern"
# Mid tier: standard ecommerce
if "Shopify" in tech_names:
return "tier_2_standard_shopify"
# Mid tier: WordPress with commerce
if "WordPress" in tech_names and "WooCommerce" in tech_names:
return "tier_2_wordpress_commerce"
# Mid tier: Webflow professional
if "Webflow" in tech_names:
return "tier_2_webflow_pro"
# Lower tier: standard WordPress
if "WordPress" in tech_names:
return "tier_3_wordpress_standard"
# Migration tier: legacy or limited platforms
if any(t in tech_names for t in ["Squarespace", "Wix", "Drupal", "Joomla"]):
return "tier_3_migration_candidate"
# Default: needs human triage
return "tier_4_needs_triage"
A few points worth calling out:
Tier 1 maps to the senior AE and the longest sales cycle. A Shopify Plus prospect deserves a 90-minute discovery call with the agency’s most technical AE, plus a customized proposal. Routing them to the junior AE who handles WordPress retainers is a common and expensive mistake.
The “needs triage” tier is real and important. If the prospect’s site uses a stack you don’t recognize (custom CMS, unusual framework, opaque proxy), don’t auto-route. A human should look at it. Some of these turn into the best deals (a custom React app means an in-house eng team that needs an agency for a specific gap), but the auto-classifier shouldn’t guess.
Add firmographic signals. Tech stack alone is incomplete. A 3-person agency on Shopify is a different deal from a 300-person brand on Shopify. Layer in employee count or estimated revenue from a Clearbit / Apollo enrichment if you have it. The simplest version is a manual monthly_revenue_band field on the contact form (“Under $100k”, “$100k-$1M”, “$1M-$10M”, “$10M+”).
Step 4: Generate the first-call brief
This is where the pipeline pays for itself. Before the discovery call, the AE gets a one-page brief auto-generated from the detected stack. The brief contains:
- Detected CMS, ecommerce, analytics, marketing, hosting, and CDN
- Tier classification and recommended service line
- Three suggested talking points based on the stack
- A pre-written first-call opener referencing the stack
def generate_brief(payload: dict, stack: list[dict], tier: str) -> str:
by_category = {}
for t in stack:
for cat in t.get("categories", []):
by_category.setdefault(cat, []).append(t["name"])
cms = ", ".join(by_category.get("CMS", []) or by_category.get("Ecommerce", []) or ["unknown"])
analytics = ", ".join(by_category.get("Analytics", []) or ["none detected"])
hosting = ", ".join(by_category.get("PaaS", []) + by_category.get("CDN", []) or ["unknown"])
brief = f"""
LEAD BRIEF — {payload['fields']['company_website']}
Tier: {tier}
Recommended service: {SERVICE_RECOMMENDATIONS[tier]}
Detected stack:
CMS / commerce: {cms}
Analytics: {analytics}
Hosting / CDN: {hosting}
Suggested first-call opener:
"Quick context before we dive in — I had a look at {payload['fields']['company_website']}
this morning. Saw you're running {cms} with {analytics}. Most agencies our size that
work on {cms} sites typically focus on {TIER_FOCUS[tier]}. Want to start there or
do you want to walk me through what brought you in?"
Talking points:
{generate_talking_points(stack, tier)}
"""
return brief
A senior AE who walks into a discovery call with this brief in hand is operating at a different level than one who is asking “so, tell me about your current site.” The brief itself is impressive to the prospect when shared at the start of the call (“we did a quick technical look this morning, here’s what we noticed”) — it signals competence before the agency has said anything substantive.
Step 5: Route to the right AE
Tier-based routing is straightforward:
def notify_assigned_ae(tier: str, crm_lead_id: str, brief: str):
ae_email = AE_BY_TIER[tier]
send_email(
to=ae_email,
subject=f"New lead — {tier}",
body=f"CRM: https://crm.example.com/leads/{crm_lead_id}\n\n{brief}",
)
The senior AE’s calendar is too valuable to spend on every inbound. The pipeline ensures only Tier 1 and Tier 2 leads hit their inbox; Tier 3 routes to the junior AE; Tier 4 routes to the founder for human triage.
What the brief does for proposal quality
The brief is not just internal context. It seeds the proposal.
A typical generic proposal has sections like “Discovery & Strategy”, “Design & UX”, “Development”, “QA”, “Launch”, “Maintenance.” Each section is generic boilerplate the agency reuses across every proposal.
A stack-aware proposal has sections that name the prospect’s actual tools:
- “Shopify Plus theme architecture review and Liquid refactor”
- “Migration of existing Klaviyo flows to align with the new product taxonomy”
- “Replacement of the current Heap analytics implementation with a Segment-based event schema”
- “Headless storefront on Next.js with the existing Shopify Plus catalog as backend”
The second proposal closes more often because it proves the agency understands the prospect’s existing investments and is proposing surgery, not a rip-and-replace. It also justifies a higher price — surgery on a known stack is more skilled work than a generic “build us a website” engagement.
Handling agencies’ favorite edge cases
A few patterns specific to the agency-prospecting use case:
The prospect’s site is on a temporary holding page. A surprising number of inbound leads come from companies whose www.company.com is a single-page Squarespace placeholder while the real product is on app.company.com. Always run the detection against both, and key the classification off the more substantive of the two.
The prospect just migrated. If the stack looks brand new (e.g., a Webflow site that screams “we launched this last week”), the prospect is probably not in market for a redesign — they may be in market for ongoing eng support. Adjust the tier classification accordingly.
The prospect is on a stack the agency doesn’t service. If you’re a Shopify-only agency and the inbound is on Magento, the right action is a polite referral plus a “let us know if you ever migrate to Shopify” note. The lead-qualifier should flag these as “out of scope” rather than dropping them into the wrong tier.
The prospect is on a stack the agency loves. Tag inbounds whose stack matches the agency’s flagship case study. (“This prospect is on the same Shopify Plus + Klaviyo + Gorgias stack as $famous_brand_we_built_for; lead with the case study.”)
The prospect’s site detection fails. Anti-bot defenses, geo-blocks, or unusual hosting can defeat detection. The pipeline should fail open — if detection comes back empty, route the lead to the human-triage tier rather than misclassifying.
What this costs
For a typical agency volume of 100–500 inbound leads per month:
- Stack detection: 500 × $0.01 = $5/month
- Web service hosting: $5–15/month on Fly.io or Render
- Brief generation: negligible compute
- CRM integration: free if you already pay for HubSpot / Pipedrive / Copper
Total: roughly $10–20/month plus 1–2 days of engineering setup. Compare to the alternative of a full-time SDR doing manual qualification (~$60k/year burdened) or to BuiltWith Pro at $295/month flat.
For agencies routing leads into a more sophisticated CRM workflow, layer in additional enrichment with the lead-list-enricher actor for firmographic data. Total cost stays well under $100/month.
What changes for the agency
When this pipeline goes live, three things shift:
Average deal size. Agencies report 20–35% higher proposal values within the first quarter, because Tier 1 prospects are now consistently routed to senior AEs who propose senior-tier work. Previously these prospects sometimes ended up with junior AEs who proposed cheaper engagements.
Close rate. The biggest reported gain is on the proposal-to-close conversion, typically from 18–25% to 32–45%. The driver is the stack-aware proposal: prospects feel the agency gets it.
Sales cycle length. The intro call goes from “let me ask you 20 questions” to “let me confirm what we already see and then propose work.” Agencies report 1–2 weeks shaved off the typical sales cycle, mostly from skipping the technical-discovery follow-up call.
These are not theoretical. They are the consistent pattern from agencies who have implemented stack-driven lead routing. The pipeline is cheap, the ROI is fast, and the AE team starts looking smarter to prospects in week one.
Putting it together
The agency that walks into a discovery call already knowing the prospect’s CMS, analytics, ecommerce platform, and hosting closes more often than the agency that asks. The pipeline to do this for every inbound is small, cheap, and solidly within reach of any agency with an engineer willing to spend a few days on it.
If you want to skip the build, the wappalyzer-replacement actor handles the detection layer end to end. Wire it into your contact-form web hook with the 50 lines of Python above, add the tier-classification logic, and you have a production lead qualifier by the end of the week.
The agencies that built this two years ago using BuiltWith and a custom backend are now competing against agencies that built the same thing for $20/month using OSS-fingerprint actors. The technological gap has closed; the operational gap (whether you have implemented it) has widened.
NexGenData publishes 195+ actors for agency, freelancer, and consulting workflows. Pay-per-result, no contracts, no per-seat fees.
Related actors for the agency-prospecting pipeline:
- lead-list-enricher — firmographic enrichment to layer on top of stack detection: employee count, funding, industry, geography. Pairs with the qualifier to make tiering more accurate.
- contact-info-scraper — pulls email, phone, and team-member contact info from any company website. Useful for outbound to prospects who haven’t filled out a form yet.
- shopify-store-directory — for agencies that specialize in Shopify: pulls stores by country / category with estimated monthly revenue, perfect for outbound prospect lists.
Top comments (0)