New contractor businesses buy a lot in their first months: insurance, bonds, trucks, tools, software, accounting and supplies. Several states publish their contractor license data as free open data, updated daily, with no login and no scraping. This post shows how to pull every new contractor business licensed in the last 30 days in Oregon and Connecticut with one short Python script, using only official state APIs.
Run on Oct 22, 2026, the script found:
- Oregon: 495 new contractor businesses in 30 days. 275 were residential general contractors, 67 lead-safe renovators and 53 residential specialty contractors. The top counties were Multnomah (62), Washington (56), Marion (48) and Clackamas (40), and 84 were out-of-state firms entering Oregon.
- Connecticut: 285 new contractor business licenses. 237 were home improvement contractors, 28 new home construction contractors, 15 major contractors and 3 demolition contractors.
The data sources
| State | Agency | Dataset | Notes |
|---|---|---|---|
| Oregon | Construction Contractors Board (CCB) | CCB Active Licenses | Public domain. Includes the original registration date, phone, bond and insurance carrier |
| Connecticut | Dept. of Consumer Protection | State Licenses and Credentials | Public domain. Covers every DCP license, not just contractors, with an entity type field |
Both run on Socrata, so you query them with plain HTTP and SoQL.
The script
import requests, re
from datetime import date, timedelta
ENTITY = re.compile(r"\b(LLC|L\.L\.C\.|INC|CORP|CORPORATION|CO|COMPANY|LTD|LLP|LP|PLLC|PC)\b\.?", re.I)
def ct_new_contractors(days=30):
since = (date.today() - timedelta(days=days)).isoformat()
rows = requests.get("https://data.ct.gov/resource/ngch-56tr.json", params={
"$select": "businessname,name,type,credential,fullcredentialcode,status,issuedate,city,zip",
"$where": (f"issuedate >= '{since}' AND issuedate <= '{date.today()}T23:59:59' "
"AND upper(credential) like '%CONTRACTOR%' "
"AND type in ('LIMITED LIABILITY COMPANY','CORPORATION','BUSINESS','PARTNERSHIP')"),
"$order": "issuedate DESC", "$limit": 5000}, timeout=120).json()
return rows
def or_new_contractors(days=30):
since = date.today() - timedelta(days=days)
rows = requests.get("https://data.oregon.gov/resource/g77e-6bhs.json", params={
"$select": "license_number,license_type,endorsement_text,full_name,city,county_name,orig_regis_date,ins_company,ins_exp_date",
"$where": f"orig_regis_date like '%/{since.year}'", "$limit": 50000}, timeout=120).json()
out = []
for r in rows:
m, d, y = map(int, r["orig_regis_date"].split("/"))
if date(y, m, d) >= since and ENTITY.search(r.get("full_name", "")):
out.append(r)
return sorted(out, key=lambda r: r["orig_regis_date"][-4:] + r["orig_regis_date"][:5], reverse=True)
ct, orr = ct_new_contractors(), or_new_contractors()
print(len(ct), "new CT contractor businesses;", len(orr), "new OR contractor businesses")
Three things that will trip you up
-
Oregon stores dates as
MM/DD/YYYYtext. You can't run a date range query on the server. The script narrows by year withlike '%/2026', then filters the exact window in Python. (For windows that cross New Year, add the previous year too.) - Connecticut has some future issue dates (data-entry errors such as 2027-03-31). Add an upper bound of today, as the script does.
-
Keep it to businesses. Both datasets include sole proprietors, whose names are personal names. Connecticut has a
typecolumn, so filter to LLCs, corporations and partnerships. Oregon doesn't, so keep only names with an entity marker (LLC, Inc, Corp...) and never pull the responsible-individual column. That's better for privacy, and businesses are the leads you want anyway.
Turning it into a weekly lead list
- Run it weekly with
days=7, de-duplicate on license number, and append to a sheet or your CRM. - Oregon's
ins_companyandins_exp_dateare useful for insurance agents: sort by expiration date for renewal timing. - In Connecticut, change the credential filter to
'%LIQUOR%'or'%FOOD%'and the same script finds new restaurants and bars.
Optional: if you'd rather not maintain the script, I publish both as hosted, scheduled tools: Oregon CCB Contractor License Scraper and Connecticut License Lookup (paid per result). Disclosure: they're my tools. The code above does the same job for free.
Top comments (0)