BuiltWith Tech Stack Scraper – Structured Output · Apify
Website Tech-Stack Detector — Find Any Site's Technologies avatar

Website Tech-Stack Detector — Find Any Site's Technologies

Pricing

from $1.45 / 1,000 domain-results

Go to Apify Store
Website Tech-Stack Detector — Find Any Site's Technologies

Website Tech-Stack Detector — Find Any Site's Technologies

Detect technology stacks from target domain responses. Get technologies, confidence, evidence, normalized URLs and HTTP data. Run with domains or URLs; no external credentials. Pricing: $0.0015 per dataset item on Free; Actor Start: $0.0005 per event.

Pricing

from $1.45 / 1,000 domain-results

Rating

0.0

(0)

Developer

Vitalii Bondarev

Vitalii Bondarev

Maintained by Community

Actor stats

0

Bookmarked

37

Total users

12

Monthly active users

a day ago

Last modified

Features

Limited permissions

Share

BuiltWith Tech Stack Scraper

Scrape a domain's live web response for detected CMS, ecommerce, frameworks, analytics, CDN and payment technologies, with confidence and evidence. On the Free plan, each priced dataset item costs $0.0015 per domain result; a run handles at most 10,000 domains.

  • Extract ecommerce, CMS and marketing signals for lead generation and sales prospecting.
  • Compare competitor stacks across scheduled runs using timestamps and detected technologies.
  • Analyse technology distribution across an industry or company list.
  • Inspect confidence scores and the strongest matched signal for each detection.
  • Run without a buyer API key, external credentials or external proxy account.

What you get

The Actor fetches each listed domain live and returns normalized URLs, HTTP details, detected technologies, confidence values and evidence.

FieldTypeDescription
domainstringNormalized domain without www. or a protocol. Always set.
urlstringURL requested for the normalized domain. Always set.
final_urlstringFinal URL after redirects; null when no response was received.
status_codeintegerHTTP status code; null when no response was received.
techsarray of objectsDetected technologies, or [] when none are found or the row has an error. The ruleset has 168 entries, matched on headers, cookie names, meta generator, script URLs, inline JavaScript or HTML patterns.
techs[]objectContains name, tag, categories, link, confidence, evidence and version.
techs[].namestringDisplay name of the detected technology.
techs[].tagstringPrimary category tag.
techs[].categoriesarray of stringsCategory labels assigned to the technology.
techs[].linkstringReference URL in the form https://builtwith.com/<slug>.
techs[].confidencenumberDetection confidence.
techs[].evidencestringStrongest signal: header:<header name in lower case>, cookie:<cookie name, first 40 characters>, meta-generator:<generator text, first 40 characters>, script-src:<script URL, first 60 characters>, inline-js or html.
techs[].versionstringTechnology version, or null unless the winning pattern captures one.
tech_countintegerNumber of detected technologies; 0 when none are found.
categoriesarray of stringsUnion of category labels; [] when none are found.
parse_confidencenumberAverage confidence rounded to 3 decimals; 0.0 when none are found.
errorstringnull on a good row; otherwise fetch_failed: <detail>, access_challenge or unusable_response.
warningsarray of strings[] on a good row; otherwise ["fetch_failed"], ["access_challenge"], ["unusable_response"] or ["no_tech_detected"].
statusstringPresent only when no technologies are found: no_technologies_detected.
scraped_atISO 8601 stringUTC timestamp shared by every row in a run.

When the source provides no value, final_url, status_code, error and techs[].version are null, subject to the table exceptions. Header or meta-generator matches score 0.95; HTML-only matches score 0.72.

Sample output

The sample below is one real record from the dataset sample.

[
{
"domain": "github.com",
"url": "https://github.com/",
"final_url": "https://github.com/",
"status_code": 200,
"techs": [
{"name":"GitHub Pages","tag":"Hosting","categories":["Hosting","PaaS"],"link":"https://builtwith.com/GitHub-Pages","confidence":0.95,"evidence":"header:server","version":null},
{"name":"Contentful","tag":"CMS","categories":["CMS","Headless CMS"],"link":"https://builtwith.com/Contentful","confidence":0.72,"evidence":"html","version":null}
],
"tech_count": 2,
"categories": ["Hosting","PaaS","CMS","Headless CMS"],
"error": null,
"parse_confidence": 0.835,
"warnings": [],
"scraped_at": "2026-10-29T11:18:17.331912+00:00"
}
]

Pricing

Billing is pay per event. apify-actor-start costs $0.0005 per event on the Free plan and is charged when the Actor starts. apify-default-dataset-item costs $0.0015 per event on the Free plan and represents one result with all fields. A result is chargeable when it has no error and at least one detected technology; failed or no-technology rows remain visible without a result charge.

The domain-result event has no price, so you are not charged for it. The apify-actor-start event is charged once per GB of run memory, with a minimum of one event; a run with more than 1 GB starts more events. A one-result run shows the exact count under charged events.

Example: 1,000 priced dataset items and one minimum apify-actor-start event cost $1.5005 on the Free plan. For 10,000 priced dataset items and one minimum apify-actor-start event, the cost is $15.0005 on the Free plan.

The Apify Free plan includes $5 of monthly platform usage credit. With exactly one start event, the Free-plan $5 credit covers 3,333 priced dataset items, calculated as floor((5 - 0.0005) / 0.0015).

You pay only for the events listed below. This Actor does not use Pay per event + usage, so compute, proxy traffic and storage are not billed separately.

Planapify-actor-startapify-default-dataset-item
Free$0.0005 per event$0.0015 per event

