AI Competitor Analyst
A program crawls competitors' websites and puts their prices, timelines and promises into one table. In one niche, monthly prices on the 29 sites that opened varied tenfold: 15,000 to 150,000 RUB (about $175–1,750).
Published Aug 25, 2026 · figures checked Sep 1, 2026
How to analyze competitors with AI: eight steps
- Niche and city. Name them precisely: "website promotion, Moscow". This one line shapes the whole list.
- Company list. Collect every company the search turns up, not just the three best-known names. Our run found 76 companies.
- Manual cleanup. Strike out aggregators, directories and companies from other niches. 30 of the 76 remained. This is the only manual step.
- What to compare. Write down the attributes before collecting anything: price, timeline, request form, calculator, promises.
- Page collection. Take the home page and several inner pages, starting with prices and plans, or you will collect nothing but menus.
- A quote is required. Ask for answers with a quote only: "quote the place where the page states the price". No quote, no answer.
- Quote check. Verify that the quote is not empty, that it contains an amount or a timeline, and that these numbers actually appear on the page.
- One table. Put everything into one table and look at the spread. In our run, prices differed tenfold: from 15,000 to 150,000 RUB (about $175–1,750).
Which setup fits which task
- One-off niche review: the free limits and one evening are enough.
- Price monitoring: you need a fixed list of URLs and a schedule, or the data goes stale within a month.
- A niche without websites: if competitors live on social media and marketplaces, this method does not fit.
Below is a live run on 30 websites: what it showed and what it cost.
Where the project is now
The service is built, has run on live data and left verifiable artifacts behind. The code is two files: run.py (835 lines) does the measurement, and dashboard.py (588 lines) builds a niche map on top of it without downloading the pages again.
The production run took place on August 21, 2026, in the niche "website promotion, Moscow": 30 sites on the list, 175 Firecrawl credits, about 45 minutes. The duration is reconstructed from the timestamps of the raw files, since the log has none. The same evening, at 18:23, the dashboard was built from the texts already downloaded, for zero Firecrawl credits and 29 extra model calls.
Still to do: the run on the niche named on the service card (legal services, a sample of 50). Two items remain open. One is a beta run by a newcomer who works from the files alone, without the author's help. The other is a mismatch between documentation and code: the instructions tell a person to set up a key for Yandex Cloud, Yandex's cloud platform, while the working script calls OpenRouter.
What was needed
The goal: see what the whole niche tells a client, not just the three best-known competitors. Contractors price this work per competitor. Demis Group, a Russian marketing agency, publishes a price list of 26,000 RUB for three competitors, 53,000 RUB for five and 72,000 RUB for seven (about $300, $620 and $840). Checking fifty sites by eye at ten minutes each takes a full working day without a break.
The constraint that shaped the whole design: a model confirms what it was asked about, not what is on the page. Asked whether a page answers the client, it agrees out of politeness almost everywhere, and the measurement ends up measuring its agreeableness. The literature calls this sycophancy (Sharma et al., 2023).
Hence one rule for its answers: no "yes" without a verbatim quote, and no quote without a number the code has found in the page text. In the August 21, 2026 run, 20 of 29 sites passed these checks, and for all twenty the quote sits in its own column of the table, ready to be opened and checked by hand.
| Method | What we took from it | Canonical name · source |
|---|---|---|
| Measure before explaining | the sample size and the client's question are declared before the first command. A sample chosen after the results is no longer a measurement | Preregistration of sample and questionNosek et al., PNAS, 2018 |
| Acceptance by thresholds | three outcomes, set by the number of sites that opened, are named before the start: 40 or more allows percentages, 25–39 allows absolute numbers only, below 25 means plan B | Preregistered criteria; small-sample ruleNosek et al., PNAS, 2018 |
| Exact match instead of trust | a model's "yes" stands only if the numbers from its quote are found in the page text. Digits are compared, not wording | Quote verification by number (faithfulness)Es et al., "RAGAS", 2023 |
| Split by verifiability | the model judges where judgment is needed; price, form and calculator are found by code from a dictionary, a check a person can repeat in a second | Dictionary-based content analysis with a codebookKrippendorff, "Content Analysis", 2004 |
| Loud failure instead of silent | every check has three states: yes, no, not checked. An empty cell is not a "no", and a site that did not open counts in neither the numerator nor the denominator | Three-valued logic: yes, no, not checkedCodd, ACM TODS, 1979 |
| Bounded agent loop | the contractor-type label comes from a closed list of three values; the code discards any other value | Closed category vocabulary (codebook)Krippendorff, "Content Analysis", 2004 |
| One owner per dataset | the output is two files: audit.csv with 13 columns, and meta.json, the run passport: niche, date, method, sample size, spending | Data passport (datasheet)Gebru et al., CACM, 2021 |
How it is built
The pipeline is linear and calls a paid service exactly twice: for company search and for site crawling. Everything else is our own code in one file, with requests as the only dependency.
Search returns 76 companies for 36 credits. Then comes the only manual step: a person strikes out aggregators, duplicates and off-niche companies by eye, and 76 becomes 30. Each site is opened in a real browser: the home page plus up to five inner pages, with links to prices, plans and price lists taken first; otherwise the top menu eats all five slots. In parallel, a free probe with a plain HTTP request records the status code and the load time in milliseconds.
The text goes to the model twice: "does the page answer the client's question", with a mandatory quote, and "what type of contractor is this", with a label from three values. Three code checks stand between the model's answer and a table row: the quote is not empty → the quote contains an amount or a timeline → the numbers from the quote are found on the page. Price, request form and calculator are detected by code from a dictionary, without the model.
All downloaded texts go into raw/: 155 pages, 52.2 MB in 58 files. So the dashboard, with its map of 24 attributes and the price distribution, is built from saved texts and spends no credits, and recalculating after a change to a check costs nothing.
A code check always stands between the model's answer and a table row: a "yes" without a number found on the page itself never reaches the table.
What holds the design together
Six rules, each stated against the alternative it rejects. In three of them the code does not trust the model; in the other three it does not trust itself.
All six can be checked against the run's artifacts in a minute: the quote column opens next to the site, the denominator is in the run passport, and the three check states are visible in the table itself.
Decisions and their grounds
Eight decisions, each backed by a measurement or a hard limit of an external service. None was made for tidiness: each either removes a specific error or stays within an external service's limit.
The decision with the biggest consequences is the pause between requests. On its own it stretches the run to forty-five minutes, and it has its own row in the limits section.
| Decision | Grounds |
|---|---|
| Pages are opened by a rendering service, not a plain request | half of small-business sites render in the browser, and a plain request returns an empty shell. In the run this happened exactly once: one site of 29 returned text only when rendered and did not answer a direct request |
| A cap of 6 pages per site, pricing pages first | otherwise the top menu eats the five inner slots. The group order is fixed: prices, plans, price list → services → case studies and "about us" |
| No more than two pages from one section | without this, all five slots go to one subsection and the rest of the site stays unread |
| A 6.5-second pause between crawler calls | the free plan allows 10 requests per minute. The slowness is deliberate: it is the price of the free plan, not slow code |
| The contractor-type label comes from a closed list of three values | a free-form label cannot be counted: 29 sites would produce 29 wordings. The code silently discards any other value |
| Site texts are saved to raw/ and not downloaded again | recalculating after a change to a check costs zero credits. In the August 21 run, three sites came from the cache at 0 credits: 17 pages downloaded earlier |
| The dashboard is built from saved texts and does not download pages again | the map of 24 attributes and the price distribution cost 0 Firecrawl credits. The trade-off: 29 model calls that are missing from the run passport |
| The estimate is printed before the start, and spending is capped | 30 sites × up to 6 pages = up to 180 credits. The run used a cap of 220 against a default of 400; the cap was set by hand, and the run files do not record why it was 220. 139 were spent, 81 remained. The cap is checked before each site, not at the end |
What the design costs
The main cost is time. The 6.5-second pause between requests stretches a run of 30 sites to about 45 minutes. That figure is not measured: it is reconstructed from the timestamps of the raw files. A sample of 50 sites at the same speed would take an hour, and that is a calculation, not a second run. Only a paid plan speeds this up. Of the total, 155 downloaded pages at 6.5 seconds each add up to about 17 minutes of pure waiting (155 × 6.5 s). Page rendering takes most of the rest; the model and text parsing barely add to the duration.
The second cost is strict definitions. Requiring a number in the quote cuts off sites that answer the client in words: at least one of the nine "no" answers in the run was given at exactly this step, and the reason is recorded in the log. The cap of six pages means that a price hidden on page seven does not make it into the measurement. On average, 5.3 pages were read per site.
Separately, the run's artifacts contain three price counters that give different numbers. This is not an error: they are three different definitions, and here they are in full. 27 of 29 in the report means "mentions a price": the page contains a word from the dictionary (the Russian for "plans", "price list", "cost of services", "% of the amount") or a number with a ruble sign. 25 of 29 in the dashboard means "price as a number": a regular expression only, matching a number with ₽ or a Russian abbreviation for rubles anywhere in the saved text. 21 of 29 in the price distribution is the starting monthly price for promotion: the number was named by the model or by a verified quote, and the code found it on the page, within a range of 3,000 to 3,000,000 RUB (about $35–35,000).
The difference in one sentence: the first two counters answer "is there a figure with a ruble sign on the page", while the third answers "can this figure be turned into a monthly price". The arithmetic checks out. Of the 25 sites with a number, five do not yield a monthly price (the number is the price of another service or a figure from a case study). One site is added back: it says "from 100,000", but its ruble sign is a letter drawn by an icon font, so the regex missed it while the model read it. 25 − 5 + 1 = 21.
The third counter has two sources, and they overlap. The model named a starting price in 13 profiles of 29, the verified quote gave one for 18 sites, and 10 sites are in both. So profile only: 3 sites; profile and quote: 10; quote only: 8; 3 + 10 + 8 = 21.
This page gives almost no percentages, and that is a cost too: 29 sites opened, fewer than forty, and under the project's method a sample below forty is reported in absolute numbers. Where a ratio such as "×10" or "+20%" appears, it is calculated from the sites' own price lists, not as a share of the sample.
| Decision | What it limits |
|---|---|
| A 6.5-second pause between requests | a run of 30 sites takes about 45 minutes, judging by raw-file timestamps rather than a measurement; 50 sites at the same speed take over an hour, which is a calculation. Only a paid plan is faster: this is the free plan's limit of 10 requests per minute |
| A cap of 6 pages per site | a price on page seven does not make it into the measurement. 155 pages were read across 29 sites, 5.3 on average |
| The denominator counts only sites that opened | the figure measures availability to the crawler, not to a client. In the run, the only site that "did not open" was alive: the crawler got a timeout, while the direct probe opened the page in 1,402 ms |
| A "yes" requires a number in the quote | a site that answers the client in words, without an amount or a timeline, ends up as a "no". Of the nine "no" answers, at least one was given at exactly this step |
| Price, form and calculator are found by a dictionary | it catches word forms, not meaning. "Price as a number" sees any number with a ruble sign (25 sites of 29), while a monthly price can be built for only 21 |
| The contractor label has three values | "freelancer-studio" went to one site of 29. A finer picture requires expanding the list and recalculating the whole run |
| The model does not always name a price | it gave a starting price in 13 profiles of 29; eight more sites got a price from the verified quote. Total: 21 of 29, and eight sites have no price at all |
| A sample below 40 | absolute numbers only until the end of the stage. One site weighs 3.4 percentage points, and percentages would suggest a precision the measurement does not have |
What came out
The run on August 21, 2026: niche "website promotion, Moscow", 30 sites on the list. 29 opened, and 20 answered the client's question and backed it with a quote. Spending: 175 Firecrawl credits out of 1,000 free per month. The 139 for crawling are in the run passport; the 36 for search come from the service diagram and were added during review. Duration: about 45 minutes, and that is not a measurement. It is reconstructed from the raw files' timestamps, 16:18 → 17:03, because the log has no timestamps at all.
The niche broke down into 24 attributes, and the distribution is a result in itself. Case studies appear on 27 sites of 29, case studies with numbers on 20: the other seven have no result of the form "+N%" or "N times" on the page, which is how this attribute is defined. 7 of 29 promise guaranteed results, while 2 of 29 back that with money ("pay for results"), so the promise is three and a half times more common than the commitment. Not one of the 29 sites offers to work without prepayment: it is the only attribute on the map that never appeared.
Prices could be extracted for 21 sites. The entry price is 15,000 RUB (about $175), the median 45,000 RUB (about $525), the top 150,000 RUB (about $1,750): a tenfold gap. The cheapest and the most expensive of the sites that named both a price and a timeline promise results in the same 3 months. The price differs tenfold; the promise is the same. The comparison rests on the eight sites that named both values, and it is a calculation from their own price lists, not a measurement of outcomes.
Full-service work costs 20% more than plain SEO: a median of 48,000 RUB (about $560) against 40,000 RUB (about $470) for SEO-only contractors, with 10 priced sites in the first group and 11 in the second. This is a ratio of two medians, not a share of the sample.
- Sample
- One niche, one run: 30 sites on the list, 29 opened, 21 with a starting price. Search returned 76 companies; the only manual step, removing aggregators and duplicates by eye, brought them down to 30.
- Spread
- The sample is below forty, so this page gives no percentages: one site weighs 1/29 ≈ 3.4 percentage points, and percentages would suggest a precision the measurement does not have. Where a ratio like "×10" appears, it is calculated from the sites' own price lists.
- Checks
- Three code checks stand between the model's answer and a table row: the quote is not empty → the quote contains an amount or a timeline → the numbers from the quote are found on the page. Nine of the twenty-nine "yes" answers were overturned at these checks. Agreement between the model and a human on a subsample was not measured.
- Does not generalize
- The numbers apply to the niche "website promotion, Moscow" as of August 21, 2026, and to what the crawler sees on six pages per site. A run on the niche named on the service card has not been done yet.
- Not measured
- Precision and recall of the attribute dictionary against manual labeling: the case of the ruble sign from an icon font shows that the dictionary makes errors, but their share is not counted. The run duration is reconstructed from file times, not measured.
It passed a production run on August 21, 2026, on 30 sites in the niche and left verifiable artifacts: a 30-row table, the run passport, a dashboard and 52.2 MB of saved texts. The figures on this page can be recalculated from that archive; the two that cannot are named under "Pitfalls".
Kaufman Lab is an AI architecture lab. We design processes and methodologies. Code goes out of date with every new generation of models, but methodology does not, so methodology is what each project breaks down. Any current AI model can build a system from this design.
What went wrong
Ten failures, all found while reviewing the run's own artifacts, not during the build. Eight of the ten concern accounting: the recorded spending, time, search coverage and run passport do not match what actually happened. The other two are about definitions: a figure is labeled as something other than what it measures.
The one with the biggest consequences is the run passport. It declares the method as "firecrawl search + scrape → yandexgpt-lite", while the code uses a different model and a different provider. The file itself was rewritten on August 25, four days after the run, whereas the table and the log were written on August 21 at 17:03:58. A passport rewritten after the fact stops being a passport.
Credits in the run passportthe search step writes its cost to the passport
Model calls in the run totalthe dashboard records its own spending
What else can be added to the code
All downloaded texts live in raw/, and the dashboard is built from them without new credits, so a new attribute or a new report is one more pass over the archive, not a new crawl of the niche. Below is what can be added next, including paid services.
What people usually ask
Ten questions people ask most often about this measurement. The first one defines the subject and is written to stand on its own when quoted out of context.
Every answer contains a number from the August 21, 2026 run or a published market price.
What is an AI competitor analyst?
An AI competitor analyst is a measurement in which a program, not a person with a notepad, crawls the websites of an entire niche. It is for business owners and marketers who need the whole market, not three well-known names. The program finds the sites, reads each one in a real browser and puts price, timeline and promises into a table. Kaufman Lab builds it for the client's niche: one run covers 30 sites. It does not rate the sites and does not give advice.
In competitor analysis, what does the model decide and what does the code decide?
The model answers one question, whether the page answers the client's main question, and must back a "yes" with a verbatim quote. Its second call assigns a contractor-type label from a closed list of three values; the code discards any other value. Price, request form, calculator and the 24 niche attributes come from text search without the model: a person can repeat such a check in a second, but not a model's decision. Of the thirteen table columns, the model fills three.
How do you check that a site actually answered the client's question?
With three code checks in a row, before anything is written to the table. The quote is not empty. The quote contains an amount or a timeline; otherwise the "yes" is overturned and the reason goes to the log. The numbers from the quote are found in the page text, and it is digits that are compared, not wording: a price on a site lives in a table, the model retells it as a sentence, and a literal match would never work. In the August 21, 2026 run, 20 of 29 sites passed all three checks, and each has its quote in a separate column.
Why is a site that did not open not counted as bad?
Nothing is known about it, and the denominator of all shares counts only the sites that opened: 29, not 30. In the August 21, 2026 run, the only site that "did not open" was in fact alive: the crawler returned a timeout, while a free direct probe from the same script got the page in 1,402 ms. That is why the figure is called "available to the crawler", not "site is down", and both columns sit side by side in the table.
Why does a run on thirty sites take about forty-five minutes?
Because of the 6.5-second pause between crawler calls: the free plan allows ten requests per minute. The run downloaded 155 pages, and waiting alone takes about 17 minutes. That is a calculation, 155 × 6.5 seconds, not a separate measurement; the rest goes to rendering the pages, while the model and text parsing barely add to the time. The 45 minutes are also reconstructed rather than measured, from the raw files' timestamps (16:18 → 17:03), because the run log has no timestamps. Only a paid plan makes it faster. The dashboard works from the texts already downloaded and does not download pages again.
How much does one run on a niche cost?
The August 21, 2026 run on 30 sites used 175 Firecrawl credits: 36 for company search and 139 for crawling. The free plan gives 1,000 credits a month and needs no card; the model in the current build runs on OpenRouter and adds no spending. On the market, the same work done by hand costs 26,000 RUB for three competitors, 53,000 RUB for five and 72,000 RUB for seven (about $300, $620 and $840), according to Demis Group's published price list. The code has no money figure for the run itself: it counts credits and calls.
What if only a few sites in the sample open?
The outcomes are declared before the start, not chosen after the result. Forty or more: percentages can be reported. From 25 to 39: the work goes on, but until the end of the stage only absolute numbers are used, since one site in a sample of 29 weighs 3.4 percentage points and "68%" becomes "71%" although nothing has changed. Fewer than 25: the fact that the niche is closed becomes the headline, and no percentages are published for the client question.
How do you analyze competitors' prices from their websites?
The program crawls the niche's sites in a real browser, the home page plus up to five inner pages, with links to prices and price lists taken first. Only the starting monthly price, found as a number on the page itself and falling between 3,000 and 3,000,000 RUB (about $35–35,000), goes into the price chart. In the August 21, 2026 run on the niche "website promotion, Moscow", this method produced a price for 21 of the 29 sites that opened: an entry price of 15,000 RUB (about $175), a median of 45,000 RUB (about $525), a top of 150,000 RUB (about $1,750), a tenfold gap. The numbers apply to one niche and one run.
How do you analyze the competitors of an entire niche?
Search collects the niche's companies; then comes the only manual step, where a person strikes out aggregators, duplicates and off-niche companies, and after that each site is read with the same set of checks. The method is ten steps from an empty folder to a project card. The funnel of the August 21, 2026 run: search returned 76 companies, 30 remained after cleanup, 29 opened. The model's answer to the client's main question is accepted only with a verbatim quote: the three checks overturned nine answers out of twenty-nine, and 20 passed.
What does a competitor analysis table look like?
It is a table with 13 columns and 30 rows: one row per company, with columns for price, timeline, promises, request form, calculator, availability and the verbatim quote. The model fills three of the thirteen columns; price, request form and calculator are found by code from a dictionary. A niche map of 24 attributes is built on top of the saved texts: in the August 21, 2026 run, 27 of 29 sites show case studies, 7 promise guaranteed results, and 2 offer pay for results.
- Nosek B. A., Ebersole C. R., DeHaven A. C., Mellor D. T. The preregistration revolution. PNAS, 115(11), 2018. doi:10.1073/pnas.1708274114
- Sharma M. et al. Towards Understanding Sycophancy in Language Models. 2023. arXiv:2310.13548
- Es S., James J., Espinosa-Anke L., Schockaert S. RAGAS: Automated Evaluation of Retrieval Augmented Generation. 2023. arXiv:2309.15217 — faithfulness: a claim can be inferred from the document.
- Krippendorff K. Content Analysis: An Introduction to Its Methodology. Sage, 2nd ed., 2004 — codebook, dictionary-based analysis.
- Codd E. F. Extending the Database Relational Model to Capture More Meaning. ACM Transactions on Database Systems, 4(4), 1979 — three-valued logic, missing values.
- Gebru T. et al. Datasheets for Datasets. Communications of the ACM, 64(12), 2021. doi:10.1145/3458723