Arizona ROC Contractor License Scraper avatar

Arizona ROC Contractor License Scraper

Pricing

from $6.00 / 1,000 results

Go to Apify Store
Arizona ROC Contractor License Scraper

Arizona ROC Contractor License Scraper

Scrape Arizona Registrar of Contractors (AZ ROC) license records. Search by license number, company name, qualifying party, city, license type and classification. Returns status, bond info, complaint history and full license details.

Pricing

from $6.00 / 1,000 results

Rating

0.0

(0)

Developer

Haketa

Haketa

Maintained by Community

Actor stats

0

Bookmarked

13

Total users

7

Monthly active users

3 days ago

Last modified

Share

Arizona ROC Contractor License Scraper — AZ Registrar of Contractors Lookup, Bond, Complaint & Classification Data Extractor

The most complete Arizona Registrar of Contractors (AZ ROC) public-records extraction tool on Apify. Look up every licensed residential, commercial, and dual contractor in Arizona — by license number, business name, qualifying party, city or classification — with full bond information, complaint history, classification codes, and live status. Structured JSON output, full pagination, ready for compliance, lead generation, due diligence, and underwriting workflows.

Apify Actor


What This Actor Does

The Arizona ROC Contractor License Scraper is a production-ready Apify Actor that extracts the complete public licensing record for any contractor registered with the Arizona Registrar of Contractors (AZ ROC) — the state regulator that licenses every residential, commercial, and dual contractor operating in Arizona, from Phoenix and Tucson to Mesa, Scottsdale, Chandler, Glendale, Gilbert, Tempe, Peoria, Flagstaff, Yuma, and beyond.

The actor targets the live AZ ROC portal at azroc.my.site.com/AZRoc/s/contractor-search — a Salesforce Experience Cloud (Aura/LWC) site that is notoriously difficult to scrape because of dynamic JavaScript rendering, virtualized result tables, and Salesforce-grade bot protection. This actor handles all of that for you with a real Chromium browser, residential-proxy rotation, browser fingerprinting, and full Next-button pagination.

In a single run, you can pull back structured JSON for every contractor matching your query including:

  • License identity — ROC license number, business name, DBA, qualifying party, entity type
  • Classifications — primary classification code (e.g. B-1, R-11, C-37, CR-39) plus the full list of every classification held
  • Status & dates — current license status, first-issued date, renewed-through date, expiration
  • Address & contact — business city, state, ZIP, phone, mailing address
  • Bond information — bond company, bond number, bond type, bond status, bond amount, effective/expiration dates
  • Complaint history — open cases, disciplined cases, resolved cases, and individual complaint IDs with type/outcome where exposed by the portal
  • Personnel — qualifying party, officers, members, partners and their roles
  • Profile URL — deep link back to the canonical AZ ROC detail page for the licensee

Every record carries a scrapedAt timestamp and direct profileUrl reference, making the output drop-in ready for compliance audits, CRM enrichment, lead lists, underwriting pipelines, and journalistic investigations.

Why scrape AZ ROC yourself when this exists?

The AZ ROC contractor-search portal looks simple from the outside. It is anything but. Teams who try to write their own scraper invariably hit the same wall:

  • The portal is a full Salesforce Experience Cloud (Lightning) app — there is no JSON endpoint, no CSV download, and no public API
  • Result rows are rendered by Aura/LWC components that hydrate asynchronously, so naïve HTTP fetches return empty <tr> shells
  • The page-size <select> and the Next pagination button live inside shadow-like Salesforce wrappers — clicks routinely no-op without proper event dispatching
  • Searches return up to thousands of rows across dozens of paginated pages (especially city-wide queries like "Phoenix"), so single-page scrapers miss 95% of the data
  • The site applies Salesforce bot detection that fingerprints headless browsers and blacklists raw datacenter IPs within minutes
  • Contractor detail pages use a flat HTML layout with no semantic IDs — every field must be parsed by label proximity (Business Entity Name, Status / Action, First Issued, Renewed Through, Bond Type, etc.)
  • Bond, complaint, and personnel sections require a second page navigation per contractor — the search results page only shows top-level identity columns
  • Class codes and descriptions are concatenated in a single cell (B-1 General Commercial Contractor) and must be split with regex
  • The portal's HTML uses HTML entities (&amp;, &nbsp;, &#39;) inconsistently — decoding is a constant chore
  • Sessions expire silently; without proper retry logic your scraper appears to succeed while actually losing rows
  • Manual export by AZ ROC public-records request takes business days and arrives as unstructured spreadsheets

This actor solves all of it: a real Playwright browser, residential proxy rotation, Salesforce-aware pagination, label-anchored detail parsing, bond and complaint normalization, deterministic JSON output, and full retry/session handling — so you get clean data the first time, every time.


Quick Start

One-Click Run

  1. Click "Try for free" on the Apify Store page
  2. Enter one or more license numbers, company names, qualifying parties, or Arizona cities into the corresponding input fields
  3. Hit Start — the actor opens a real Chromium browser, performs each search, paginates through every result page, and (optionally) opens each contractor's detail page for full bond and complaint enrichment
  4. Download the dataset as JSON, CSV, Excel, HTML, XML, or RSS directly from the Apify dataset view