How to use

  1. Prepare bare domains or full URLs, such as shopify.com or https://www.example.com/path.
  2. Configure maxItems to cap processing, or leave it at 0 for no input cap.
  3. Keep the default Apify residential proxy configuration, or provide an accepted Apify proxy configuration.
  4. Run the Actor with this input:
{
"startDomains": ["shopify.com", "https://www.example.com/path", "stripe.com"],
"maxItems": 0,
"proxyConfiguration": {
"useApifyProxy": true,
"apifyProxyGroups": ["RESIDENTIAL"]
}
}
  1. Inspect techs for names, categories, links, confidence and evidence.
  2. Filter by techs, categories, status_code or parse_confidence, then export JSON or CSV.
  3. Repeat runs through Apify Schedules; weekly is a starting point for competitor-stack monitoring.

Integration: read the results through the Apify dataset API.

Input parameters

ParameterWhat it doesDefault
startDomainsRequired domains or URLs. Inputs are normalized, duplicates removed, and rows containing spaces or commas split into domains.Required
maxItemsCaps listed domains to process. 0 means no cap and cannot create domains.0
proxyConfigurationProxy configuration used to reach target sites.Apify RESIDENTIAL
disableUsageStatsSet to true to turn off the run summary in Usage statistics.false

Limits and edge cases

ConditionWhat you seeWhat to do
More than 10,000 domainsProcessing stops at 10,000; remaining domains are noted as unprocessed.Run the remainder separately.
A domain appears more than onceDuplicate normalized domains are removed.Supply distinct domains for separate tracking.
A row contains spaces or commasEach piece becomes a domain.Use separate pieces for separate entries.
Entry has no dot or host, such as localhostIt is skipped. Up to 50 entries, each cut at 100 characters, appear as invalid_inputs in OUTPUT; the terminal message names the first 10.Provide a domain such as example.com or a full URL.
Empty or whitespace-only rowIgnored silently.Provide a valid domain or URL.
No valid entryRun ends Failed with error: "no_valid_domains" in OUTPUT; nothing is read or charged.Provide at least one valid domain.
Input list is emptyRun ends Failed with error: "no_domains" in OUTPUT.Provide startDomains.
maxItems is below the valid-domain countOnly the capped number is processed; remaining entries are noted.Increase maxItems or split the list.
Every domain is fetchedEach is fetched directly first.Residential retry occurs for status 401, 403, 407, 429, 451, 503 or 500+, a block page, or no technologies with a non-200 status or body under 5,000 characters.
Response is unusable, blocked or unreachableRow contains fetch_failed, access_challenge or unusable_response; failed rows are pushed without a result charge.Check the domain and proxy configuration, then retry later.
Page returns no technologiesA 200 response with a body of at least 5,000 characters and no technologies gets empty techs, tech_count 0 and no_technologies_detected; no result charge applies.Review the URL and rerun if the site changed.
Short or non-200 response has no technologiesRow becomes unusable_response or access_challenge.Check the domain and retry later.
Apify proxy is unavailable or setup failsRun ends Failed before reading domains; OUTPUT has proxy_setup_failed or no_proxy; nothing is charged.Enable Apify Proxy and check proxyConfiguration.
Cost guard stops the runAfter residential proxy bytes or compute make continuation uneconomic, a partial run can end Succeeded with Partial result. OUTPUT has stopped_early: true, stoppedEarly: "MARGIN_GUARD", reason, domain_rows_delivered, domains_not_processed as a count, and message; a MARGIN_GUARD record has cost figures. With no delivered row, it ends Failed with nothing charged and the same stoppedEarly value.Compare domain with the input; rerun unprocessed domains.
Rows are processedRows are pushed in groups of 20 domains plus a final group; pushed rows are charged at push time.Use existing dataset rows as the delivered portion.
Run aborts, times out or fails mid-runUp to 19 processed but unpushed domains are lost and not charged. No resume progress is saved; only OUTPUT and MARGIN_GUARD are written.Rerun the missing domains.
No row is delivered and a lookup failsRun ends Failed with stoppedEarly: "ALL_LOOKUPS_FAILED" in OUTPUT; the dataset lists each domain with its error or status.Retry later and review errors.
No failures but every row has no technologyRun ends Succeeded with 0 delivered rows and nothing charged; OUTPUT contains message and domains_no_technologies.Review the domains and rerun if needed.
Ruleset does not recognize a technologyIt is absent from techs; the ruleset has 168 entries.Technologies outside the 168 entries are not reported.

FAQ

How much does it cost to scrape a website domain?

On the Free plan, a priced dataset item costs $0.0015 per event and the minimum apify-actor-start charge costs $0.0005 per event. 1,000 priced dataset items and one minimum start event cost $1.5005 on the Free plan.

What happens when a domain returns an empty result?

A 200 response with a body of at least 5,000 characters and no technologies is written with empty techs, tech_count 0 and no_technologies_detected. It is not charged as a result.

Why is a domain not working?

The target is fetched directly first. An unusable direct response can be retried over the Apify residential proxy; the dataset records an error marker and available status information, and failed rows are not charged.

The Actor reads the target domain’s public web response. Whether collection and use are allowed depends on the source’s terms and applicable law for your use case, so review those requirements before running it.

Usage statistics

This Actor creates a small, content-free summary at the end of each run, used only to monitor reliability and improve this Actor. No input values, credentials or scraped data are sent.

A copy of the exact record for your run is saved as USAGE_STATS in your own Apify key-value store.

To opt out, set disableUsageStats to true in the input. Nothing is sent then.

Full list of collected fields