Us State Contractor License Scraper
Pricing
from $3.50 / 1,000 contractor license extracteds
Us State Contractor License Scraper
Look up official California CSLB, Florida DBPR and Texas TDLR records. Extract license status, expiration dates, public contacts and renewal flags, plus available California bond and workers' compensation details. Export data for verification and prospecting.
Pricing
from $3.50 / 1,000 contractor license extracteds
Rating
0.0
(0)
Developer
Arezdev
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
Find licensed contractors and renewal opportunities using official California, Florida, and Texas licensing records.
Extract contractor identities, classifications, published contact details, license dates, and 60-day renewal flags into a flat Apify dataset. California records also include published contractor bond and Workers' Compensation details. Download JSON, CSV, Excel, or connect the dataset to your workflow.
Best for license verification workflows and renewal lead research. California requires exact license numbers. Texas discovery covers supported HVAC and electrical datasets; Florida coverage follows supported DBPR searches. Verify trade and location coverage before scaling.
Ready-to-run example
The Input form includes public example values. A fresh apify run uses the input schema defaults. To explicitly select the small sample, including when input was saved by an earlier local run, use:
apify run --input-file .actor/input.example.json
You can also paste .actor/input.example.json into the JSON input editor in Apify Console. Replace the example sources with your own targets and increase the limits when you are ready.
How to use
- Choose Texas, California, or Florida.
- Enter license numbers for exact lookup, or select a trade and city for Texas or Florida discovery.
- Set the maximum number of saved records and optional expiration window.
- Run the Actor and open the dataset. Filter
status = SUCCESSbefore using the records downstream.
The form starts with a small Texas HVAC sample, an empty city, and 3 records. Its request uses the public Socrata API directly. The schema default is also city: "" for statewide extraction, with maxItems: 50 for API or CLI inputs that omit the item limit. Source availability and network latency can change; successful extraction within five seconds cannot be guaranteed.
Quick Texas sample:
{"state": "TX","tradeCategory": "HVAC_ACR","city": "","onlyActive": true,"maxItems": 3}
Florida HVAC discovery:
{"state": "FL","tradeCategory": "HVAC_ACR","city": "MIAMI","onlyActive": true,"maxItems": 50}
California exact lookup:
{"state": "CA","licenseNumbers": ["1013845"],"onlyActive": false,"maxItems": 3}
Exact license lookup ignores the discovery city and trade category. Active-status and expiration filters still apply. Supply only the numeric license portion for Texas and California; Florida numbers include their prefix. A missing exact license produces an ERROR record. A valid license excluded by a filter produces no record. An empty discovery search produces no records.
What data can you extract?
| Data | California CSLB | Florida DBPR | Texas TDLR |
|---|---|---|---|
| License number, business or licensee, classification | Yes | Yes | Yes |
| Owner or qualifying individual | When published | Primary licensee | When published |
| Published license status | Yes | Yes | Not in this dataset |
| Expiration and renewal flags | When published | When published | When published |
| Issue date | When published | When published | Not in this dataset |
| Address, city, county, ZIP, phone | When published | When published | Frequently omitted by the source |
| Contractor bond company and amount | When published | Not on the supported detail page | Not in this dataset |
| Workers' Compensation carrier, policy, expiration | When published | Not on the supported detail page | Not in this dataset |
Unavailable fields are null. They are never filled with guesses or unrelated state agency contact information. California insurance exemptions leave policy fields null. bondAmount refers to the contractor's bond, rather than additional LLC or qualifying-individual bonds. Multiple California classifications share one record. Distinct Texas license classifications or subtypes can produce separate records for the same numeric license.
Texas uses the TDLR All Licenses dataset. Its published schema has no license-status column. onlyActive uses an unexpired date as a proxy, and licenseStatus explicitly says that TDLR does not publish status here. An unexpired date does not independently confirm that a license is in good standing. The dataset is a periodic extract and may lag behind a license's latest renewal.
Texas supports electrical and HVAC discovery. ALL includes those construction trades and excludes unrelated professions. Plumbing licenses are overseen by a separate Texas board; plumbing, roofing, and general-building discovery are unavailable through this TDLR endpoint. Unsupported Texas trade discovery is rejected before any network requests. Published Texas HVAC records inspected on October 19, 2026 had no business or mailing city values. Such records cannot match a city filter; clear the city to retrieve them.
California uses CSLB license detail lookups and requires license numbers. Florida submits the official DBPR search form, follows its pagination, and supports both legacy and current portal detail layouts. An empty Florida city searches the 67 Florida counties in turn; this is slower than searching one city. Records are checked against the exact requested city after detail extraction.
Input settings
| Setting | Default | Accepted values |
|---|---|---|
state | TX | TX, CA, FL |
licenseNumbers | None | Up to 5,000 exact numbers; required for CA |
tradeCategory | HVAC_ACR | ALL, ELECTRICAL, HVAC_ACR, PLUMBING, ROOFING, GENERAL_BUILDING |
city | "" (statewide) | Optional city; empty string for statewide discovery |
onlyActive | true | Exclude inactive or expired licenses; TX uses date inference |
expiringWithinDays | None | Integer from 1 through 365, inclusive |
maxItems | 50 | 1 through 5,000; form sample uses 3 |
timeoutSecs | 15 | 3 through 60 seconds per HTTP attempt |
maxConcurrency | 25 | 1 through 100; HTML portals use at most 3 concurrent lookups |
proxyConfiguration | Automatic direct-first policy | Apify proxy editor configuration |
daysUntilExpiration compares calendar dates in UTC. Today is 0; yesterday is -1. isRenewalLead is true from 0 through 60 days, inclusive. Missing or invalid expiration dates yield daysUntilExpiration: null and isRenewalLead: false. Expiration-window filtering excludes missing dates and already expired licenses.
Texas always connects directly. California and Florida first connect directly, then can try SHADER and account datacenter proxies for HTTP 403, 429, or 503. Configured or residential fallback is enabled only when useApifyProxy: true is explicitly supplied. useApifyProxy: false forces direct requests. Custom proxyUrls are used as supplied, rotating across requests without automatic Apify fallback. HTTP and HTTPS proxies must resolve to public addresses.
Automatic Apify proxy use requires APIFY_PROXY_PASSWORD in the run environment. The Actor never retrieves an account-wide proxy password through a user-profile API. If credentials or proxy access are unavailable, source failures remain visible as uncharged errors. No credentials are included in logs or output.
Output example
Illustrative data:
{"state": "CA","licenseNumber": "123456","status": "SUCCESS","businessName": "EXAMPLE ELECTRIC LLC","ownerOrQualifierName": "JANE DOE","tradeClassification": "C-10 - ELECTRICAL","licenseStatus": "This license is current and active.","issueDate": "2020-03-10","expirationDate": "2026-11-01","daysUntilExpiration": 13,"isRenewalLead": true,"phone": "+1 (213) 555-0100","streetAddress": "100 MAIN ST","city": "LOS ANGELES","county": null,"zipCode": "90001","workersCompCarrier": "EXAMPLE INSURANCE","workersCompPolicyNumber": "WC123","workersCompExpirationDate": "2026-12-31","bondCompany": "EXAMPLE SURETY","bondAmount": 25000,"sourceUrl": "https://www.cslb.ca.gov/OnlineServices/CheckLicenseII/LicenseDetail.aspx?LicNum=123456","scrapedAt": "2026-10-19T12:00:00.000Z","errorMessage": null}
Every record uses the same 24 flat fields. An error retains state, the requested licenseNumber when known, sourceUrl, and scrapedAt; it sets status: "ERROR", a safe errorMessage, nullable extracted fields to null, and isRenewalLead: false.
Use the results in Clay, n8n, Make, or your API
- Clay: Import the dataset's CSV export, deduplicate by state, license number, and classification, then filter renewal leads.
- n8n: Use the Apify integration or an HTTP Request node to start a run, wait for completion, and fetch the default dataset. Route only
SUCCESSrecords into your CRM. - Make: Connect an Apify run to a dataset-record iterator, then send selected fields to your existing workflow.
- API: Use the Actor's API tab to obtain its run endpoint. After completion, request
GET https://api.apify.com/v2/datasets/{defaultDatasetId}/items?format=json&clean=truewith the authorization method provided by your Apify account.
Schedule repeated runs in Apify to track upcoming renewals. Match on state, license number, and classification because numeric license numbers are not globally unique. Dataset strings are protected against spreadsheet formula injection. Valid phone numbers retain their leading plus sign. Render values as text when displaying them in an HTML application.
Pricing and limits
The custom pay-per-event name is license-scraped. Only saved SUCCESS records are submitted with that event. ERROR rows cost $0 in custom event fees. Platform compute, storage, transfer, and proxy usage may still apply to a run.
Use the current price shown in the Store or run pricing configuration. For a concrete example, at an event rate of $0.002 per successful record, 1,000 successful records cost $2.00 in event fees; 900 successful records and 100 errors cost $1.80 in event fees. This is an example calculation, not an advertised configured price. Pricing is configured on Apify, outside this repository.
Free Apify plans can save at most 25 records per run, including errors. Paid and local runs honor maxItems up to 5,000. A charge budget can reduce the number of successful records saved. When the budget is exhausted, the Actor flushes allowed records, stops scheduling requests, and finishes with exit code 0.
Records are written in serialized batches of up to 100, on a five-second flush interval, at limits, and during orderly shutdown. A platform abort can retain already saved records; a forced process kill cannot flush in-memory records.
FAQ and troubleshooting
Why did Texas return zero records for Austin?
The source may omit every city in the selected trade. Clear city, use exact license numbers, or choose Florida city discovery. The Actor does not silently drop a user-supplied city filter. Empty discovery results have no custom event fee.
Why are phone, address, bond, or insurance fields null?
The selected official source did not publish them. These fields are not equally available across states. The DBPR agency phone in a page footer is never treated as a contractor phone.
Why did California return SOURCE_UNAVAILABLE?
CSLB sometimes redirects license detail requests to a maintenance page. This is detected as an ERROR, and that row has no custom event charge. Retry when the official portal is available. California detail requests on October 19, 2026 returned scheduled-maintenance pages during verification.
Why was an exact number omitted?
It may exist but fail onlyActive or expiringWithinDays. Disable the status filter and remove the expiration window to inspect it. A missing license or failed request is recorded separately as an error.
What does a partial-response warning mean?
HTML is limited to 4 MiB after decompression. A completed license record may be retained from a larger page, or after a timeout/reset when at least 16 KiB of a successful HTML response arrived. Missing fields remain null, and a page without the required license identity is rejected. JSON responses are limited to 2 MiB and are never partially parsed.
Can I use limited permissions?
Yes. The Actor uses run environment metadata for the free-plan gate and does not call /v2/users/me. Automatic proxy setup skips account-profile discovery. No browser or browser engine is installed or launched.
Development and deployment
Requires Node.js 22 or later. All source, logs, schemas, and documentation are in English.
npm ci --ignore-scriptsnpm run buildnpm testnpm run smoke
Unit tests use node:test and deterministic HTTP fixtures or injected streams. npm run smoke performs direct live-source checks; it reports California source failures separately because maintenance cannot be predicted. Every child test or smoke process sets UV_THREADPOOL_SIZE=64, production mode, and strict TLS verification.
The Dockerfile uses a Node.js 22 Alpine build stage and a non-root production stage with a 160 MiB JavaScript heap limit. Actor run defaults are 256 MiB RAM and a 3,600-second timeout. Network protection validates public DNS addresses on every redirect, pins direct DNS lookups without replacing the hostname, and tunnels proxy connections to validated destination IPs while keeping TLS verification and the original TLS server name.
Before publication, configure Pay per event in Apify Console with the event license-scraped and your chosen price. Do not add an automatic default-dataset-item charge; only the explicit custom event should have a price. Keep the Actor's run permission mode at Limited permissions. The repository does not publish, set a Store price, or modify your account automatically.
Initialized by Arezgit.