Arizona ROC Contractor License Scraper
Pricing
from $6.00 / 1,000 results
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
Maintained by CommunityActor stats
0
Bookmarked
13
Total users
7
Monthly active users
3 days ago
Last modified
Categories
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.
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 (
&, ,') 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
- Click "Try for free" on the Apify Store page
- Enter one or more license numbers, company names, qualifying parties, or Arizona cities into the corresponding input fields
- 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
- Download the dataset as JSON, CSV, Excel, HTML, XML, or RSS directly from the Apify dataset view
API Run (Python)
from apify_client import ApifyClientclient = 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:
| Step | Engine | What Happens |
|---|---|---|
| Navigate | Playwright (Chromium) | Opens https://azroc.my.site.com/AZRoc/s/contractor-search and waits for the Aura runtime to hydrate |
| Search | Playwright | Types the query into input[name="input1"], applies advanced filters (type, status, classification) if requested, clicks the Search button |
| Page size | Playwright | Switches the results <select> to 50 rows per page to minimize Next clicks |
| Paginate | Playwright | Clicks the Next button (button.slds-button.right-btn) until disabled — every page is traversed |
| Parse list | HTML + regex | Extracts License No, Business Name, Qualifying Party, Class, Status, City/State/ZIP, Phone from data-label columns |
| Open detail | Playwright | Optionally opens each ?licenseId=... profile URL to grab bond, complaint, personnel, classifications, entity type |
| Normalize | Node.js | Decodes HTML entities, parses dates into YYYY-MM-DD, splits addresses, deduplicates by licence ID, builds the canonical record |
| Output | Apify Dataset | Pushes each enriched record to the default dataset with scrapedAt timestamp |
Source endpoints
| URL | Purpose |
|---|---|
https://azroc.my.site.com/AZRoc/s/contractor-search | Public 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
PlaywrightCrawleron 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
licenseIdextracted 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:
&, ,',",<,>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
| Parameter | Type | Default | Description |
|---|---|---|---|
licenseNumbers | array<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. |
companyNames | array<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. |
qualifyingPartyNames | array<string> | [] | Full name of the qualifying party, the individual legally responsible for the licence. Format First Last. Partial names allowed. |
cities | array<string> | [] | Arizona cities to search by location (e.g. Phoenix, Tucson, Mesa, Scottsdale). Large cities may return thousands of records — every page is traversed. |
licenseType | enum | ALL | One of ALL, RESIDENTIAL, COMMERCIAL, DUAL. Filters the advanced-search type dropdown. |
licenseStatus | enum | ALL | One of ALL, ACTIVE, SUSPENDED, EXPIRED, REVOKED, CANCELLED. Filters by current standing. |
licenseClassification | string | "" | Optional classification code filter (e.g. B-1, R-11, C-37, CR-39). Leave blank to return all classifications. |
maxResultsPerSearch | integer | 0 | Cap records per individual search query. 0 = unlimited (scraper paginates until Next is disabled). |
resultsPerPage | enum | "50" | Page size in the AZ ROC native dropdown. One of "10", "20", "50". 50 minimizes the number of Next clicks. |
scrapeDetailPage | boolean | true | If true, opens every contractor's detail page for full bond, complaint, classification, and personnel data. Disable for fast list-only crawls. |
scrapeComplaints | boolean | true | If 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. |
maxConcurrency | integer | 3 | Max 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. |
proxyConfiguration | object | Apify residential | Standard 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
| Field | Type | Description |
|---|---|---|
licenseNumber | string | ROC license number (e.g. 099999) — leading zeros preserved |
licenseType | string | null | Residential, Commercial, Dual, or contractor-type label from detail page |
licenseStatus | string | null | Normalized license standing — see Status Reference below |
businessName | string | null | Legal business entity name |
dbaName | string | null | "Doing Business As" name where present |
qualifyingParty | string | null | Individual responsible for the licence |
entityType | string | null | Corporation, LLC, LP, Sole Proprietorship, Joint Venture, etc. |
personnel | array | null | Officers, members, partners, qualifying party — each with name and role (or position) |
Classification fields
| Field | Type | Description |
|---|---|---|
primaryClassification | string | null | Top classification code (e.g. B-1, R-11, C-37) |
classificationDesc | string | null | Plain-English description of the primary classification |
classifications | array | null | Full list of every classification held — each item { code, description } |
Address & contact
| Field | Type | Description |
|---|---|---|
city | string | null | Business city |
state | string | null | State (almost always AZ) |
zip | string | null | ZIP code |
phone | string | null | Business phone — detail-page records are formatted (XXX) XXX-XXXX |
mailingAddress | string | null | Mailing address when distinct from business address |
Lifecycle dates
| Field | Type | Description |
|---|---|---|
issuedDate | string | null | First-issued date in YYYY-MM-DD |
renewedThroughDate | string | null | Current renewal expiration in YYYY-MM-DD |
expirationDate | string | null | License expiration in YYYY-MM-DD |
Bond information
| Field | Type | Description |
|---|---|---|
bondType | string | null | Contractor bond type (e.g. License Bond) |
bondStatus | string | null | Active, Cancelled, Expired, etc. |
bondAmount | string | null | Bond face amount, formatted as $ {amount} |
bondCompany | string | null | Surety company name |
bondNumber | string | null | Surety bond number |
bondEffectiveDate | string | null | Bond effective date YYYY-MM-DD |
bondExpirationDate | string | null | Bond expiration date YYYY-MM-DD |
Complaint history (last 2 years exposed by AZ ROC)
| Field | Type | Description |
|---|---|---|
openCases | integer | null | Count of open complaints |
disciplinedCases | integer | null | Count of complaints resulting in discipline |
resolvedCases | integer | null | Count of resolved / settled complaints |
complaintCount | integer | null | Total complaint count across all categories |
complaints | array | null | Per-complaint detail — { complaintId, type, outcome } |
Metadata
| Field | Type | Description |
|---|---|---|
profileUrl | string | null | Direct deep link to the contractor's AZ ROC detail page |
scrapedAt | string | ISO-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
| Status | Meaning |
|---|---|
Active | License in good standing, contractor may bid and build |
Active - Probation | Active but subject to Board-imposed conditions |
Pending Renewal | Renewal application in process |
Inactive / restricted statuses — contractor MAY NOT legally work
| Status | Meaning |
|---|---|
Suspended | Temporarily barred from contracting |
Expired | License lapsed; renewal not completed |
Cancelled | Licence cancelled (often voluntary) |
Revoked | Permanently terminated by ROC action |
Surrendered | Voluntarily surrendered to ROC, sometimes pre-disciplinary |
Tip: Use
licenseStatus: "ACTIVE"to receive only currently authorized contractors. Combine withbondStatusfiltering 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.
| Prefix | Scope | Example Codes |
|---|---|---|
A | General Engineering | A, A-1 through A-21 (heavy civil, paving, well drilling, etc.) |
B | General Commercial / Residential | B, B-1 (General Residential), B-2 (General Small Commercial), B-3 (Dual) |
C | Commercial Specialty | C-37 (Plumbing), C-39 (HVAC), C-11 (Electrical), C-16 (Roofing), C-9 (Drywall), C-42 (Pool), C-78 (Solar) |
CR | Commercial / Residential Specialty (Dual) | CR-1 through CR-79 covering all combined trades |
K | Specialty (Residential) | K-37 (Plumbing), K-39 (HVAC), K-11 (Electrical), K-42 (Pool) |
L | Specialty | Misc specialty endorsements |
R | Residential Specialty | R-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 changes —
ActivetoCancelledis a leading indicator of contractor distress - Adjust pricing for complaint history —
disciplinedCases > 0is a hard underwriting signal - Cross-check qualifying party against named-insured records to detect QP swaps
- Trigger renewal outreach automatically when
renewedThroughDatefalls 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-11electrician hold the right endorsement for solar work? - Detect look-alike scams — match
businessNameagainst 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
scrapedAtproof 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, orRevokedstatus - 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, timedeltacutoff = (date.today() + timedelta(days=60)).isoformat()expiring_bonds = [r for r in recordsif 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 recordsif (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
- Schedule this actor on Apify (daily, weekly, or custom cron)
- Add the official Export to Google Sheets integration to the schedule
- 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 (
Active→Suspended/Expired) - Bond status changes (
Active→Cancelled) - 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 / City | Population | Why It Matters for AZ ROC Data |
|---|---|---|
| Phoenix | 1.65M | State capital, largest construction market — every general, plumbing, HVAC, solar, and roofing trade is densely represented |
| Tucson | 0.55M | Second-largest metro, strong commercial and university construction; high CR-class density |
| Mesa | 0.50M | Major East Valley hub for residential and remodel contractors |
| Chandler | 0.28M | High concentration of tech-campus and data-center commercial contractors |
| Scottsdale | 0.24M | Premium residential, custom homes, swimming pool (C-42 / K-42), and landscape contractors |
| Gilbert | 0.27M | Fast-growing East Valley town with strong B-1 builder activity |
| Glendale | 0.25M | West Valley sports + commercial cluster |
| Tempe | 0.18M | Mixed-use, university-adjacent, light commercial |
| Peoria | 0.20M | Bedroom community, residential remodel-heavy market |
| Surprise | 0.15M | Active-adult and retirement community construction |
| Flagstaff | 0.075M | Mountain construction, snow-load specialties, high-altitude HVAC |
| Yuma | 0.10M | Agricultural construction, border-region commercial |
| Prescott | 0.045M | High-elevation residential, custom homes |
| Sierra Vista | 0.044M | Military-adjacent (Fort Huachuca) commercial |
| Lake Havasu City | 0.058M | Lakefront residential, marina construction, recreational |
| Casa Grande | 0.057M | Industrial / logistics build-out corridor between Phoenix and Tucson |
| Sedona | 0.010M | High-end custom residential and resort construction |
| Bullhead City | 0.041M | Border-region commercial and residential |
| Goodyear | 0.10M | West Valley industrial and warehouse construction boom |
| Buckeye | 0.11M | Fastest-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
| Metric | Value |
|---|---|
| Engine | Playwright (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 model | Pay-per-event (transparent per-record pricing) |
| Data freshness | Live at run time — pulled directly from AZ ROC portal |
| Auth required | None |
| Proxy required | Recommended — Apify residential |
| Concurrency | 1–10 browser tabs (default 3) |
| Memory footprint | 2–4 GB recommended for default concurrency |
| Retries | 3 automatic per request with session marking |
| Pagination depth | Unlimited — every Next click traversed until disabled |
| Output formats | JSON, CSV, Excel, HTML, XML, RSS, JSONL |
Compliance, Privacy & Legal Notes
- Public data only. Every field is published by the Arizona Registrar of Contractors at
azroc.govunder 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.
Related Apify Actors by Haketa
If you work across multiple US licensing jurisdictions or need adjacent regulatory data, these sibling actors pair well with AZ ROC:
- North Carolina Licensing Board for General Contractors Scraper — NC general contractor licences
- Washington L&I Contractor License Scraper — WA contractor + bond data
- Colorado Professional License Scraper — CO DORA professional licences
- Virginia DPOR Professional License Scraper — VA regulated occupations including contractors
- Minnesota DLI Professional License Scraper — MN Department of Labor & Industry licences
- California DCA Professional License Scraper — California Department of Consumer Affairs licences
- Ohio eLicense Scraper — all Ohio professional licences
- Illinois IDFPR License Scraper — Illinois professional regulation
- Texas Pharmacy License Scraper (TSBP) — Texas State Board of Pharmacy
- TTB Alcohol Permittee Scraper — federal alcohol permittees (TTB)
- SAM.gov Federal Contractor Entity Scraper — federal contractor registrations
- BBB Business Scraper — Better Business Bureau ratings & complaints
Comparison vs. Alternatives
| Approach | Setup Time | Bond Data | Complaint Data | Pagination | Cost (1K records) | Maintenance |
|---|---|---|---|---|---|---|
| This actor | < 2 minutes | Included | Included | Full traversal | Cents to low dollars | Zero |
| Manual portal lookup | N/A | Yes (one at a time) | Yes (one at a time) | Manual | Free, but ~30 sec/record | None |
| Custom Playwright script | 2–5 days dev | DIY parsing | DIY parsing | DIY | Free + infra | Constant |
| AZ ROC public-records request | Days–weeks | Sometimes | Sometimes | N/A | Variable fees | None |
| Paid contractor-data APIs | Hours | Often | Often | Yes | $500–$5,000+/month | None |
| Scraping aggregator screen-scrape | Days | Inconsistent | Inconsistent | Variable | $$$ | 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: 10for pennies - Cancel anytime by not running it; no lock-in
Changelog
| Version | Date | Notes |
|---|---|---|
| 1.2.0 | 2026-05 | Full pagination, residential-proxy default, complaint history enrichment, fingerprint generator, classification enum filter |
| 1.1.0 | 2026-04 | Detail-page enrichment for bond, personnel, classifications |
| 1.0.0 | 2026-03 | Initial 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!