Website Contact Page Finder: About, Pricing, Careers
Pricing
from $1.80 / 1,000 mapped websites
Website Contact Page Finder: About, Pricing, Careers
Contact page finder for a list of websites. Returns each site's contact, about, team, pricing, careers, blog, press, support, docs, privacy and terms page URLs, with confidence and how each was found. Public pages only, robots.txt obeyed, no emails or phones. Not affiliated with any website.
Pricing
from $1.80 / 1,000 mapped websites
Rating
0.0
(0)
Developer
Muhammet Mustafa Dincer
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Security
Limited permissionsShare

What is Website Contact Page Finder?
Website Contact Page Finder takes a list of domains and returns, for each one, the contact page and the other key pages: the about page, team, pricing, the careers page, blog, press, support, docs, privacy and terms. You get:
- one row per website (
recordType: "site") with eleven ready-to-use columns (contactUrl,aboutUrl,pricingUrl,careersUrland so on), one address per page type; - yes/no columns for a filter:
hasContactForm(a contact form is present; the fields are not read),hasPricing,hasCareersandhasDemoCta; - for every address, a confidence (
high,medium,low), a score from 0 to 100 and how it was found (homepage_nav,homepage_footer,sitemap,common_path), in thepagesfield, so you can trust the strong ones and review the weak ones; - an honest status for every website, so a site that forbids access, shows a bot challenge or does not exist is reported, not hidden, and costs nothing;
- a
RUN_SUMMARYrecord with counts per status and per page type.
It reads public pages only: the home page, robots.txt, the sitemap, the contact page when it needs to see whether a form is there, and, when something is still missing, a few common addresses such as /pricing. It obeys robots.txt, visits a site about once per second, never logs in, never reads an e-mail address, a phone number or a form field, and stops when a site shows a bot challenge. A run of 101 websites took 207 seconds on the platform.
Quick answer: when should you (or an AI agent) pick this Actor?
Pick this Actor when you have a list of company domains and need to know where things are on each site: the page to send a sales form to, whether that page has a form, the pricing page to monitor, the careers page to watch, and whether the site asks for a demo. It is the step between "I have a domain" and "I fetch that page", and the step before a paid enrichment such as Apollo: keep the rows where hasPricing and hasCareers are true. It is also for lead lists, competitor tracking, due diligence, vendor reviews and AI agents that need to land on the right page without crawling the whole site.
Pick something else when you want the contents of those pages. This Actor returns addresses, not text, e-mail addresses, phone numbers or social profiles: it deliberately never reads them. Use a contact-details scraper for those, or fetch the addresses this Actor gives you with a content extractor. Also note that a site whose menu is drawn by JavaScript after the page loads may expose few links to a plain request; the Actor then falls back to the sitemap and common addresses and labels the result honestly.
Defaults that work: send {"websites": ["linear.app", "vercel.com"]} and you get all eleven page types, one best address each, about 7 requests per site. To get only what you need, add "pageTypes": ["contact", "pricing", "careers"]. To see alternatives (for example a sales contact and a support contact), add "maxPagesPerType": 3.
At a glance
| Does | Finds contact, about, team, pricing, careers, blog, press, support, docs, privacy and terms page addresses for each domain, with a confidence score and the evidence. Adds hasContactForm, hasPricing, hasCareers and hasDemoCta |
| Input | websites (up to 1,000). Optional: pageTypes, maxPagesPerType, probeCommonPaths, maxRequestsPerSite, concurrency, requestDelayMs |
| Output | One site row per website in the dataset, plus RUN_SUMMARY in the key-value store |
| Needs | Nothing: no account on the target sites, no API key, no proxy |
| Speed | Measured on the platform: 3 websites in 9 s, 30 in 85 s, 101 in 207 s (default settings) |
| Pricing | Pay per event: $0.0025 per mapped website and $0.0002 per run on the Free plan. Websites without a key page, refusals and failures are free |
| Obeys | robots.txt (RFC 9309, including Crawl-delay), about one request per second per site, stops at bot challenges |
| Does not | Read e-mail addresses, phone numbers, form field values or personal data, submit a form, log in, solve CAPTCHAs, rotate addresses, bypass bot protection, or crawl a whole site |
Key terms used in this README
- Website: a domain such as
linear.app, or a link to its home page. Only the site is used, never the path you add.www.and the bare domain count as one website. - Page type: one of eleven kinds of page:
contact,about,team,pricing,careers,blog,press,support,docs,privacy,terms. - Key page: the best address the Actor found for a page type on that website.
- Confidence:
high(score 85 or more),medium(65 to 84) orlow(50 to 64). Candidates below 50 are dropped. - Score: 0 to 100, built from the address, the link text, where the link sits (menu or footer) and how many independent sources name the same address.
- Found via:
homepage_nav(link in the page's menu),homepage_footer(link in the footer),homepage_link(link elsewhere on the page),sitemap(an address in the site's sitemap),common_path(a guessed address that answered and was checked). - Verified:
truewhen the Actor opened a guessed address and its title or path confirmed the page type, so a "page not found" screen or the home page in disguise is not returned. - Mapped website: a website with at least one key page found (status
ok). It is the only thing charged. - hasContactForm:
truewhen a contact form was seen on the home page or the contact page,falsewhen those pages were read and none was there,nullwhen the contact page could not be opened. The Actor does not read the fields. - hasPricing / hasCareers:
truewhen that page was found,falsewhen you asked for it and the site was read but it was not found,nullwhen you did not ask for that type or the site was not read. - hasDemoCta:
truewhen a link or button asks for a demo (for example "Book a demo"),falsewhen the pages that were read have no such button,nullwhen the home page was not read. The demo address is not stored. - robots.txt: the file at the root of a site that tells automated visitors where they may go. This Actor reads it first and follows it.
What can you use it for?
Lead lists: where do I send this?
Take domains from a CRM, a directory or a map scrape and add the contact page and sales or support page to each. hasContactForm tells you the page has a form, without reading the fields. Sales teams and outreach tools can open the right page without hunting through menus. The Actor returns the address only. It never reads the e-mail addresses on the page, and you should not use it to build mailing lists.
Before Apollo, Clay or any paid enrichment
Keep a company only when hasPricing and hasCareers are both true. That is the check people run in n8n so a lead list does not spend Apollo credits on sites with no pricing page and no careers page. hasDemoCta is the same kind of yes/no for a "Book a demo" button. A null means the Actor did not look, not that the answer is no. The Clay and n8n section below is a copy-paste version of this filter.
Competitor monitoring
Collect the pricing, careers, blog and press addresses of fifty competitors once, then point a page-change monitor or a content extractor at them. Rerun the Actor every few months to catch redesigned sites.
Compliance and vendor reviews
Find the privacy policy and terms pages of every vendor in a list, so a reviewer, an archive job or a document-fetching agent has the exact addresses.
Hiring and market research
The careers field points at the company's own page or at the applicant tracking system it uses. When the careers link goes to Greenhouse, Lever, Ashby, Workable, Recruitee, Personio, Teamtailor, BambooHR, SmartRecruiters, Workday, Breezy, Jobvite or iCIMS, the Actor labels it with atsProvider, so you know which board to read next. For the jobs themselves, see the sibling Actor ATS Jobs Monitor (mmdincer/ats-jobs-monitor).
Feeding an LLM agent
Through MCP an agent can call the Actor with a domain and receive a flat row with the addresses it needs, instead of crawling or guessing. Because every row has the same keys and an explicit status, an agent can tell "the site has no pricing page" from "the site blocked us".
How does it work?
- Each entry is cleaned up into a website. Links lose their path,
www.duplicates are merged, and entries that are not public websites are refused with a reason: IP addresses,localhost, internal and private network names, non-standard ports, links with a password inside, and e-mail addresses (which are refused and not echoed back). - For every website the Actor first requests
robots.txtand reads it following RFC 9309: groups, the most specific rule wins,AllowbeatsDisallowon a tie,*and$patterns,Sitemaplines, andCrawl-delay. If the home page is not allowed, the site is reported asrobots_disallowedand nothing more is requested. - It reads the home page and collects its links. Each link is scored by its address (in several languages, such as
/kontakt,/precios,/a-propos), by its link text, and by where it sits: a menu link scores higher than a body link, and a footer link is a strong signal. - Only if some page types are still missing it reads the site's sitemap (from
robots.txtor the usual location) and picks out the page-like addresses. - Only if types are still missing and
probeCommonPathsis on it tries a few common addresses (/contact,/about,/pricing,/careers, ...). A guess is kept only if the page answers with a real page whose title or address names the type, not the home page, not a "not found" page and not a redirect to another site. Optional steps stop when the request budget per website is used up. - If a contact address was found and the home page did not already show a contact form, the Actor opens that contact page once, still inside the request budget and still only where
robots.txtallows. It looks for a form element or a known embedded form (a message box, a contact label, or a name-and-email form on the contact page). A search box, a newsletter signup, a login and a cookie banner do not count. Nothing inside the form is stored: no field names that hold a value, no placeholders, no addresses. If the home page already has a contact form, the contact page is not opened again.hasDemoCtais decided from the link and button labels already on the pages that were read ("Book a demo", or a path such as/request-a-demo). The demo address is not stored. - Redirects are followed one hop at a time, and every hop is checked against
robots.txt. A redirect to another site is refused, except for the home page itself (for exampleexample.comtowww.example.com). - Rows are written in the order of your input list, one row per website.
- If a site answers 403 or 429, or shows a bot challenge (a "checking your browser" page, a CAPTCHA, a Cloudflare or similar wall), the Actor stops for that site and marks it
bot_challengeorrefused. It does not retry, switch address or look for a way round. The same rule applies to the single contact-page request: a challenge there is not retried, pages already found are kept, andhasContactFormstaysnull.
Pages that are not in the home page's links, not in the sitemap and not at a common address are not found. That is by design: the Actor does not crawl.
How to find the key pages of a list of websites (step by step)
- Open the Actor and keep the prefilled websites, or paste your own domains, one per line.
- Leave Page types to find at all eleven, or keep only the ones you need to save requests.
- Click Start. A few websites finish in seconds; a hundred take about three and a half minutes.
- Open the Sites view of the dataset for the main columns, including
hasContactForm,hasPricing,hasCareersandhasDemoCta, or the Details view for confidence, score and evidence. Download JSON, CSV or Excel. - Check the
statuscolumn. Anything other thanokhas amessagethat says why.
Input
| Field | Type | Default | Meaning |
|---|---|---|---|
websites | array of strings | required | Up to 1,000. A domain such as example.com or a link to the home page. Only the site is used, never the path. www. and the bare domain are one website |
pageTypes | array | all eleven | Which types to look for: contact, about, team, pricing, careers, blog, press, support, docs, privacy, terms. Fewer types means fewer requests |
maxPagesPerType | integer 1 to 3 | 1 | Addresses returned per type, best first. The eleven *Url columns always hold the best one; the rest are in pages |
probeCommonPaths | boolean | true | When a type is still missing after the home page and the sitemap, try a few common addresses and keep only verified ones |
maxRequestsPerSite | integer 3 to 20 | 8 | Upper limit of requests for one website, robots.txt and redirects included. The home page and robots.txt always come first |
concurrency | integer 1 to 20 | 10 | Websites visited in parallel. Requests to one site are always one at a time and spaced apart |
requestDelayMs | integer 1000 to 10000 | 1000 | Minimum wait between two requests to one site. A longer Crawl-delay in robots.txt (up to 10 s) is used instead. A site asking for more than 10 s is skipped as crawl_delay_too_long |
The delay has a floor of 1000 ms on purpose. This Actor is built to be polite and cannot be set to hammer a site.
Output
One dataset, one kind of row (recordType: "site"), two views: Sites and Details.

