# Arkansas Contractor Directory & Leads Scraper (ACLB) (`scrapebench/arkansas-contractor-directory-leads-scraper`) Actor

Every licensed Arkansas contractor in a county, by trade — business name, email, phone, mailing address, officers, licence, trades and bid limit — from the Arkansas Contractors Licensing Board.

- **URL**: https://apify.com/scrapebench/arkansas-contractor-directory-leads-scraper.md
- **Developed by:** [ScrapeBench](https://apify.com/scrapebench) (community)
- **Categories:** Lead generation
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.002 / contractor record

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Arkansas Contractor Directory & Leads Scraper (ACLB)

### Pain points

- ACLB publishes a free nightly roster CSV of every licence (18,290 rows on 2026-09-28), but it is one statewide file: cutting it down to a county and a trade is spreadsheet work, and its trade column joins names that themselves contain commas, so it cannot be split cleanly.
- ACLB's county search is a loose text match across every state's licensees: search 'Washington' and you also get contractors in Washington County, Oregon.
- For residential licences the 'License No.' ACLB shows is only a month-and-year suffix like '1226', shared by every firm expiring that month, so de-duplicating on it silently merges different contractors.

### What we solve

- Pick a county and a trade and get every licensed contractor in one run, with email, phone and mailing address, ready for a CRM.
- Uses ACLB's own trade codes for the filter, keeps only firms with an Arkansas address in exactly the county you asked for, and merges every spelling of that county.
- Joins each contractor to ACLB's nightly roster by ACLB ID for email, officers, DBA and business structure, and says on every row whether that join succeeded.

### Summary

Build a contractor prospect list for any Arkansas county in one run. Choose a county (or several) and a trade — Roofing, Plumbing, Residential Builder, Concrete, any of the 141 trades the Arkansas Contractors Licensing Board licenses — and get back every contractor that matches: business name, email, phone, fax, mailing address, city, county, ZIP, named officers, DBA, business structure, licence type, status, expiry date, the full list of trades each firm is licensed for, and its ACLB bid limit. The filter runs on ACLB's own licence search; email, officers and DBA come from ACLB's own nightly roster, matched by ACLB ID. Leave the trade empty for every contractor in the county, or leave the county empty to search a trade across all of Arkansas. Pay only per contractor returned.

### Who it's for

- Sales teams selling tools, materials, equipment or software to contractors in an Arkansas territory
- Insurance and bonding agents prospecting for contractor accounts by county
- General contractors building a subcontractor shortlist by trade before bidding
- Market researchers sizing licensed trade coverage across Arkansas counties

### How to use

Set the input, run the actor, and collect results from the run's dataset (export to JSON/CSV/Excel, or pull via the Apify API). Example input:

```json
{
  "county": "Pulaski",
  "trade": "Roofing"
}
```

See **Inputs** below for every available field.

### What you get

One row per record:

| Field | Description |
|---|---|
| `business_name` | Contractor name as licensed by ACLB |
| `email` | Email on file in ACLB's nightly roster (null when not on file; see enrichment\_status) |
| `phone` | Phone number on file with ACLB |
| `fax` | Fax number, when listed |
| `address` | Mailing street address (often a PO box) |
| `city` | Mailing city |
| `county` | Arkansas county of the mailing address — the canonical name when you searched by county, ACLB's own spelling on a statewide search |
| `zip_code` | Mailing ZIP code |
| `officers` | Named officers and members on file, e.g. 'President: …', when filed |
| `dba` | Doing-business-as name, when filed |
| `business_structure` | Corporation, Limited Liability Company, Sole Proprietorship, … |
| `license_type` | Commercial, Residential (Limited/Unlimited) or Registration, as ACLB labels it |
| `status` | Valid, 'Valid (extended)', Invalid, or 'Call ACLB to confirm' |
| `expiration_date` | Licence expiry date (MM/DD/YYYY) |
| `classifications` | Every trade the contractor is licensed for, as ACLB lists them |
| `bid_limit` | ACLB's suggested bid limit, e.g. 'UNLIMITED' or 'Restricted to projects under $1,500,000' |
| `aclb_id` | ACLB's ID for the firm — the stable identifier for licensed contractors |
| `license_number` | The 'License No.' ACLB shows — a full number for commercial licences, only an MMYY suffix for residential ones |
| `registration_number` | For Registration rows (which have no ACLB ID), their registration number |
| `enrichment_status` | matched, not\_in\_roster, or roster\_unavailable — why email/officers may be null |
| `requested_county` | The county search that returned the row |
| `requested_trade` | The trade search that returned the row |
| `source_url` | The ACLB licence search |

Sample:

```json
{
  "business_name": "KETCHER AND COMPANY, INC.",
  "email": "kristy@ketcherandco.com",
  "phone": "501-372-5216",
  "fax": "501-372-0949",
  "address": "PO BOX 5271",
  "city": "NORTH LITTLE ROCK",
  "county": "Pulaski",
  "zip_code": "72119",
  "state": "AR",
  "officers": "President: Henry Ketcher, Vice President: Hank Ketcher III, President: Henry H Ketcher III",
  "dba": null,
  "business_structure": "Corporation",
  "license_type": "Commercial",
  "status": "Valid",
  "expiration_date": "06/30/2027",
  "classifications": "Roofing, Roof Decks, Roofing Sheet Metal",
  "bid_limit": "UNLIMITED",
  "aclb_id": "2247",
  "license_number": "0006000627",
  "enrichment_status": "matched",
  "requested_county": "Pulaski",
  "requested_trade": "Roofing, Roof Decks, Roofing Sheet Metal",
  "source_url": "http://aclb2.arkansas.gov/clbsearch.php"
}
```

### Inputs

| Field | Required | Type | Default | Description |
|---|---|---|---|---|
| `listOptionsOnly` | no | boolean | `false` | If true, skip the scrape and return the 75 Arkansas counties plus every trade the Arkansas Contractors Licensing Board (ACLB) licenses, with its code. Free, not charged. Use it to find the exact trade name before a real run. |
| `trade` | no | string | `"Roofing"` | An ACLB trade (specialty or classification), by name or code, e.g. 'Roofing', 'Plumbing', 'Residential Builder', 's\_1899'. A word from the name works too: 'roof' finds Roofing but not Fireproofing. Leave it empty to get every trade in the county. |
| `trades` | no | array | `["Roofing", "Concrete"]` | Several trades in ONE run, e.g. Roofing and Plumbing and Concrete. Combined with 'Trade' if you fill both. Every trade is searched in every county, and a contractor holding two of them is returned (and billed) once, not twice. |
| `county` | no | string | `"Pulaski"` | Arkansas county, e.g. 'Pulaski', 'Benton County', 'saint francis'. Case, punctuation and a trailing 'County' do not matter. Leave it empty with a trade set to search all of Arkansas. If it is not an Arkansas county, the run returns the free county and trade lists instead of failing. |
| `counties` | no | array | `["Pulaski", "Faulkner"]` | Several counties in ONE run, e.g. Pulaski and Faulkner and Saline. Combined with 'County' if you fill both. |
| `validOnly` | no | boolean | `true` | Return only contractors whose licence ACLB lists as valid (a few show 'Call ACLB to confirm'). Turn off to include expired and invalid licences too. |
| `workType` | no | string | `"all"` | Commercial licences, residential licences, or both. |
| `maxResults` | no | integer | — | Cap on the contractors returned PER county + trade search, not per run, so adding counties can never silently truncate the ones later in the list. Leave empty to return every match. |
| `proxyConfiguration` | no | object | `{"useApifyProxy": false}` | Optional. ACLB answers direct requests; enable a proxy only if runs come back with a 'blocked' notice. |

### Pricing (Pay Per Event)

You pay per result (`dataset-item`) — **no charge for empty runs**. Example: **129 Pulaski County roofing contractors** at *$0.002/result* ≈ **$0.26**.

Discovery Mode and unrecognised inputs return the free county and trade lists. Apify platform usage is billed separately.

### Use cases

- Territory prospecting — pull every licensed roofer, plumber or builder in Pulaski, Benton and Washington counties and load the email and phone list into your CRM.
- Subcontractor sourcing — list every contractor licensed for a trade in the county where a project sits, with their bid limit, before you send bid invitations.
- Market sizing — count licensed contractors per trade and county to decide where to open a branch or send a rep.
- List refresh — re-run monthly and compare licence status and expiry dates to spot firms that lapsed or renewed.

### Why this actor

- Email on 1,363 of 1,387 Benton County contractors and 117 of 129 Pulaski roofers (measured 2026-09-28), from ACLB's own roster.
- Straight from the Arkansas Contractors Licensing Board: its licence search for the filter, its nightly roster for contact detail.
- County results are exact: out-of-state firms with a same-named county are removed, and every spelling of the county is merged.
- Each contractor is identified by ACLB ID, so residential firms that share a month-and-year licence suffix are never merged together.
- Pay per contractor returned; the county and trade lists are free.

### Limitations & updates

Covers contractors licensed or registered by the Arkansas Contractors Licensing Board with an Arkansas mailing address. The county is the county of the licence's mailing address, which is often a PO box, so a firm working in several counties appears only under its mailing county. Email, officers and DBA come from ACLB's nightly roster: registration-only firms (no ACLB ID) are matched to it by business name, and a firm missing from that night's roster ships without them (enrichment\_status says which). Trades are returned as ACLB lists them, in one text field. ACLB is an older HTTP-only site; if it does not answer, the run returns a free row saying so instead of an empty dataset.

### FAQ

**Where does the data come from?**

Two ACLB sources. The filter and core licence fields come from ACLB's public licence search at aclb2.arkansas.gov. Email, officers, DBA and business structure come from ACLB's free nightly roster (latestroster.csv), matched to each search row by ACLB ID.

**Can't I just download ACLB's roster myself?**

Yes, and if you want the whole state once, you should: it is free. This actor is for when you want a county and a trade on demand, already filtered, deduplicated, matched to the search's licence fields, and repeatable on a schedule.

**How many contractors does a county return?**

Counted on the live search 2026-09-28, valid licences, all trades: Pulaski 1,712, Benton 1,387, Washington 1,052, Garland 607, Sebastian 449, Chicot 28. Pulaski roofers alone are 129.

**Why is a residential licence number only four digits?**

That is what ACLB shows: for residential licences its 'License No.' column holds only a month-and-year suffix such as '1226'. Use aclb\_id to identify those firms; this actor does.

**How do I name a trade?**

By name ('Roofing', 'Plumbing', 'Residential Builder'), by a word from the name ('roof' finds Roofing but not Fireproofing), or by ACLB code ('s\_1899'). Turn on Discovery Mode to get all 141 trades with their codes, free.

**Why is email empty on some rows?**

Check enrichment\_status. 'matched' with no email means ACLB has none on file for that firm; 'not\_in\_roster' means the firm was not in that night's roster; 'roster\_unavailable' means the roster download failed and the row shipped without enrichment.

**What does 'Call ACLB to confirm' mean?**

ACLB's own status column says 'Call' for a few licences instead of Yes or No — the board wants a phone call before it vouches for them. We pass that through rather than guess. It was 3 of 129 Pulaski roofers.

**How am I charged?**

One event per contractor returned ($0.002). A contractor that matches two of your searches is returned and charged once. The county and trade lists, and any row explaining a source problem, are free.

### Which actor to choose

Part of the contractor-data suite — pick the one that fits your goal:

- **Arkansas Contractor License Lookup & Verify (ACLB)** — You have a contractor's name or licence number and want to check that one licence.
- **California Contractor Directory by Trade & County (CSLB)** — You need the same trade-by-county contractor list for California.
- **Texas Contractor Directory & Leads Scraper (TDLR)** — You need a county-scoped roster of Texas TDLR-licensed contractors.
- **Oregon Contractor Directory & Leads Scraper (CCB)** — You need the same county-level directory for Oregon.

### Guides & use cases

Written up on **[scrapebench.dev](https://scrapebench.dev)** — the bench that runs and verifies this actor against the live source every night:

- **How-to:** [How to run Arkansas Contractor Directory & Leads Scraper (ACLB)](https://scrapebench.dev/guides/how-to-arkansas-contractor-directory-leads-scraper/)
- **Use case:** [Build a Pulaski County Roofing Contractor List](https://scrapebench.dev/use-cases/pulaski-county-roofing-contractors/)
- **Use case:** [List Residential Builders in Northwest Arkansas](https://scrapebench.dev/use-cases/northwest-arkansas-residential-builders/)

More actors, coverage and nightly verification results: **[scrapebench.dev](https://scrapebench.dev)**

### Works with AI assistants (MCP)

Callable as an MCP tool, so Claude, Cursor, VS Code Copilot and other MCP clients can run it directly. Grab the config from the [MCP tab](https://apify.com/scrapebench/arkansas-contractor-directory-leads-scraper/api/mcp) on this page — Apify hosts the server and keeps that snippet current, and OAuth signs you in on first connect, so no API token goes in your config file.

Then just ask:

> "List the licensed roofing contractors in Pulaski County, Arkansas, with their email addresses and phone numbers."

Each row also carries the contractor's ACLB bid limit, which tells you how large a job the board lets them take. Runs started this way bill exactly like any other run.

# Changelog

This Actor's version history is a separate document: https://apify.com/scrapebench/arkansas-contractor-directory-leads-scraper/changelog.md

# Actor input Schema

## `listOptionsOnly` (type: `boolean`):

If true, skip the scrape and return the 75 Arkansas counties plus every trade the Arkansas Contractors Licensing Board (ACLB) licenses, with its code. Free, not charged. Use it to find the exact trade name before a real run.

## `trade` (type: `string`):

An ACLB trade (specialty or classification), by name or code, e.g. 'Roofing', 'Plumbing', 'Residential Builder', 's\_1899'. A word from the name works too: 'roof' finds Roofing but not Fireproofing. Leave it empty to get every trade in the county.

## `trades` (type: `array`):

Several trades in ONE run, e.g. Roofing and Plumbing and Concrete. Combined with 'Trade' if you fill both. Every trade is searched in every county, and a contractor holding two of them is returned (and billed) once, not twice.

## `county` (type: `string`):

Arkansas county, e.g. 'Pulaski', 'Benton County', 'saint francis'. Case, punctuation and a trailing 'County' do not matter. Leave it empty with a trade set to search all of Arkansas. If it is not an Arkansas county, the run returns the free county and trade lists instead of failing.

## `counties` (type: `array`):

Several counties in ONE run, e.g. Pulaski and Faulkner and Saline. Combined with 'County' if you fill both.

## `validOnly` (type: `boolean`):

Return only contractors whose licence ACLB lists as valid (a few show 'Call ACLB to confirm'). Turn off to include expired and invalid licences too.

## `workType` (type: `string`):

Commercial licences, residential licences, or both.

## `maxResults` (type: `integer`):

Cap on the contractors returned PER county + trade search, not per run, so adding counties can never silently truncate the ones later in the list. Leave empty to return every match.

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

Optional. ACLB answers direct requests; enable a proxy only if runs come back with a 'blocked' notice.

## Actor input object example

```json
{
  "listOptionsOnly": false,
  "trade": "Roofing",
  "trades": [
    "Roofing",
    "Concrete"
  ],
  "county": "Pulaski",
  "counties": [
    "Pulaski",
    "Faulkner"
  ],
  "validOnly": true,
  "workType": "all",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

Each row is one ACLB-licensed contractor: name, phone, mailing address, county, licence and trades.

# 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 = {
    "trade": "Roofing",
    "trades": [
        "Roofing",
        "Concrete"
    ],
    "county": "Pulaski",
    "counties": [
        "Pulaski",
        "Faulkner"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapebench/arkansas-contractor-directory-leads-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 = {
    "trade": "Roofing",
    "trades": [
        "Roofing",
        "Concrete",
    ],
    "county": "Pulaski",
    "counties": [
        "Pulaski",
        "Faulkner",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("scrapebench/arkansas-contractor-directory-leads-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 '{
  "trade": "Roofing",
  "trades": [
    "Roofing",
    "Concrete"
  ],
  "county": "Pulaski",
  "counties": [
    "Pulaski",
    "Faulkner"
  ]
}' |
apify call scrapebench/arkansas-contractor-directory-leads-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapebench/arkansas-contractor-directory-leads-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/GoxrfGrUdlEauJYhT/builds/bAvRfl7ti1uiAqckV/openapi.json
