Contact Form Detector: Fields, CAPTCHA & Action URL
Pricing
from $1.40 / 1,000 website with a contact page or forms
Contact Form Detector: Fields, CAPTCHA & Action URL
Give company websites, get the contact page URL, whether it has a contact form, each field and its role (name, email, phone, message), the form action, CAPTCHA (reCAPTCHA, hCaptcha, Turnstile), honeypots, and emails and phones. Never submits a form.
Pricing
from $1.40 / 1,000 website with a contact page or forms
Rating
0.0
(0)
Developer
NeverEmpty
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
Contact Form Detector - find the contact page and read its form fields, CAPTCHA and action URL
For outreach teams, lead-gen agencies and form-automation builders: give it a list of company websites and get back, for each one, the contact page URL and the exact shape of its contact form - every field with its name, type, label and role (firstName, email, phone, company, message, ...), which fields are required, where the form posts (action, method, encoding), which CAPTCHA is on the page (reCAPTCHA v2/v3, hCaptcha, Turnstile) and which fields are hidden spam traps.
One row per website. Also on the row: emails, phone numbers and social profiles printed on those pages, forms embedded from HubSpot, Typeform, Google Forms, Jotform and others, and the site's own "no sales pitches through this form" notice when it has one.
Finds contact pages in 20+ languages - Contact, Kontakt, Contacto, Contato, Contatti, Nous contacter, お問い合わせ, 联系我们, 문의, Связаться, İletişim, Liên hệ and more - by reading the links on the home page, then the common contact paths for the site's language.
Reads only. No form is ever submitted, no CAPTCHA is solved, robots.txt is followed. No API key, no login. Export as JSON, CSV or Excel.
What you get
One row per website, with:
- The contact page:
contactPageUrl, how it was found (link,link-from-contact-page,common-path,given-url) and the link text the site uses for it - The form:
hasContactForm,contactFormUrl,formAction,formMethod,formEnctype, whether the action posts to the same site, the submit button label, and the form builder behind it (contact-form-7,wpforms,gravity-forms,elementor,hubspot,shopify, ...) - Every field in
formFields: name, type, label, placeholder, required or not, the options of a select box, and aroleyou can map from fieldMap: role → field name, ready to fill ({"email": "your-email", "message": "your-message"}), andrequiredRoles- What stands in the way:
captcha(recaptcha-v2,recaptcha-v3,recaptcha-enterprise,hcaptcha,turnstile,captcha-field),honeypotFields,consentRequired(a privacy checkbox that must be ticked),fileUpload - Forms from other services:
embeddedFormswith the provider, its URL and how it is placed (iframe,link,script) noSolicitationNotice: the sentence where the site asks not to be sent sales messages, with the page it is on - so you can respect it- Other ways to reach them:
emails,phones(international format) andphonesAsWritten,socials(LinkedIn, X/Twitter, Facebook, Instagram, YouTube, TikTok, GitHub), contact pages on another domain (offsiteContactLinks) - The trail:
pagesRead,httpStatus,statusand a plain-Englishnotethat says why a site has no row of results
Example output (one website, socials shortened)
{"status": "ok","website": "https://wpforms.com/","contactPageUrl": "https://wpforms.com/contact/","contactPageFoundBy": "link","contactLinkText": "contact us","hasContactForm": true,"contactFormUrl": "https://wpforms.com/contact/","formProvider": "wpforms","formAction": "https://wpforms.com/contact/","formActionSameSite": true,"formMethod": "POST","formEnctype": "multipart/form-data","formFields": [{ "name": "wpforms[fields][0][first]", "type": "text", "role": "firstName", "label": "First", "required": true },{ "name": "wpforms[fields][0][last]", "type": "text", "role": "lastName", "label": "Last", "required": true },{ "name": "wpforms[fields][1]", "type": "email", "role": "email", "label": "Email: *", "required": true },{ "name": "wpforms[fields][3]", "type": "url", "role": "website", "label": "Website: *", "required": true },{ "name": "wpforms[fields][2]", "type": "textarea", "role": "message", "label": "Comment or Message *", "required": true }],"fieldMap": {"firstName": "wpforms[fields][0][first]","lastName": "wpforms[fields][0][last]","email": "wpforms[fields][1]","website": "wpforms[fields][3]","message": "wpforms[fields][2]"},"requiredRoles": ["firstName", "lastName", "email", "website", "message"],"captcha": [],"honeypotFields": [],"consentRequired": false,"fileUpload": false,"submitLabel": "Submit","embeddedForms": [],"noSolicitationNotice": null,"socials": { "twitter": ["http://x.com/easywpforms"], "facebook": ["https://facebook.com/wpforms"] },"pagesRead": ["https://wpforms.com/", "https://wpforms.com/contact/"]}
Field roles: name, firstName, lastName, nameKana, email, phone, company, jobTitle, website, subject, message, address, city, zip, country, date, number, consent, file, captchaAnswer, other. Labels in Japanese, German, French, Spanish, Portuguese, Italian and other languages are read too (会社名 → company, Nachricht → message).
Input
- Websites (
domains) - domains (example.com) or URLs, one per line, up to 500 per run. Give a page URL (https://example.com/de/kontakt) and that page is read first. - Pages read per website (
maxPagesPerWebsite, 1 to 8, default 4) - the home page counts as one. Reading stops as soon as a contact form is found. - Websites read at the same time (
maxConcurrency, 1 to 8, default 4). - Time limit per request (
requestTimeoutSecs, 5 to 60 seconds, default 20). Busy servers (HTTP 429 and 5xx) are asked again up to two more times.
Leave the list empty and the example site contactform7.com is read, free of charge.
When a website has no row of results
Every website you give gets a row, so you can see what happened. status says why:
| status | what it means |
|---|---|
ok | a contact page or a contact form was found |
no-contact-page-found | the pages read have no contact link and the usual contact paths do not answer with a contact page |
robots-disallowed / robots-unreachable | the site's robots.txt does not allow the page, or robots.txt itself could not be read - the page is not fetched |
login-required | the site sends visitors to a login page |
blocked | the site answers with a bot check or refuses the request |
not-found, http-error, unreachable, unreadable, not-html | the site is gone, answers with an error, cannot be reached, or is not a web page |
bad-input | not a website (an email address, an ftp link, a private address) |
Only ok rows are charged.
Things this Actor is careful about
- It never submits a form and never solves a CAPTCHA. It reports what is there.
- robots.txt is followed for every page, and a site whose robots.txt cannot be read is left alone.
- A page is called a contact page only when it is one. A path that answers 200 for anything (
/contact/on a site that returns its home page for every URL) is checked for contact wording and a form before it is used. Links that lead to another company's site are not followed. - Spam traps are named, not filled. Hidden fields named like a trap (
website_hp,honeypot,ak_hp_textarea, ...) are listed inhoneypotFieldsso your own tooling can leave them empty. - Search boxes, newsletter sign-ups and login forms are not counted as contact forms.
- The same website given twice is read and charged once, and a run restarted by the platform does not charge again for websites already returned.
Good to know
- Forms that a script draws after the page loads are not in the page's HTML. When the contact page loads a form script (HubSpot, Marketo, Pardot, ...) or has almost no text without JavaScript,
jsFormHintsays so andembeddedFormslists the script. - Some contact pages carry only an email address or a phone number. Those rows have
hasContactForm: falseand the address and number filled in. - A big site can have several forms (sales, support, press). The main one is in
formFields;otherContactFormscounts the rest.
Frequently asked
How do I find the contact form of a list of company websites? Paste the domains into Websites and run. Each row gives the contact page URL, the form's fields with their roles, and where it posts.
How do I know which fields a contact form requires?
requiredRoles lists the roles of the required fields, and each entry of formFields has required: true or false.
Which websites use reCAPTCHA, hCaptcha or Cloudflare Turnstile on their contact form?
The captcha column names the kind found on the page with the form. An empty list means no CAPTCHA mark was found in the HTML.
Can it find contact pages on German, Japanese or Spanish sites? Yes. Links such as Kontakt, お問い合わせ, Contacto, Contato and Contatti are recognised, and the usual contact path for the site's language is tried when no link is found.
Does it send messages through the forms?
No. It reads the form and returns its shape. Sending is up to you, and noSolicitationNotice shows when a site asks not to receive sales messages.
Does it need a browser or an API key? No API key and no login. Pages are read as plain HTML, which keeps runs fast and inexpensive.
Limitations
- Fields that only exist after JavaScript runs are not read (see
jsFormHint). - Sites behind a bot check, a login, or a robots.txt rule are reported with their
statusand not read. - Up to 8 pages per website are read; a form hidden deeper is not found.
- CAPTCHA detection is from marks in the HTML; a CAPTCHA added only after a click is not seen.
Pricing
You pay per website where a contact page or a contact form was found (status: ok). Websites with nothing found, errors, blocked sites and the free example run are not charged. Set a maximum charge for a run and the Actor stops before going over it, and says how many websites were left out.
Thanks for using this Actor
Found a site it reads wrong, or a field role you need? Open an issue on the Actor's page - fixes for reported sites come first.