Site rows
| Field | Meaning |
|---|---|
recordType | site |
input | The entry as you wrote it |
domain, website | Host name, and the home page address after redirects. Pages are listed relative to this site |
status | ok, no_pages_found, robots_disallowed, bot_challenge, refused, unreachable, http_error, crawl_delay_too_long, invalid_input or not_fetched. See below |
message | Why a website has a status other than ok, or a note such as "Stopped early" |
pagesFound | Number of distinct page types found |
contactUrl, aboutUrl, teamUrl, pricingUrl, careersUrl, blogUrl, pressUrl, supportUrl, docsUrl, privacyUrl, termsUrl | The best address for each type, or null |
hasContactForm | true, false or null. Presence of a contact form only. See the terms above |
hasPricing, hasCareers | true if that page was found, false if you asked for it and the site was read but it was missing, null if you did not ask or the site was not read |
hasDemoCta | true if a demo button or link was seen, false if the read pages had none, null if the home page was not read. The address is not included |
pages | Every address found (up to maxPagesPerType per type) with type, url, confidence, score, foundVia, evidence (all sources that named it), verified, anchorText (the link text, at most 80 characters) and atsProvider |
homepageTitle, language | The home page <title> and its declared language |
robotsTxt | found, missing or unavailable (the site refused or could not be reached) |
crawlDelaySeconds | The Crawl-delay the site asked for, if any |
sitemapRead | true if a sitemap was read |
requests | Requests made for this website, robots.txt included |
stoppedReason | Set when the Actor stopped early (a refusal, a challenge, the request budget) |
durationMs, scrapedAt | How long the website took, and when |
Statuses
status | Meaning | Charged |
|---|---|---|
ok | At least one key page found | Yes |
no_pages_found | The site was read and no key page was found (a one-page site, an app behind a login, a site drawn by JavaScript) | No |
robots_disallowed | robots.txt does not allow the Actor to read the home page | No |
bot_challenge | The site showed bot protection. The Actor stopped | No |
refused | HTTP 403 or 429 without a recognised challenge. The Actor stopped | No |
unreachable | No answer, a DNS failure, or a server that kept failing | No |
http_error | The home page answered with an error such as 404 | No |
crawl_delay_too_long | robots.txt asks for a Crawl-delay above 10 seconds | No |
invalid_input | The entry is not a public website, with the reason in message | No |
not_fetched | Not visited because the spending limit was reached | No |
If no website in a run could be read at all, the run ends as failed and says why. Otherwise it succeeds, and the statuses tell you what happened to each site.
Run summary
RUN_SUMMARY in the key-value store: websites requested and mapped, count per status, count per page type, requests made, how many sites forbade access in robots.txt, websites not visited because of the spending limit, duplicates removed, whether the run stopped at the limit, the settings used, and the first problems with their reasons.
How much does it cost?
The Actor uses pay-per-event pricing. On the Free plan:
| Event | Price | When it is charged |
|---|---|---|
| Actor Start | $0.0002 | Once per run |
| Mapped website | $0.0025 | Once per website with at least one key page found |
Websites that forbid access in robots.txt, refuse or challenge the request, cannot be reached, have no key page, are duplicates or invalid entries, or were not visited because of a spending limit are free. Paid plans get lower prices per website.
Measured examples, charged at Free-plan prices (platform runs on 2026-11-04):
| Run | Websites | Mapped | Requests | Run time | You pay |
|---|---|---|---|---|---|
The prefill: linear.app, vercel.com, gitlab.com | 3 | 3 | 21 | 9 s | $0.0077 |
| 30 well-known sites | 30 | 27 | 204 | 85 s | $0.0677 |
| 101 well-known sites, default settings | 101 | 94 | 702 | 207 s | $0.2352 |
In the 101-site run, 94 sites were mapped, 4 showed a bot challenge, 1 could not be reached, 1 had no key page and 1 asked for a Crawl-delay above 10 seconds. These are the only ones that were not charged. Across the 94 mapped sites the Actor found on average 8.2 of the 11 page types: docs on 89, blog on 86, about on 78, privacy on 78, support on 76, contact on 73, pricing on 69, careers on 68, terms on 68, press on 56 and team on 34. Of the 775 addresses returned, 577 were high confidence, 126 medium and 72 low.
To cap spending, lower the number of websites, or set a maximum cost per run in the Apify run options: the Actor stops cleanly when the limit is reached and marks the remaining websites not_fetched.
Unit price against SiteEnrich
SiteEnrich is a website-enrichment API aimed at the same kind of list. Capterra lists the Starter plan at $19 per month for 2,000 requests, which is $0.0095 per request, and the Pro plan at $49 per month for 10,000 requests, which is $0.0049 per request. That listing was updated on 21 October 2026. Check the current price before you rely on it.
| This Actor (Free plan) | SiteEnrich Starter | SiteEnrich Pro | |
|---|---|---|---|
| Unit price | $0.0025 per mapped website, plus $0.0002 once per run | $0.0095 per request ($19 / 2,000) | $0.0049 per request ($49 / 10,000) |
| One website, its own run | $0.0027 | $0.0095 | $0.0049 |
| 100 websites, one run, all mapped | $0.2502 | $0.95 | $0.49 |
| What you get | Page addresses, contact-form presence, hasPricing, hasCareers, hasDemoCta. No e-mail addresses | Their listing includes e-mail extraction, social profiles and business signals | Same as Starter, plus their higher quota |
| Not mapped (robots, challenge, no page) | Free | A request, on their pricing page's terms | A request, on their pricing page's terms |
The two products are not the same thing. SiteEnrich's listing sells e-mail extraction. This Actor does not return e-mail addresses, phone numbers or social profiles. The comparison is the price of looking up one website.
How does it compare with other Actors?
Checked on the Apify Store on 2026-11-04. Most "contact" Actors on the Store are built to collect e-mail addresses and phone numbers. This one is built to map where the pages are, and to stay within what a polite visitor may do.
| This Actor | sandy_yclept/contact-page-finder | emastra/website-contact-scraper | automation-lab/website-contact-finder | |
|---|---|---|---|---|
| Main job | Addresses of eleven page types | The contact page and whether it has a form | E-mails, phones, social profiles | E-mails, phones, social profiles, contact pages |
| Page types beyond contact | About, team, pricing, careers, blog, press, support, docs, privacy, terms | No | No | No |
| Confidence and evidence per page | Yes | Not documented | Not documented | Not documented |
| Reads e-mail addresses and phone numbers | No, by design | Not documented | Yes | Yes |
| Detects contact forms | Yes, presence only. No field values and no e-mail addresses | Yes | Not documented | Not documented |
| Yes/no columns for pricing, careers and a demo button | Yes (hasPricing, hasCareers, hasDemoCta) | Not documented | Not documented | Not documented |
Obeys robots.txt | Yes, checked at every redirect | Not documented | Not documented | Not documented |
| Stops at bot challenges | Yes, never bypasses | Not documented | Not documented | Not documented |
| Needs a proxy | No | Optional (proxy input) | Optional | Optional |
| Price (Free plan) | $0.0025 per mapped website + $0.0002 start | $0.005 per contact page + $0.00005 start | $0.004 per domain + $0.00005 start | $0.001 per website + $0.035 start (e-mail checks extra) |
In short: this Actor now reports whether a contact form is present, and it still does not read the form or collect e-mail addresses. sandy_yclept/contact-page-finder is the specialist if the contact page alone is the whole job. If you need e-mails and phone numbers, use a contact scraper and check that you may use that data. If you need a map of the key pages of each site, with confidence, evidence and yes/no columns for a pricing page, a careers page and a demo button, and a tool that refuses to do what a site has asked automated visitors not to do, this Actor is built for that. Cells marked "Not documented" mean the other Actor's page does not mention the feature; it may still do it.
Is it legal to find key pages of websites?
This Actor reads only public pages that any visitor can open without logging in, and it follows the rules sites publish for automated visitors. Please read this section before you use it at scale.
- It sends plain HTTP requests for the home page,
robots.txt, a sitemap and a few common addresses. It uses no login, no cookies, no accounts and no hidden or paid content. - It obeys
robots.txt. If the home page is not allowed, nothing else is requested. Every redirect hop is checked again. It identifies itself with a user agent that names the Actor and its Store page, and the rules forKeyPagesFinderinrobots.txtapply to it. - It is polite: one request at a time per site, at least one second apart, and longer if
Crawl-delayasks for it. A site that asks for more than ten seconds is skipped. Different sites are visited in parallel, but a single site never sees more than one request at a time. - If a site answers 403 or 429, or shows a bot challenge, the Actor stops for that site. It does not retry, rotate addresses, change its identity, solve CAPTCHAs or look for another way in. That is final for the run.
- It collects no personal data. It never opens
mailto:ortel:links, drops any address or link text that contains an e-mail address or phone number, refuses an e-mail address typed into the input and does not echo it, and keeps link text to at most 80 characters. It returns addresses of pages, not their contents. When it looks for a contact form it reads only that a form element is there. Values, placeholders and addresses inside the form are not copied to the output, and the form is never submitted. - Website terms of use may still restrict automated access even to public pages, and some sites object to it. Whether a particular use is lawful depends on the site's terms, the data you do something with afterwards and the law that applies to you (for example the GDPR and the rules on unsolicited marketing). You are responsible for how you use the output. Do not use it to build contact lists for unsolicited messages.
- Takedown: if a rights holder or a website owner asks for something to be removed, or for access to stop, we will honour the request, up to and including removing the Actor. Use the Issues tab of this Actor.
Not affiliated with, endorsed by or sponsored by Greenhouse, Lever, Ashby, Workable or any website it visits. All names are the property of their owners.
Using the API
MCP (AI agents)
Apify MCP server (ChatGPT, Claude, Cursor and other MCP clients). Connect https://mcp.apify.com, then:
search-actorswith a query such ascontact page finder about page careers page.fetch-actor-detailsformmdincer/website-key-pages-finderto read the input schema.call-actorwith the input below.get-dataset-itemswith the returned dataset ID.
{"actor": "mmdincer/website-key-pages-finder","input": {"websites": ["linear.app", "vercel.com"],"pageTypes": ["contact", "pricing", "careers"]},"callOptions": { "maxTotalChargeUsd": 0.1 }}
To give an MCP client this Actor as its own tool (no search step), connect https://mcp.apify.com?tools=mmdincer/website-key-pages-finder.
JavaScript
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('mmdincer/website-key-pages-finder').call({websites: ['linear.app', 'vercel.com', 'gitlab.com'],pageTypes: ['contact', 'pricing', 'careers'],});const { items } = await client.dataset(run.defaultDatasetId).listItems();for (const site of items.filter((item) => item.status === 'ok')) {console.log(site.domain, site.contactUrl, site.pricingUrl, site.careersUrl);}
Python
from apify_client import ApifyClientclient = ApifyClient("YOUR_APIFY_TOKEN")run = client.actor("mmdincer/website-key-pages-finder").call(run_input={"websites": ["linear.app", "vercel.com", "gitlab.com"],"pageTypes": ["contact", "pricing", "careers"],})items = client.dataset(run["defaultDatasetId"]).list_items().itemsfor site in items:if site["status"] == "ok":print(site["domain"], site["contactUrl"], site["pricingUrl"], site["careersUrl"])
curl
curl -s -X POST "https://api.apify.com/v2/acts/mmdincer~website-key-pages-finder/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"websites": ["linear.app"], "pageTypes": ["contact", "pricing"]}'
Clay and n8n
Use the yes/no columns as a gate before a paid enrichment. Keep a company when hasPricing and hasCareers are both true. Add hasDemoCta or hasContactForm when you want a tighter list. A null means the Actor did not look (you left that page type out, or the site was not read). Do not treat null as "no".
Clay
Add an HTTP API enrichment column on a table that already has a domain column:
- Method:
POST - URL:
https://api.apify.com/v2/acts/mmdincer~website-key-pages-finder/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN - Body:
{"websites": ["{{Domain}}"],"pageTypes": ["contact", "pricing", "careers"]}
Map hasPricing, hasCareers, hasDemoCta, hasContactForm and contactUrl from the first item of the response. Put the Apollo column behind a filter that keeps the row only when hasPricing and hasCareers are true.
One Clay row is one Actor run, so the $0.0002 start fee is paid on every row. For a long list, run the Actor once with every domain in websites (up to 1,000) and import that dataset into Clay. The start fee is then paid once. See the unit-price table above.
n8n
- Add an HTTP Request node. Method POST. URL:
https://api.apify.com/v2/acts/mmdincer~website-key-pages-finder/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN
Body (JSON), one run for the whole list:
{"websites": ["linear.app", "vercel.com", "gitlab.com"],"pageTypes": ["contact", "pricing", "careers"]}
The endpoint returns one JSON item per website. Let n8n split that array into items.
- Add an IF node before the Apollo node:
{{ $json.status === "ok" && $json.hasPricing === true && $json.hasCareers === true }}
Only the true branch calls Apollo. hasDemoCta and hasContactForm can be extra conditions on that same expression. A site that showed a bot challenge has hasPricing set to null and stays on the false branch, so the credit is not spent. Put the token in an n8n credential or an environment variable, not in a shared workflow export.
Review the weak results only
Keep the strong addresses and send the rest to a person:
const weak = items.filter((site) => site.status === 'ok').flatMap((site) => site.pages.filter((page) => page.confidence !== 'high').map((page) => ({ domain: site.domain, ...page })));
FAQ
Does it collect e-mail addresses or phone numbers?
No, and it is built so that it cannot. It never opens mailto: or tel: links, drops any address or link text that contains an e-mail address or a phone number, and returns only the address of the page. A contact form is reported as yes or no. The fields, the placeholders and any address typed into the form are not returned. If you need contact details, you need a different tool and your own legal basis.
Does it detect contact forms?
Yes, as a yes/no on hasContactForm. It counts a message box, a form labelled as contact, a name-and-email form on the contact page, or an embedded form from a known form host. It does not count a search box, a newsletter signup, a login or a cookie banner. It does not submit the form. If robots.txt disallows the contact page, the request budget is used up, or the page answers with a bot challenge, hasContactForm is null and the Actor does not try another way in.
What do hasPricing, hasCareers and hasDemoCta mean?
hasPricing and hasCareers are true when that page was found. They are false when you included that type and the site was read but the page was not found. They are null when you did not ask for that type, so a run with "pageTypes": ["contact"] will not claim the site has no pricing page. The default asks for all eleven types, so a default run fills both columns. hasDemoCta is true when a link or button on a page that was read asks for a demo. The demo URL is not included, because a booking link can carry an address.
What happens if a site blocks the Actor?
On a 403, a 429 or a bot challenge the Actor stops for that site, marks the row bot_challenge or refused and does not charge for it. It does not retry or look for another route. In the 101-site run, 4 well-known sites did this. Run again later if you wish; the answer may differ, and for some sites it never will.
What if robots.txt does not allow the Actor?
The row says robots_disallowed and nothing else is requested from that site. You are not charged. If a robots.txt cannot be reached because the server fails, the site is reported as unreachable and not visited, because the Actor cannot tell what is allowed. If robots.txt is missing (a 404, or an HTML page returned instead), the Actor treats everything as allowed, as RFC 9309 says.
Why did a site return few or no pages?
The home page may be built by JavaScript, so a plain request sees few links; the site may be a single page or an app behind a login; or the pages may use unusual names. The Actor then falls back to the sitemap and common addresses. If nothing is found the row says no_pages_found, and you are not charged. Raising maxRequestsPerSite helps only when the budget was the limit (see stoppedReason).
How accurate are the addresses?
Addresses linked from the menu or footer and confirmed by the sitemap score high and were almost always right in our checks. medium and low addresses come from a single weaker source (for example a guessed common address, which is verified, or a sitemap-only entry) and deserve a look. For example, a site's terms page found only in the sitemap may be a product-specific terms page. The evidence field shows every source that named the address.
Why is there a support and a contact address that are the same?
Many sites use one page for both. The same address can appear under several types. pagesFound counts distinct types, not distinct addresses.
Does it follow redirects?
Yes, one hop at a time, and each hop is checked against robots.txt. A redirect to a different site is refused, except for the home page of the site you entered (for example from the bare domain to www.). A refused redirect to another site is not followed.
Why can't I set the delay below one second?
The Actor is built to be a polite visitor. The minimum is 1000 ms between two requests to the same site, and a site's own Crawl-delay (up to 10 s) takes precedence if it is longer.
How many websites can I send?
Up to 1,000 per run. For longer lists, split them into several runs. Duplicates (including www. and bare domain) are merged and not charged twice.
What about careers pages on Greenhouse, Lever and similar boards?
When the company's careers link points to a known applicant tracking system, the address is returned with atsProvider set (for example greenhouse). Reading the jobs there is a different job: see mmdincer/ats-jobs-monitor.
Is the output deterministic?
For the same site content, yes: same scores, same order. Sites change, so two runs months apart may differ.
Where can I report a problem or request a feature?
Use the Issues tab of this Actor. Please include the run ID and the website that failed.