# Arizona ROC Contractor License Scraper (`parsebird/az-roc-contractor-license-scraper`) Actor

Look up Arizona Registrar of Contractors licenses by number, company, qualifying party, or city. Get status, bond, classification, personnel, and complaint history. Export as JSON, CSV, or Excel.

- **URL**: https://apify.com/parsebird/az-roc-contractor-license-scraper.md
- **Developed by:** [ParseBird](https://apify.com/parsebird) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.19 / 1,000 license records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### Arizona ROC Contractor License Scraper

Look up **[Arizona Registrar of Contractors](https://azroc.my.site.com/AZRoc/s/contractor-search)** (AZ ROC) license records by license number, company name, qualifying party, or city. The Arizona ROC Contractor License Scraper pulls license status, bond details, classification, personnel, and complaint history for any Arizona contractor, with no login and no AZ ROC API key.

<table><tr>
<td style="border-left:4px solid #1C1917;padding:12px 16px;font-weight:600">
Search by license number, company, qualifying party, or city, filter by classification, status, and type, then get full bond, personnel, and complaint-history data straight from AZ ROC's own records.
</td>
</tr></table>

##### Copy to your AI assistant

Copy this block into ChatGPT, Claude, Cursor, or any LLM to start using this actor.

```
Actor: parsebird/az-roc-contractor-license-scraper (Apify). Looks up Arizona Registrar of Contractors (AZ ROC) contractor licenses. Call with ApifyClient.
Input JSON fields: licenseNumbers: string[] — exact ROC license numbers, e.g. ["333318"] (leading zeros added automatically to 6 digits); companyNames: string[] — partial business name matches; qualifyingPartyNames: string[] — partial name matches for the individual responsible for the license; cities: array<string> — Arizona cities to search by mailing address; licenseClassification: string — optional classification code, e.g. "C-37" (see the Classification Reference in the README); licenseType: "ALL"|"RESIDENTIAL"|"COMMERCIAL"|"DUAL" (default ALL); licenseStatus: "ALL"|"ACTIVE"|"SUSPENDED"|"EXPIRED"|"REVOKED"|"CANCELLED" (default ALL); maxResultsPerSearch: int (default 0 = unlimited); scrapeDetailPage: bool (default true) — full bond/personnel/complaint data; scrapeComplaints: bool (default true); maxConcurrency: int 1-10 (default 3); proxyConfiguration: object (default residential).
Output: one dataset item per license — licenseNumber, licenseType, licenseStatus, businessName, dbaName, qualifyingParty, entityType,
  personnel, primaryClassification, classificationDesc, classifications, city, state, zip, phone, issuedDate, renewedThroughDate,
  expirationDate, bondType, bondStatus, bondAmount, bondCompany, bondNumber, bondEffectiveDate, openCases, disciplinedCases,
  resolvedCases, complaintCount, complaints, profileUrl, searchQuery, scrapedAt.
Example: { "licenseNumbers": ["333318"], "cities": ["Tucson"], "licenseClassification": "C-37", "licenseStatus": "ACTIVE" }
API: https://api.apify.com/v2/acts/parsebird~az-roc-contractor-license-scraper  ·  Token: https://console.apify.com/account/integrations
```

### What does Arizona ROC Contractor License Scraper do?

The [Arizona Registrar of Contractors](https://roc.az.gov) licenses every contractor legally allowed to work in Arizona. There is no public AZ ROC API — this scraper reads the same public search backend the AZ ROC contractor-search website itself uses. For every matching license it extracts:

- 🏷️ **License identity** — number, type, status, business name, DBA name, entity type, and qualifying party.
- 👥 **Personnel** — officers, members, partners, and the qualifying party, each with their role.
- 🧾 **Classification** — the license's classification code and plain-English description (e.g. `C-37` → Plumbing).
- 💰 **Bond information** (optional) — bond type, status, amount, surety company, and bond number.
- ⚠️ **Complaint history** (optional) — open, disciplined, and resolved case counts for the prior two years, as displayed by AZ ROC.

Common uses: vetting a contractor before hiring, verifying an active license and bond before signing a contract, due-diligence checks for lenders and insurers, and building a local dataset of licensed contractors by city or trade.

### Input parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| licenseNumbers | array | No | `[]` | ROC license numbers to look up directly. Leading zeros added automatically to make 6 digits. Fastest, most precise mode. |
| companyNames | array | No | `[]` | Business names to search. Partial matches accepted. Each name is its own search. |
| qualifyingPartyNames | array | No | `[]` | Full name of the qualifying party (format: First Last). Partial names allowed. |
| cities | array | No | `[]` | Arizona cities to search by mailing address, e.g. `Phoenix`, `Tucson`. Must match AZ ROC's exact spelling on file. |
| licenseClassification | string | No | `""` | Classification code filter, e.g. `B-1`, `R-11`, `C-37`. See the Classification Reference below. |
| licenseType | enum | No | `ALL` | One of `ALL`, `RESIDENTIAL`, `COMMERCIAL`, `DUAL`. |
| licenseStatus | enum | No | `ALL` | One of `ALL`, `ACTIVE`, `SUSPENDED`, `EXPIRED`, `REVOKED`, `CANCELLED`. |
| maxResultsPerSearch | integer | No | 0 | Cap records per individual search query. 0 = unlimited. |
| resultsPerPage | enum | No | `"50"` | Kept for input compatibility only — see the FAQ for why it has no effect. |
| scrapeDetailPage | boolean | No | true | Fetch each license's full bond, complaint, classification, and personnel data. |
| scrapeComplaints | boolean | No | true | Capture complaint history (requires `scrapeDetailPage`). AZ ROC only shows the prior two years. |
| maxConcurrency | integer | No | 3 | Max concurrent requests to AZ ROC's search backend (1-10). |
| proxyConfiguration | object | No | Residential | Apify Proxy settings. |

#### Example inputs

Direct license lookup:

```json
{
  "licenseNumbers": ["333318"]
}
```

City + classification, active only:

```json
{
  "cities": ["Tucson"],
  "licenseClassification": "C-37",
  "licenseStatus": "ACTIVE"
}
```

Fast list-only crawl by company name:

```json
{
  "companyNames": ["Acme Plumbing"],
  "scrapeDetailPage": false
}
```

Full detail with complaint history:

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

### What data can you extract from AZ ROC?

#### Core fields

| Field | Description |
|-------|-------------|
| licenseNumber | ROC license number (e.g. `333318`) |
| licenseType | Residential, Commercial, Dual, or General Engineering — derived from the classification's own description |
| licenseStatus | Active, Suspended, Expired, Revoked, Cancelled, Inactive, etc. |
| businessName | Legal business entity name |
| dbaName | "Doing Business As" name where present |
| qualifyingParty | Individual responsible for the license |
| entityType | AZ ROC's own entity-type label (e.g. `LLC`, `Corporation`) |
| personnel | Officers, members, partners, qualifying party — each with name and role |

#### Classification fields

| Field | Description |
|-------|-------------|
| primaryClassification | Classification code (e.g. `B-1`, `R-11`, `C-37`) |
| classificationDesc | Plain-English description of the classification |
| classifications | Array of `{ code, description }` — AZ ROC issues each classification as its own separate license number, so this typically holds one entry matching `primaryClassification` |

#### Address, contact & lifecycle

| Field | Description |
|-------|-------------|
| city / state / zip | Business mailing address |
| phone | Formatted as `(XXX) XXX-XXXX` when the source has 10 digits |
| issuedDate | First-issued date, `YYYY-MM-DD` |
| renewedThroughDate / expirationDate | AZ ROC exposes a single forward-looking "Renewed Through" date; both fields carry that same value |

#### Bond information (with `scrapeDetailPage`)

| Field | Description |
|-------|-------------|
| bondType | Contractor bond type (e.g. `Surety`) |
| bondStatus | Active, Cancelled, Expired, etc. |
| bondAmount | Bond face amount, formatted as `$ {amount}` |
| bondCompany | Surety company name |
| bondNumber | Surety bond number |
| bondEffectiveDate | Bond effective date, `YYYY-MM-DD` |

#### Complaint history (with `scrapeComplaints`, last 2 years exposed by AZ ROC)

| Field | Description |
|-------|-------------|
| openCases | Count of open complaints |
| disciplinedCases | Count of complaints resulting in discipline |
| resolvedCases | Count of resolved/settled complaints |
| complaintCount | Total complaint count |
| complaints | Per-complaint detail, when any exist |

#### Metadata

| Field | Description |
|-------|-------------|
| profileUrl | Direct link to the license's AZ ROC detail page |
| searchQuery | The input value that produced this record |
| scrapedAt | ISO-8601 timestamp of extraction |

### Output example

```json
{
  "licenseNumber": "333318",
  "licenseType": "Dual",
  "licenseStatus": "Active",
  "businessName": "Mike Robbins Plumbing LLC",
  "dbaName": "Phoenix Residential & Commercial Plumbing",
  "qualifyingParty": "Tyler Michael Robbins",
  "entityType": "LLC",
  "personnel": [
    { "name": "Tyler Michael Robbins", "role": "Qualifying Party" },
    { "name": "Michael A Robbins", "role": "Manager;Member" }
  ],
  "primaryClassification": "CR-37",
  "classificationDesc": "Plumbing",
  "classifications": [{ "code": "CR-37", "description": "Plumbing" }],
  "city": "Apache Junction",
  "state": "AZ",
  "zip": "85120",
  "phone": "(480) 529-4852",
  "issuedDate": "2021-05-12",
  "renewedThroughDate": "2027-05-31",
  "expirationDate": "2027-05-31",
  "bondType": "Surety",
  "bondStatus": "Active",
  "bondAmount": "$ 6,750",
  "bondCompany": "RLI Insurance Company",
  "bondNumber": "LSM1483204",
  "bondEffectiveDate": "2021-05-04",
  "openCases": 0,
  "disciplinedCases": 0,
  "resolvedCases": 0,
  "complaintCount": 0,
  "profileUrl": "https://azroc.my.site.com/AZRoc/s/contractor-search?licenseId=a0o8y0000004CYXAA2",
  "searchQuery": "333318",
  "scrapedAt": "2026-09-05T14:40:46.584Z"
}
```

Download the dataset as **JSON, CSV, Excel, HTML, or XML** from the Storage tab or the [Apify API](https://docs.apify.com/api/v2).

### Use cases

- **Pre-hire vetting** — confirm a contractor's license is Active and bonded before signing a contract.
- **Lender / insurer due diligence** — check license status, classification, and complaint history in bulk.
- **Market research** — pull every licensed contractor for a trade classification or city.
- **Compliance monitoring** — track qualifying parties and personnel across multiple licenses.

### How it works

1. **Search** — each `licenseNumbers`, `companyNames`, `qualifyingPartyNames`, or `cities` entry runs as its own search against AZ ROC's contractor-search backend.
2. **Flatten** — each matched business can hold multiple licenses; the scraper emits one row per license.
3. **Filter** — `licenseStatus`, `licenseType`, and `licenseClassification` are applied precisely on the client side (see the FAQ for why).
4. **Enrich (optional)** — with `scrapeDetailPage` on, each license's own detail record is fetched for bond, personnel, and (with `scrapeComplaints`) complaint history.
5. Rows stream to the dataset, deduplicated across all searches by license.

### How much does it cost to scrape AZ ROC?

This actor is **pay per result** — charged once per license record saved to the dataset, regardless of whether `scrapeDetailPage` is on.

| Plan | Price per 1,000 licenses |
|------|---------------------------|
| Free | **$2.99** |
| Bronze | **$2.79** |
| Silver | **$2.49** |
| Gold | **$2.19** |

A small platform **Actor start** fee also applies per run. Turn `scrapeDetailPage` off for a faster, list-only crawl at the same per-row price. Apify's monthly free platform usage covers small runs.

### How to look up AZ ROC contractors

1. Click **Try for free** and sign in to Apify.
2. Enter one or more **license numbers**, **company names**, **qualifying party names**, or **cities**.
3. Optionally set a **classification code**, **license type**, or **license status** filter.
4. Toggle **Scrape detail page** and **Scrape complaints** for full bond and complaint data.
5. Click **Start**, then watch rows appear in the **Output** tab.
6. Export from **Storage**, or pull results via the API.

#### Run it via API

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("parsebird/az-roc-contractor-license-scraper").call(run_input={
    "cities": ["Tucson"],
    "licenseClassification": "C-37",
    "licenseStatus": "ACTIVE",
})
for lic in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(lic["businessName"], "-", lic["licenseNumber"], "-", lic["licenseStatus"])
```

JavaScript:

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('parsebird/az-roc-contractor-license-scraper').call({
    licenseNumbers: ['333318'],
    scrapeDetailPage: true,
    scrapeComplaints: true,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

Schedule recurring runs, add webhooks, or push results to Google Sheets, Slack, Zapier, and Make with [Apify integrations](https://docs.apify.com/platform/integrations).

### Classification Reference

AZ ROC uses a letter-prefix classification system. The actor returns the raw code plus a plain-English description in `primaryClassification` / `classificationDesc`. This table is scraped directly from AZ ROC's own classification list.

| Prefix | Scope | Example codes |
|--------|-------|----------------|
| A | General Engineering | A, A-4 Drilling, A-9 Swimming Pools, A-14 Asphalt Paving |
| B | General Residential / Commercial | B General Residential, B-1 General Commercial, B-3 General Remodeling |
| C | Commercial Specialty | C-37 Plumbing, C-39 Air Conditioning and Refrigeration, C-11 Electrical, C-16 Fire Protection Systems, C-42 Roofing, C-78 Solar Plumbing |
| CR | Commercial/Residential Specialty (Dual) | CR-37 Plumbing, CR-39 Air Conditioning and Refrigeration, CR-11 Electrical, CR-42 Roofing |
| K | Dual (General) | KA Dual Engineering, KB-1 Dual Building Contractor, KB-2 Dual Residential and Small Commercial |
| R | Residential Specialty | R-11 Electrical, R-37 Plumbing (Including Solar), R-39 Air Conditioning and Refrigeration, R-62 Minor Home Improvements |

**Full code list used by `licenseClassification`:**

<details>
<summary>Show all 160+ classification codes</summary>

**A — General Engineering**
A General Engineering · A-4 Drilling · A-5 Excavating Grading and Oil Surfacing · A-7 Piers and Foundations · A-9 Swimming Pools · A-11 Steel and Aluminum Erection · A-12 Sewers Drains and Pipe Laying · A-14 Asphalt Paving · A-15 Seal Coating · A-16 Waterworks · A-17 Electrical and Transmission Lines · A-19 Swimming Pools, Including Solar

**B — General Residential / Commercial**
B General Residential Contractor · B-1 General Commercial Contractor · B-2 General Small Commercial Contractor · B-3 General Remodeling and Repair Contractor · B-4 General Residential Engineering Contractor · B-4R Sport Court Accessories · B-5 General Swimming Pool Contractor · B-5R Swimming Pool Covers · B-6 General Swimming Pool Contractor, Including Solar · B-10 Pre-Manufactured Spas and Hot Tubs

**C — Commercial Specialty**
C-1 Acoustical Systems · C-3 Awnings, Canopies, Carports and Patio Covers · C-4 Boilers, Steamfitting and Process Piping · C-6 Swimming Pool Service and Repair · C-7 Carpentry · C-8 Floor Covering · C-9 Concrete · C-10 Drywall · C-11 Electrical · C-12 Elevators · C-14 Fencing · C-15 Blasting · C-16 Fire Protection Systems · C-21 Hardscaping and Irrigation Systems · C-24 Ornamental Metals · C-27 Lightweight Partitions · C-31 Masonry · C-34 Painting and Wall Covering · C-36 Plastering · C-37 Plumbing · C-38 Signs · C-39 Air Conditioning and Refrigeration · C-40 Insulation · C-41 Septic Tanks and Systems · C-42 Roofing · C-45 Sheet Metal · C-48 Ceramic, Plastic and Metal Tile · C-49 Refrigeration · C-53 Water Well Drilling · C-54 Water Conditioning Equipment · C-56 Welding · C-57 Wrecking · C-58 Comfort Heating, Ventilating and Evaporative Cooling · C-60 Finish Carpentry · C-61 Carpentry, Remodeling and Repairs · C-63 Appliances · C-65 Glazing · C-67 Low Voltage Communication Systems · C-70 Reinforcing Bar and Wire Mesh · C-74 Boilers, Steamfitting & Process Piping, Including Solar · C-77 Plumbing Including Solar · C-78 Solar Plumbing, Liquid Systems Only · C-79 Air Conditioning and Refrigeration, Including Solar

**CR — Commercial/Residential Specialty (Dual)**
CR-1 Acoustical Systems · CR-2 Excavating Grading and Oil Surfacing · CR-3 Awnings, Canopies, Carports and Patio Covers · CR-4 Boilers, Steamfitting and Process Piping · CR-5 As Restricted by the Registrar · CR-6 Swimming Pool Service and Repair · CR-7 Carpentry · CR-8 Floor Covering · CR-9 Concrete · CR-10 Drywall · CR-11 Electrical · CR-12 Elevators · CR-14 Fencing · CR-15 Blasting · CR-16 Fire Protection Systems · CR-17 Steel and Aluminum Erection · CR-21 Hardscaping and Irrigation Systems · CR-24 Ornamental Metals · CR-29 Machinery · CR-31 Masonry · CR-34 Painting and Wall Covering · CR-36 Plastering · CR-37 Plumbing · CR-38 Signs · CR-39 Air Conditioning and Refrigeration · CR-40 Insulation · CR-41 Septic Tanks and Systems · CR-42 Roofing · CR-45 Sheet Metal · CR-48 Ceramic, Plastic and Metal Tile · CR-53 Water Well Drilling · CR-54 Water Conditioning Equipment · CR-56 Welding · CR-57 Wrecking · CR-58 Comfort Heating, Ventilating and Evaporative Cooling · CR-60 Finish Carpentry · CR-61 Carpentry, Remodeling and Repairs · CR-63 Appliances · CR-65 Glazing · CR-66 Seal Coating · CR-67 Low Voltage Communication Systems · CR-69 Asphalt Paving · CR-70 Reinforcing Bar and Wire Mesh · CR-74 Boilers, Steamfitting & Process Piping, Including Solar · CR-77 Plumbing Including Solar · CR-78 Solar Plumbing, Liquid Systems Only · CR-79 Air Conditioning and Refrigeration, Including Solar · CR-80 Sewers, Drains and Pipe Laying

**K — Dual (General)**
KA Dual Engineering · KA-5 Dual Swimming Pool Contractor · KA-6 Dual Swimming Pool Contractor, Including Solar · KB-1 Dual Building Contractor · KB-2 Dual Residential and Small Commercial · KE As Restricted by the Registrar · KO As Restricted by the Registrar

**R — Residential Specialty**
R-1 Acoustical Systems · R-2 Excavating, Grading and Oil Surfacing · R-3 Awnings, Canopies, Carports and Patio Covers · R-4 Boilers, Steamfitting and Process Piping · R-4R Boilers · R-6 Swimming Pool Service and Repair · R-7 Carpentry · R-8 Floor Covering · R-9 Concrete · R-10 Drywall · R-11 Electrical · R-12 Elevators · R-13 Asphalt Paving · R-14 Fencing · R-15 Blasting · R-16 Fire Protection Systems · R-17 Structural Steel and Aluminum · R-21 Hardscaping and Irrigation Systems · R-22 House Moving · R-24 Ornamental Metals · R-31 Masonry · R-34 Painting and Wall Covering · R-36 Plastering · R-37 Plumbing, Including Solar · R-37R Plumbing · R-38 Signs · R-39 Air Conditioning and Refrigeration, Including Solar · R-39R Air Conditioning and Refrigeration · R-40 Insulation · R-41 Septic Tanks and Systems · R-42 Roofing · R-45 Sheet Metal · R-48 Ceramic, Plastic and Metal Tile · R-53 Drilling · R-54 Water Conditioning Equipment · R-56 Welding · R-57 Wrecking · R-60 Finish Carpentry · R-61 Carpentry, Remodeling and Repairs · R-62 Minor Home Improvements · R-63 Appliances · R-65 Glazing · R-67 Low Voltage Communication Systems · R-70 Reinforcing Bar and Wire Mesh

</details>

Pass any of these codes into `licenseClassification` to filter results to that endorsement.

### 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 | License cancelled (often voluntary) |
| Revoked | Permanently terminated by ROC action |

Use `licenseStatus: "ACTIVE"` to receive only currently authorized contractors.

### FAQ

**Do I need an AZ ROC account or API key?**
No. The scraper reads AZ ROC's own public contractor-search backend. There is no public search API — this actor is the alternative.

**Why does `resultsPerPage` have no effect?**
AZ ROC's search returns every matching record in a single response — the site's own "Next" pagination is purely a client-side display convenience over data it already has in full. This actor reads that same complete response directly, so there's nothing to paginate and no page-size setting to apply.

**How reliable is `licenseClassification` filtering?**
AZ ROC's own classification search parameter was found (through direct testing) to return additional, unrelated classifications alongside the requested one rather than filtering exactly. To guarantee correct results, this actor always applies an exact match against each license's own parsed classification code after fetching results, rather than trusting AZ ROC's filter alone.

**Why is `expirationDate` the same as `renewedThroughDate`?**
AZ ROC's contractor detail page shows a single forward-looking date, labeled "Renewed Through" — there is no separate expiration date exposed. Both fields carry that value for compatibility with schemas that expect an `expirationDate` field.

**Why are some bond/complaint fields null?**
`bondExpirationDate` is not exposed by AZ ROC's bond data at all (only an effective date). Complaint and bond details require `scrapeDetailPage` (and `scrapeComplaints` for complaints); with both off, or when a license genuinely has no bond or complaint record, those fields are null.

**What proxy do I need?**
AZ ROC's search backend has responded to direct and datacenter requests during testing, but residential is recommended for larger production runs to reduce rate-limiting risk.

**Something's not working.**
Open an issue on the **Issues** tab with your input and the run link — we respond quickly.

### Is it legal to scrape AZ ROC contractor licenses?

AZ ROC contractor license records are public information, published by the State of Arizona and viewable by any visitor without logging in. Scraping publicly available government records is legal in most jurisdictions, and this actor does not access private data or bypass any login. You are responsible for how you use the data — follow AZ ROC's Terms of Use and applicable data-protection law, and consult a lawyer if you are unsure. See Apify's guide on [the legality of web scraping](https://blog.apify.com/is-web-scraping-legal/).

### Related actors

- [BuildZoom Scraper](https://apify.com/parsebird/buildzoom-scraper) — contractor profiles and reviews from BuildZoom.
- [UK Companies House Scraper](https://apify.com/parsebird/uk-companies-house-scraper) — UK company registry records.
- [Zefix.ch Scraper](https://apify.com/parsebird/zefix-ch-scraper) — Swiss commercial register lookups.
- [Allabolag Scraper](https://apify.com/parsebird/allabolag-company-scraper) — Swedish company and B2B lead data.

Browse all [ParseBird actors](https://apify.com/parsebird) on Apify Store.

# Actor input Schema

## `licenseNumbers` (type: `array`):

One or more ROC license numbers to look up directly, e.g. 333318. Leading zeros are added automatically to make 6 digits. Fastest and most precise search mode.

## `companyNames` (type: `array`):

Business names to search. Partial matches accepted (e.g. Acme Plumbing). Each name triggers its own search.

## `qualifyingPartyNames` (type: `array`):

Full name of the qualifying party -- the individual legally responsible for the license. Format: First Last. Partial names allowed.

## `cities` (type: `array`):

Arizona cities to search by mailing address (e.g. Phoenix, Tucson, Mesa, Scottsdale). Must match the exact spelling AZ ROC has on file. Large cities can return hundreds of records.

## `licenseClassification` (type: `string`):

Optional classification code to filter by (e.g. B-1, R-11, C-37, CR-39). See the Classification Reference in the README for the full list. Leave blank to return all classifications. Applied together with Cities, or on its own if no other search field is set.

## `licenseType` (type: `string`):

Keep only licenses whose classification scope matches. Derived from the classification's own description (Residential / Commercial / Dual), since AZ ROC's search does not filter by type server-side.

## `licenseStatus` (type: `string`):

Keep only licenses in this status. Applied after fetching results, since AZ ROC's search does not filter by status server-side.

## `maxResultsPerSearch` (type: `integer`):

Cap records per individual search query (license number, company name, qualifying party, or city). 0 = unlimited.

## `resultsPerPage` (type: `string`):

Kept for compatibility with the AZ ROC site's own page-size control. This actor reads every matching record directly from AZ ROC's single search response instead of clicking through pages, so this value has no effect on what's collected.

## `scrapeDetailPage` (type: `boolean`):

If true, fetches each license's full detail record: bond, complaint counts, classification, and personnel data. Disable for a fast list-only crawl.

## `scrapeComplaints` (type: `boolean`):

If true (and Scrape detail page is enabled), captures the license's complaint history (open / disciplined / resolved counts, plus individual complaints). AZ ROC only displays the prior two years of complaints.

## `maxConcurrency` (type: `integer`):

Maximum concurrent requests to AZ ROC's search API (1-10). This actor talks to AZ ROC's own backend directly rather than driving a browser, so this controls concurrent HTTP requests, not browser tabs. Higher values speed up bulk runs but increase load on AZ ROC's server.

## `proxyConfiguration` (type: `object`):

Standard Apify proxy config. AZ ROC's search API has responded to direct and datacenter requests in testing, but residential is recommended for larger production runs to reduce rate-limiting risk.

## Actor input object example

```json
{
  "licenseNumbers": [
    "333318"
  ],
  "companyNames": [],
  "qualifyingPartyNames": [],
  "cities": [],
  "licenseType": "ALL",
  "licenseStatus": "ALL",
  "maxResultsPerSearch": 0,
  "resultsPerPage": "50",
  "scrapeDetailPage": true,
  "scrapeComplaints": true,
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "licenseNumbers": [
        "333318"
    ],
    "companyNames": [],
    "qualifyingPartyNames": [],
    "cities": [],
    "licenseClassification": "",
    "licenseType": "ALL",
    "licenseStatus": "ALL",
    "maxResultsPerSearch": 0,
    "resultsPerPage": "50",
    "maxConcurrency": 3,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("parsebird/az-roc-contractor-license-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "licenseNumbers": ["333318"],
    "companyNames": [],
    "qualifyingPartyNames": [],
    "cities": [],
    "licenseClassification": "",
    "licenseType": "ALL",
    "licenseStatus": "ALL",
    "maxResultsPerSearch": 0,
    "resultsPerPage": "50",
    "maxConcurrency": 3,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("parsebird/az-roc-contractor-license-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "licenseNumbers": [
    "333318"
  ],
  "companyNames": [],
  "qualifyingPartyNames": [],
  "cities": [],
  "licenseClassification": "",
  "licenseType": "ALL",
  "licenseStatus": "ALL",
  "maxResultsPerSearch": 0,
  "resultsPerPage": "50",
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call parsebird/az-roc-contractor-license-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,parsebird/az-roc-contractor-license-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/HE74RGPh4vmq1fW6A/builds/0nCQt9m7YbxfWJFTt/openapi.json