API Run (Python)

from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("haketa/az-roc-contractor-license-scraper").call(run_input={
"cities": ["Phoenix", "Scottsdale", "Mesa"],
"licenseType": "RESIDENTIAL",
"licenseStatus": "ACTIVE",
"scrapeDetailPage": True,
"scrapeComplaints": True,
"resultsPerPage": "50",
"maxResultsPerSearch": 0
})
for record in client.dataset(run["defaultDatasetId"]).iterate_items():
print(
record["licenseNumber"],
record["businessName"],
record["primaryClassification"],
record["bondStatus"],
record["complaintCount"],
)

API Run (Node.js / TypeScript)

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('haketa/az-roc-contractor-license-scraper').call({
companyNames: ['Acme Plumbing', 'Sunbelt HVAC'],
licenseStatus: 'ACTIVE',
scrapeDetailPage: true,
scrapeComplaints: true,
maxConcurrency: 3
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(`Got ${items.length} AZ contractor records`);
for (const r of items) {
console.log(`${r.licenseNumber} ${r.businessName}${r.licenseStatus}`);
}

API Run (cURL)

curl -X POST "https://api.apify.com/v2/acts/haketa~az-roc-contractor-license-scraper/runs?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"licenseNumbers": ["099999", "123456"],
"scrapeDetailPage": true,
"scrapeComplaints": true
}'

API Run (Synchronous, single record lookup)

curl "https://api.apify.com/v2/acts/haketa~az-roc-contractor-license-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"licenseNumbers":["099999"]}'

How It Works

The AZ ROC public portal is a single-page Salesforce Experience Cloud application. There is no JSON API and no bulk download. The actor automates the public UI exactly as a human user would, but at production scale:

StepEngineWhat Happens
NavigatePlaywright (Chromium)Opens https://azroc.my.site.com/AZRoc/s/contractor-search and waits for the Aura runtime to hydrate
SearchPlaywrightTypes the query into input[name="input1"], applies advanced filters (type, status, classification) if requested, clicks the Search button
Page sizePlaywrightSwitches the results <select> to 50 rows per page to minimize Next clicks
PaginatePlaywrightClicks the Next button (button.slds-button.right-btn) until disabled — every page is traversed
Parse listHTML + regexExtracts License No, Business Name, Qualifying Party, Class, Status, City/State/ZIP, Phone from data-label columns
Open detailPlaywrightOptionally opens each ?licenseId=... profile URL to grab bond, complaint, personnel, classifications, entity type
NormalizeNode.jsDecodes HTML entities, parses dates into YYYY-MM-DD, splits addresses, deduplicates by licence ID, builds the canonical record
OutputApify DatasetPushes each enriched record to the default dataset with scrapedAt timestamp

Source endpoints

URLPurpose
https://azroc.my.site.com/AZRoc/s/contractor-searchPublic search form + results table
https://azroc.my.site.com/AZRoc/s/contractor-search?licenseId={ID}Contractor detail page (bond, complaints, classifications, personnel)

Engineering details

  • Engine: Crawlee PlaywrightCrawler on Chromium (headless) with --disable-blink-features=AutomationControlled
  • Fingerprinting: Built-in fingerprint generator targeting Chrome 116+ on Windows and macOS desktops
  • Proxy: Apify residential proxy group is the recommended default; datacenter proxies are blocked by Salesforce within minutes of bulk usage
  • Concurrency: Default 3 concurrent browser tabs — tunable from 1 to 10
  • Retry: 3 automatic request retries with session marking on failure
  • Navigation timeout: 90 s
  • Request handler timeout: 600 s (large city searches with thousands of rows can take several minutes)
  • Deduplication: All records keyed by AZ ROC licenseId extracted from the row's deep link; duplicate hits across queries are merged
  • Polite jitter: Random 600–1000 ms delays between Next clicks to mirror human pacing and reduce bot-detection signal
  • HTML entity decoding: &amp;, &nbsp;, &#39;, &quot;, &lt;, &gt; are all canonicalized
  • Date normalization: All date strings emitted as ISO YYYY-MM-DD
  • Phone formatting: Detail-page numbers reformatted to (XXX) XXX-XXXX

Input Parameters

{
"licenseNumbers": ["099999"],
"companyNames": ["Acme Plumbing"],
"qualifyingPartyNames": ["John Smith"],
"cities": ["Phoenix", "Scottsdale"],
"licenseType": "ALL",
"licenseStatus": "ACTIVE",
"licenseClassification": "",
"maxResultsPerSearch": 0,
"resultsPerPage": "50",
"scrapeDetailPage": true,
"scrapeComplaints": true,
"maxConcurrency": 3,
"proxyConfiguration": {
"useApifyProxy": true,
"apifyProxyGroups": ["RESIDENTIAL"]
}
}

Parameter reference

ParameterTypeDefaultDescription
licenseNumbersarray<string>[]One or more ROC license numbers to look up directly. Leading zeros are added automatically (so 99999 becomes 099999). Fastest and most precise search mode.
companyNamesarray<string>[]Business names to search. Partial matches accepted (e.g. Acme Plumbing). Each name triggers its own search and may return many pages of results.
qualifyingPartyNamesarray<string>[]Full name of the qualifying party, the individual legally responsible for the licence. Format First Last. Partial names allowed.
citiesarray<string>[]Arizona cities to search by location (e.g. Phoenix, Tucson, Mesa, Scottsdale). Large cities may return thousands of records — every page is traversed.
licenseTypeenumALLOne of ALL, RESIDENTIAL, COMMERCIAL, DUAL. Filters the advanced-search type dropdown.
licenseStatusenumALLOne of ALL, ACTIVE, SUSPENDED, EXPIRED, REVOKED, CANCELLED. Filters by current standing.
licenseClassificationstring""Optional classification code filter (e.g. B-1, R-11, C-37, CR-39). Leave blank to return all classifications.
maxResultsPerSearchinteger0Cap records per individual search query. 0 = unlimited (scraper paginates until Next is disabled).
resultsPerPageenum"50"Page size in the AZ ROC native dropdown. One of "10", "20", "50". 50 minimizes the number of Next clicks.
scrapeDetailPagebooleantrueIf true, opens every contractor's detail page for full bond, complaint, classification, and personnel data. Disable for fast list-only crawls.
scrapeComplaintsbooleantrueIf true (and scrapeDetailPage enabled), captures the contractor's complaint history (open / disciplined / resolved counts plus individual IDs). AZ ROC only displays the prior two years of complaints.
maxConcurrencyinteger3Max concurrent browser tabs (1–10). Higher values speed up bulk runs but use more memory and proxy bandwidth. 2–5 is the sweet spot for residential proxies.
proxyConfigurationobjectApify residentialStandard Apify proxy config. Residential is strongly recommended for production.

Output Schema

Every record uses one flat JSON shape so downstream consumers (databases, CRMs, BI tools) can ingest the entire dataset without per-record branching.

Identity fields

FieldTypeDescription
licenseNumberstringROC license number (e.g. 099999) — leading zeros preserved
licenseTypestring | nullResidential, Commercial, Dual, or contractor-type label from detail page
licenseStatusstring | nullNormalized license standing — see Status Reference below
businessNamestring | nullLegal business entity name
dbaNamestring | null"Doing Business As" name where present
qualifyingPartystring | nullIndividual responsible for the licence
entityTypestring | nullCorporation, LLC, LP, Sole Proprietorship, Joint Venture, etc.
personnelarray | nullOfficers, members, partners, qualifying party — each with name and role (or position)

Classification fields

FieldTypeDescription
primaryClassificationstring | nullTop classification code (e.g. B-1, R-11, C-37)
classificationDescstring | nullPlain-English description of the primary classification
classificationsarray | nullFull list of every classification held — each item { code, description }

Address & contact

FieldTypeDescription
citystring | nullBusiness city
statestring | nullState (almost always AZ)
zipstring | nullZIP code
phonestring | nullBusiness phone — detail-page records are formatted (XXX) XXX-XXXX
mailingAddressstring | nullMailing address when distinct from business address

Lifecycle dates

FieldTypeDescription
issuedDatestring | nullFirst-issued date in YYYY-MM-DD
renewedThroughDatestring | nullCurrent renewal expiration in YYYY-MM-DD
expirationDatestring | nullLicense expiration in YYYY-MM-DD

Bond information

FieldTypeDescription
bondTypestring | nullContractor bond type (e.g. License Bond)
bondStatusstring | nullActive, Cancelled, Expired, etc.
bondAmountstring | nullBond face amount, formatted as $ {amount}
bondCompanystring | nullSurety company name
bondNumberstring | nullSurety bond number
bondEffectiveDatestring | nullBond effective date YYYY-MM-DD
bondExpirationDatestring | nullBond expiration date YYYY-MM-DD

Complaint history (last 2 years exposed by AZ ROC)

FieldTypeDescription
openCasesinteger | nullCount of open complaints
disciplinedCasesinteger | nullCount of complaints resulting in discipline
resolvedCasesinteger | nullCount of resolved / settled complaints
complaintCountinteger | nullTotal complaint count across all categories
complaintsarray | nullPer-complaint detail — { complaintId, type, outcome }

Metadata

FieldTypeDescription
profileUrlstring | nullDirect deep link to the contractor's AZ ROC detail page
scrapedAtstringISO-8601 timestamp of extraction

Example record — active residential contractor with clean bond

{
"licenseNumber": "099999",
"licenseType": "Residential",
"licenseStatus": "Active",
"businessName": "DESERT SUN HOMES LLC",
"dbaName": "Desert Sun Custom Homes",
"qualifyingParty": "MARTINEZ, CARLOS A",
"primaryClassification": "B-1",
"classificationDesc": "General Residential Contractor",
"classifications": [
{ "code": "B-1", "description": "General Residential Contractor" },
{ "code": "R-11", "description": "Electrical" }
],
"entityType": "Limited Liability Company",
"personnel": [
{ "name": "MARTINEZ, CARLOS A", "role": "Qualifying Party" },
{ "name": "MARTINEZ, ELENA", "role": "Member" }
],
"city": "Phoenix",
"state": "AZ",
"zip": "85016",
"phone": "(602) 555-0142",
"mailingAddress": "PO BOX 12345, Phoenix, AZ 85016",
"issuedDate": "2014-06-12",
"renewedThroughDate": "2026-06-30",
"expirationDate": "2026-06-30",
"bondType": "License Bond",
"bondStatus": "Active",
"bondAmount": "$ 9,000",
"bondCompany": "Western Surety Company",
"bondNumber": "WS-99999123",
"bondEffectiveDate": "2023-06-15",
"bondExpirationDate": "2026-06-15",
"openCases": 0,
"disciplinedCases": 0,
"resolvedCases": 1,
"complaintCount": 1,
"complaints": [
{ "complaintId": "2024-00345", "type": "Workmanship", "outcome": "Resolved" }
],
"profileUrl": "https://azroc.my.site.com/AZRoc/s/contractor-search?licenseId=a0X8z00000ABCDEFGH",
"scrapedAt": "2026-05-16T09:30:00.000Z"
}

Example record — list-only mode (detail page disabled)

{
"licenseNumber": "088888",
"businessName": "SUNBELT HVAC INC",
"dbaName": null,
"qualifyingParty": "CHEN, WEI",
"primaryClassification": "C-39",
"classificationDesc": "Air Conditioning and Refrigeration",
"licenseStatus": "Active",
"city": "Tucson",
"state": "AZ",
"zip": "85701",
"phone": "(520) 555-0199",
"personnel": [
{ "name": "CHEN, WEI", "role": "Qualifying Party / President" }
],
"profileUrl": "https://azroc.my.site.com/AZRoc/s/contractor-search?licenseId=a0X8z00000XXXXYYYY",
"scrapedAt": "2026-05-16T09:30:01.000Z"
}

License Status Reference

Active statuses — contractor may legally work

StatusMeaning
ActiveLicense in good standing, contractor may bid and build
Active - ProbationActive but subject to Board-imposed conditions
Pending RenewalRenewal application in process

Inactive / restricted statuses — contractor MAY NOT legally work

StatusMeaning
SuspendedTemporarily barred from contracting
ExpiredLicense lapsed; renewal not completed
CancelledLicence cancelled (often voluntary)
RevokedPermanently terminated by ROC action
SurrenderedVoluntarily surrendered to ROC, sometimes pre-disciplinary

Tip: Use licenseStatus: "ACTIVE" to receive only currently authorized contractors. Combine with bondStatus filtering downstream to identify contractors carrying valid bonds in addition to a valid licence.


Classification Reference (commonly seen codes)

AZ ROC uses a letter-prefix classification system. The actor returns the raw code (B-1, R-11, C-37) plus a plain-English description.

PrefixScopeExample Codes
AGeneral EngineeringA, A-1 through A-21 (heavy civil, paving, well drilling, etc.)
BGeneral Commercial / ResidentialB, B-1 (General Residential), B-2 (General Small Commercial), B-3 (Dual)
CCommercial SpecialtyC-37 (Plumbing), C-39 (HVAC), C-11 (Electrical), C-16 (Roofing), C-9 (Drywall), C-42 (Pool), C-78 (Solar)
CRCommercial / Residential Specialty (Dual)CR-1 through CR-79 covering all combined trades
KSpecialty (Residential)K-37 (Plumbing), K-39 (HVAC), K-11 (Electrical), K-42 (Pool)
LSpecialtyMisc specialty endorsements
RResidential SpecialtyR-11 (Electrical), R-37 (Plumbing), R-39 (HVAC), R-62 (Pool service)

Pass any of these codes into licenseClassification to filter searches to that endorsement only.


Use Cases

Construction Lead Generation & B2B Sales

Materials suppliers, equipment vendors, software companies (estimating, CRM, field-management), insurance brokers, and trade associations use AZ ROC data to:

  • Build targeted contractor lead lists by Arizona metro, classification, and entity size
  • Segment by trade — pull every active C-37 plumber in Phoenix, or every B-1 general residential builder in Scottsdale
  • Identify net-new licensees by diffing this week's run against last week's
  • Score by experience using issuedDate — flag established firms (10+ years) versus brand-new entrants
  • Enrich CRM accounts (Salesforce, HubSpot, Pipedrive) with current licence status, bond status, and qualifying party
  • Power direct-mail and SMS campaigns with verified mailing addresses and phone numbers

Construction Insurance Underwriting & Surety

Carriers writing general-liability, workers-comp, builders-risk, and contractor surety policies use this data to:

  • Verify licence validity at policy bind, renewal, and on a continuous-monitoring schedule
  • Flag bond status changesActive to Cancelled is a leading indicator of contractor distress
  • Adjust pricing for complaint historydisciplinedCases > 0 is a hard underwriting signal
  • Cross-check qualifying party against named-insured records to detect QP swaps
  • Trigger renewal outreach automatically when renewedThroughDate falls within 60 days
  • Build territory loss ratios with classification-level segmentation

Homeowner Verification & Due Diligence

Homeowner-services platforms, mortgage lenders, title companies, real-estate brokerages, and consumer-protection sites use AZ ROC data to:

  • Verify a contractor's licence before payment — required by Arizona law for projects over $1,000
  • Display real-time licence and bond status in contractor profiles
  • Surface complaint counts and outcomes to consumers comparing bids
  • Confirm classification scope — does this R-11 electrician hold the right endorsement for solar work?
  • Detect look-alike scams — match businessName against advertised name to flag impostors

Compliance, Audit & Risk

General contractors, owner's reps, construction managers, and public agencies use AZ ROC data to:

  • Continuously verify subcontractor licences before issuing change orders or progress payments
  • Maintain SOX/audit-ready logs with timestamped scrapedAt proof of when verification ran
  • Detect lapsed bonds on active projects within 24 hours of expiration
  • Catch suspended qualifying parties before they lose authority on an in-progress job
  • Document responsible-bidder qualifications for public works procurement under Arizona prevailing-wage rules

Investigative Journalism & Public Records

Reporters covering housing, construction defects, fraud, and consumer protection use the dataset to:

  • Map serial complaint history across contractor portfolios
  • Identify QP-shopping patterns — qualifying parties moving rapidly between distressed licensees
  • Quantify disciplinary trends by ROC region or classification
  • Cross-reference SOS filings with ROC license entities for ownership exposes
  • Build investigative leads by isolating licensees with active complaints in specific ZIPs

Real Estate, Property Management & PropTech

Brokerages, iBuyers, property managers, HOAs, and PropTech platforms use AZ ROC data to:

  • Maintain pre-vetted vendor directories of licensed plumbers, HVAC techs, roofers, pool service contractors per metro
  • Auto-route maintenance requests to in-network contractors with valid licences and bonds
  • Vet contractors for HOA project bids — confirm classification scope before awarding work
  • Score listing photos / inspection findings against contractor licence history to flag unpermitted work risk
  • Support iBuyer pre-purchase inspection workflows with same-day contractor verification

Government Contracting & Public Works

State agencies, ADOT prime contractors, municipal procurement teams, and Tribal Nation construction managers use the data to:

  • Validate bidder responsibility in compliance with Arizona Procurement Code
  • Confirm classification scope matches the project's scope of work
  • Pre-screen DBE / SBE subcontractors for licensing prerequisites
  • Audit prevailing-wage compliance by cross-referencing licensee personnel
  • Maintain pre-qualified contractor pools with continuous licence and bond monitoring

Construction Tech, Marketplaces & Lead Networks

Platforms like Houzz, Thumbtack, Angi, HomeAdvisor, Porch, BuildZoom, Procore, and ServiceTitan use AZ ROC data to:

  • License-gate contractor onboarding — block sign-ups with Expired, Suspended, or Revoked status
  • Power "verified" trust badges on contractor profiles
  • Run monthly relicensure sweeps across their entire AZ contractor base
  • Match consumer requests to contractors with the right classification scope
  • Enrich seller / pro accounts with bond, complaint, and personnel data

Academic & Workforce Research

Construction-management programs, urban planning faculty, labor economists, and policy researchers use the dataset to:

  • Quantify contractor density by metro, by trade, by classification
  • Study new-license issuance trends through downturns and booms
  • Map QP-shortage hotspots for workforce-development programs
  • Analyze complaint-to-license ratios as a proxy for industry quality
  • Track entity-type evolution (Sole Prop vs LLC vs Corp) over time

Sample Queries & Recipes

Recipe 1: All active general residential contractors (B-1) in the Phoenix metro

{
"cities": ["Phoenix", "Scottsdale", "Mesa", "Chandler", "Tempe", "Glendale", "Gilbert", "Peoria"],
"licenseClassification": "B-1",
"licenseStatus": "ACTIVE",
"scrapeDetailPage": true,
"scrapeComplaints": true
}

Recipe 2: Every HVAC (C-39) commercial contractor statewide for B2B sales

{
"cities": ["Phoenix", "Tucson", "Mesa", "Flagstaff", "Yuma", "Prescott", "Sierra Vista"],
"licenseClassification": "C-39",
"licenseType": "COMMERCIAL",
"licenseStatus": "ACTIVE"
}

Recipe 3: Direct lookup of specific licence numbers (fastest mode)

{
"licenseNumbers": ["099999", "088888", "077777", "066666"],
"scrapeDetailPage": true,
"scrapeComplaints": true
}

Recipe 4: Bond-monitoring sweep — find all contractors whose bond is expiring soon

{
"cities": ["Phoenix"],
"licenseStatus": "ACTIVE",
"scrapeDetailPage": true,
"scrapeComplaints": false
}

Then filter downstream:

from datetime import date, timedelta
cutoff = (date.today() + timedelta(days=60)).isoformat()
expiring_bonds = [
r for r in records
if r.get("bondExpirationDate") and r["bondExpirationDate"] <= cutoff
]

Recipe 5: Disciplinary watchlist — contractors with open or disciplined complaints

{
"cities": ["Phoenix", "Tucson"],
"licenseStatus": "ACTIVE",
"scrapeDetailPage": true,
"scrapeComplaints": true
}

Then post-filter:

flagged = [
r for r in records
if (r.get("openCases") or 0) > 0 or (r.get("disciplinedCases") or 0) > 0
]

Recipe 6: Qualifying-party lookup for a specific individual

{
"qualifyingPartyNames": ["John Smith"],
"scrapeDetailPage": true
}

Recipe 7: Sample mode — pull 25 records before committing to a full crawl

{
"cities": ["Scottsdale"],
"licenseStatus": "ACTIVE",
"maxResultsPerSearch": 25,
"scrapeDetailPage": true
}

Recipe 8: List-only fast crawl (no detail pages) — best for bulk identity discovery

{
"cities": ["Phoenix", "Tucson", "Mesa"],
"licenseStatus": "ACTIVE",
"scrapeDetailPage": false,
"resultsPerPage": "50",
"maxConcurrency": 5
}

Integration Examples

Google Sheets

  1. Schedule this actor on Apify (daily, weekly, or custom cron)
  2. Add the official Export to Google Sheets integration to the schedule
  3. A fresh Arizona contractor sheet lands in your Drive on every run — perfect for sales ops or compliance ops dashboards

Make.com / Zapier / n8n

Use the Apify connector available on every major automation platform. Trigger downstream automations on:

  • New contractor licences (today's run minus yesterday's)
  • Status changes (ActiveSuspended / Expired)
  • Bond status changes (ActiveCancelled)
  • New complaint records on tracked contractors
  • Renewal-window alerts at 90 / 60 / 30 days

Power BI / Tableau / Looker / Metabase

Connect the Apify dataset REST endpoint as a data source and refresh on schedule. Useful dashboards:

  • Active contractor count by metro, by classification
  • Bond-status heatmap by ZIP
  • Complaint density by trade
  • New-licensee velocity quarter over quarter
  • QP coverage gaps (licensees with no current qualifying party)

Postgres / Snowflake / BigQuery / Redshift

Use the Apify webhook integration to POST run results directly to your warehouse ingestion endpoint after each scheduled run. The flat output schema maps cleanly to a single az_contractors table; classifications, personnel, and complaints are JSONB columns.

Salesforce / HubSpot / Pipedrive CRM Enrichment

Run this actor nightly and upsert into Account records keyed on licenseNumber. Trigger:

  • New Opportunity creation on net-new licensees
  • Risk-score updates on bond or complaint changes
  • Renewal Tasks at configurable expiration thresholds
  • QP-change alerts on accounts you sponsor

Slack / Microsoft Teams / Email Alerts

Wire the dataset to a webhook that diffs runs and posts to channels:

  • #new-contractors-az — every new licence this week
  • #risk-alerts — every status downgrade or bond cancellation
  • #renewals — every licence expiring in the next 30 days

Construction-tech & Field Service Apps (Procore, ServiceTitan, BuilderTrend)

Use the Apify Node.js SDK to enrich vendor and subcontractor records during onboarding. Reject onboarding flows for any contractor whose licenseStatus !== "Active" or whose bondStatus !== "Active".


Major Arizona Markets & Regional Coverage

The actor works statewide. Below are the highest-volume Arizona metros and the contractor-market context for each.

Metro / CityPopulationWhy It Matters for AZ ROC Data
Phoenix1.65MState capital, largest construction market — every general, plumbing, HVAC, solar, and roofing trade is densely represented
Tucson0.55MSecond-largest metro, strong commercial and university construction; high CR-class density
Mesa0.50MMajor East Valley hub for residential and remodel contractors
Chandler0.28MHigh concentration of tech-campus and data-center commercial contractors
Scottsdale0.24MPremium residential, custom homes, swimming pool (C-42 / K-42), and landscape contractors
Gilbert0.27MFast-growing East Valley town with strong B-1 builder activity
Glendale0.25MWest Valley sports + commercial cluster
Tempe0.18MMixed-use, university-adjacent, light commercial
Peoria0.20MBedroom community, residential remodel-heavy market
Surprise0.15MActive-adult and retirement community construction
Flagstaff0.075MMountain construction, snow-load specialties, high-altitude HVAC
Yuma0.10MAgricultural construction, border-region commercial
Prescott0.045MHigh-elevation residential, custom homes
Sierra Vista0.044MMilitary-adjacent (Fort Huachuca) commercial
Lake Havasu City0.058MLakefront residential, marina construction, recreational
Casa Grande0.057MIndustrial / logistics build-out corridor between Phoenix and Tucson
Sedona0.010MHigh-end custom residential and resort construction
Bullhead City0.041MBorder-region commercial and residential
Goodyear0.10MWest Valley industrial and warehouse construction boom
Buckeye0.11MFastest-growing US city — explosive new-construction activity

Use any of these as values in the cities input array to scrape every contractor with a business address in that locality.


Cost & Performance

MetricValue
EnginePlaywright (Chromium) on Salesforce Experience Cloud
Runtime — single licence lookup (with detail page)15–40 seconds
Runtime — city-wide scrape (e.g. all active Phoenix)10–40 minutes depending on detail-page volume
Runtime — list-only fast crawl (no detail)1–10 minutes per city
Pricing modelPay-per-event (transparent per-record pricing)
Data freshnessLive at run time — pulled directly from AZ ROC portal
Auth requiredNone
Proxy requiredRecommended — Apify residential
Concurrency1–10 browser tabs (default 3)
Memory footprint2–4 GB recommended for default concurrency
Retries3 automatic per request with session marking
Pagination depthUnlimited — every Next click traversed until disabled
Output formatsJSON, CSV, Excel, HTML, XML, RSS, JSONL

  • Public data only. Every field is published by the Arizona Registrar of Contractors at azroc.gov under Arizona Public Records Law (A.R.S. § 39-121 et seq.). The data is intended for public consumption.
  • No PII beyond what AZ ROC publishes. The actor does not collect SSNs, dates of birth, driver's licence numbers, or financial information. Qualifying party names and business addresses are the same fields AZ ROC displays on every public detail page.
  • No PHI / HIPAA scope. This is contractor regulatory data, not healthcare data.
  • No emails. AZ ROC does not publish licensee email addresses.
  • Business addresses, not residences. Address data reflects the address-of-record filed with AZ ROC, which in most cases is a business location. Sole proprietors may file home addresses — consumers of this data should treat addresses respectfully and avoid harassment.
  • TCPA / CAN-SPAM responsibility. If you contact licensees via phone, SMS, or email, compliance with TCPA, CAN-SPAM, the Arizona Telephone Solicitation Act, DNC scrubs, and CCPA / GDPR (where applicable) is the responsibility of the data consumer — not the scraper.
  • Robots.txt and ToS. The AZ ROC portal exposes the contractor-search functionality publicly without authentication; the actor mirrors the same human-accessible UI rather than abusing a private API. Rate-limit yourself responsibly.
  • No resale of raw output. Reselling raw scraped data as a substitute for the AZ ROC portal may violate state terms. Adding value (enrichment, dashboards, alerts, integrations) is the appropriate use pattern.
  • Indemnity. The actor and its author make no warranty as to fitness for any particular purpose. Verify any single legal or licensing decision against the live AZ ROC portal before relying on it in court, in underwriting, or in contracting decisions.

Important: AZ ROC data must not be used for unlawful purposes including identity fraud, stalking, harassment, or discrimination. Always provide a clear opt-out path for commercial outreach.


Frequently Asked Questions

How fresh is the data?

The data is live at run time — the actor queries the AZ ROC portal directly each time it runs. There is no cache. If a licence status changed an hour ago, your run reflects it.

How many records will I get?

It depends on your query. A single licenseNumbers lookup returns 1 record. A city-wide search like Phoenix with licenseStatus: ALL can return thousands of records across many paginated pages. A classification-filtered statewide sweep can return tens of thousands. The actor traverses every page until the Next button is disabled.

Does this scraper require login or AZ ROC credentials?

No. AZ ROC's contractor-search portal is fully public. You only need an Apify account to run the actor.

Why does the actor use residential proxies?

The AZ ROC portal runs on Salesforce Experience Cloud, which applies aggressive bot detection. Datacenter proxies and unrotated IPs are flagged and blocked within minutes of bulk crawling. Residential proxies look like real consumer connections and pass cleanly.

Can I run it without proxies?

Yes for small runs (one or two licence lookups). For any bulk crawl, residential proxies are strongly recommended — without them you will see CAPTCHAs and 403s.

Does the actor handle CAPTCHAs?

The portal does not throw interactive CAPTCHAs under normal usage, but Salesforce sometimes injects challenge interstitials when it detects automation. The actor's fingerprinting plus residential proxies are designed to avoid triggering those challenges in the first place. The retry logic recovers when they do appear.

How deep does pagination go?

Unlimited. The actor clicks Next until the button is disabled. Large cities like Phoenix can have dozens of pages — all are traversed.

What's the difference between licenseType and primaryClassification?

licenseType is the broad category — Residential, Commercial, or Dual. primaryClassification is the specific endorsement code (e.g. B-1 General Residential, C-37 Plumbing, R-11 Electrical). A single contractor can hold multiple classifications.

What does "qualifying party" mean?

The Qualifying Party (QP) is the individual whose construction experience and exam pass the AZ ROC uses to qualify the licence. The QP is legally responsible for the work performed under the licence. If a QP leaves a company, the licence becomes vulnerable to suspension.

Can I get complaint history beyond 2 years?

No — AZ ROC only displays complaints from the prior two years on the public portal. To build a longer history, schedule this actor monthly and archive each run.

Can I filter by expiration date?

The actor returns expirationDate / renewedThroughDate as fields. Filter downstream (SQL WHERE, Python comprehension, Sheets filter).

Does the actor deduplicate across multiple queries?

Yes. Records are deduplicated by AZ ROC licenseId. Running with cities: ["Phoenix", "Scottsdale"] and companyNames: ["Acme"] will not double-count a contractor that matches both.

Are bond amounts always populated?

Bond fields are populated when the contractor's detail page exposes them — most active commercial and residential licensees do. Cancelled or expired licences sometimes lack current bond data.

Does this dataset include closed / inactive contractors?

Yes — set licenseStatus: "ALL" (or EXPIRED, SUSPENDED, REVOKED, CANCELLED) to include them. Useful for historical analysis, churn studies, and disciplinary trend research.

Does this actor work on the Apify Free Plan?

Yes — full functionality on the free tier. Bulk crawls of large cities benefit from a paid plan with more memory and residential-proxy bandwidth.

Can I schedule it to run automatically?

Yes. Use the Apify Scheduler to run hourly, daily, weekly, or on any cron expression. Combine with webhook delivery or Google Sheets export for fully hands-off pipelines.

What formats can I export the data in?

JSON, CSV, Excel (XLSX), HTML, XML, RSS, and JSON Lines — all directly from the Apify dataset view or API.

Does this work for contractor licensing in other states?

No — this actor is specific to Arizona Registrar of Contractors. We maintain separate scrapers for other state licensing boards (North Carolina General Contractors, Washington L&I, California DCA, Virginia DPOR, Colorado DORA, Minnesota DLI, Ohio eLicense, Illinois IDFPR). See the Related Actors section below.

How do I report a bug or request a feature?

Open an Issue on the Apify Store actor page or contact the developer directly via the Apify Console.

What happens if the AZ ROC portal changes its HTML?

The actor uses label-anchored parsing (looks for "Business Entity Name", "First Issued", "Bond Type" labels rather than fragile DOM paths) which survives most cosmetic changes. Structural changes are patched within 24–48 hours of report.


If you work across multiple US licensing jurisdictions or need adjacent regulatory data, these sibling actors pair well with AZ ROC:


Comparison vs. Alternatives

ApproachSetup TimeBond DataComplaint DataPaginationCost (1K records)Maintenance
This actor< 2 minutesIncludedIncludedFull traversalCents to low dollarsZero
Manual portal lookupN/AYes (one at a time)Yes (one at a time)ManualFree, but ~30 sec/recordNone
Custom Playwright script2–5 days devDIY parsingDIY parsingDIYFree + infraConstant
AZ ROC public-records requestDays–weeksSometimesSometimesN/AVariable feesNone
Paid contractor-data APIsHoursOftenOftenYes$500–$5,000+/monthNone
Scraping aggregator screen-scrapeDaysInconsistentInconsistentVariable$$$Constant

This actor is the only option that combines same-day deployment, bond + complaint enrichment, full pagination, and pay-per-event pricing — without a long-term subscription or custom code.


Why Pay-Per-Event Pricing?

Most contractor-data tools charge monthly subscriptions ranging from a few hundred to several thousand dollars — whether or not you use them. This actor uses pay-per-event pricing instead:

  • You only pay when the actor runs and produces records
  • Charges scale with actual data consumed, not arbitrary seat counts
  • Transparent line-item billing inside the Apify console
  • No monthly minimums, no annual contracts, no overage surprises
  • Free to evaluate — sample with maxResultsPerSearch: 10 for pennies
  • Cancel anytime by not running it; no lock-in

Changelog

VersionDateNotes
1.2.02026-05Full pagination, residential-proxy default, complaint history enrichment, fingerprint generator, classification enum filter
1.1.02026-04Detail-page enrichment for bond, personnel, classifications
1.0.02026-03Initial public release — list-mode search by licence number, business name, QP, or city

Keywords

Arizona ROC scraper · Arizona Registrar of Contractors scraper · AZ ROC scraper · Arizona contractor license lookup · AZ contractor license verification · Arizona ROC verification · Arizona contractor license API · azroc.gov scraper · azroc.my.site.com scraper · Phoenix contractor data · Phoenix contractor license lookup · Tucson contractor scraper · Mesa contractor lookup · Scottsdale contractor data · Chandler contractor license · Gilbert contractor verification · Glendale contractor data · Tempe contractor scraper · Arizona general contractor lookup · Arizona residential contractor scraper · Arizona commercial contractor scraper · Arizona dual contractor license · AZ ROC bond lookup · Arizona contractor bond scraper · Arizona contractor complaint scraper · ROC complaint history · Arizona qualifying party lookup · Arizona contractor classification lookup · B-1 general residential Arizona · C-37 plumbing contractor Arizona · C-39 HVAC contractor Arizona · R-11 electrical contractor Arizona · CR classification Arizona scraper · Arizona contractor lead generation · Arizona construction lead data · AZ contractor B2B leads · Arizona contractor CRM enrichment · Arizona contractor underwriting data · Arizona surety bond data · Arizona construction compliance scraper · Apify Arizona contractor actor · AZ ROC Salesforce scraper · Arizona contractor license verification API · contractor verification automation Arizona · Phoenix HVAC contractor list · Scottsdale custom home builder lookup · Apify contractor licensing scraper


Support

  • Bug reports: Open an Issue on the Apify Store actor page
  • Feature requests: Same place — please describe your use case so prioritization can match real demand
  • Direct contact: Reach the developer through the Apify Console messaging system

If this actor saves you time, a 5-star rating on the Apify Store helps other contractors, insurers, lenders, and compliance teams discover it. Thank you!