# Ohio Contractor License Lookup & Export (OCILB) (`scrapebench/ohio-contractor-license-lookup`) Actor

Look up or export every active Ohio OCILB licence — electrical, HVAC, plumbing, hydronics and refrigeration contractors — with company, address, phone and expiry. Filter by trade, county, city, ZIP or name.

- **URL**: https://apify.com/scrapebench/ohio-contractor-license-lookup.md
- **Developed by:** [ScrapeBench](https://apify.com/scrapebench) (community)
- **Categories:** Lead generation
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.004 / license 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

## Ohio Contractor License Lookup & Export (OCILB)

### Pain points

- OCILB's free roster download is a three-step web form that builds a fresh file each time, and its State box defaults to Ohio — left alone it drops the 1,929 licences held by out-of-state contractors (measured 2026-10-07).
- The raw roster has one row per licence-and-company pair (12,495 rows for 12,486 licences on 2026-10-07) and uses a pseudo-company called 'ESCROW', so a straight import duplicates some licences and lists 'ESCROW' as a business name for 85 rows.
- Phone numbers are filed in several formats ('2162554298', '614-863-0588', '(724)962-5742'), which breaks dialers and de-duplication.

### What we solve

- One run returns the whole OCILB roster, or just the trade, county, city, ZIP or name you filter for — no form to click through.
- One row per licence number: the company association wins over 'ESCROW' or blank duplicates, and licences held only in escrow are flagged instead of named 'ESCROW'.
- Phones are normalised to (XXX) XXX-XXXX, emails lower-cased, and every row carries both the licensee's county and the company's address.

### Summary

Get the Ohio Construction Industry Licensing Board (OCILB) roster as clean data: every active electrical (EL), HVAC (HV), hydronics (HY), plumbing (PL) and refrigeration (RE) contractor licence — 12,309 on 2026-10-07 — with licence number, trade, status, effective and expiry dates, licensed individual, company, company street address, city, ZIP, phone, fax and email where filed, plus the licensee's county. Leave the input empty for a statewide export, or narrow it by trade, county, city, ZIP, name or status. The data is OCILB's own free roster, rebuilt from the state's eLicense site on every run. Ohio licenses only these commercial trades at state level — there is no statewide general-contractor or home-builder licence, so those are not in this data. Pay only per licence returned.

### Who it's for

- Distributors and manufacturers selling HVAC, electrical and plumbing supplies to licensed Ohio contractors
- General contractors and property managers checking that an Ohio trade subcontractor holds a live OCILB licence
- Insurers, sureties and lenders verifying licence status and expiry for Ohio trade contractors
- Data teams loading a statewide Ohio trade-contractor table into a CRM or warehouse

### 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
{
  "trade": "HV",
  "county": "Cuyahoga",
  "maxResults": 500
}
```

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

### What you get

One row per record:

| Field | Description |
|---|---|
| `license_number` | OCILB licence number with its trade prefix, e.g. HV.11969 — one row per licence |
| `license_type` | Electrical, HVAC, Hydronics, Plumbing or Refrigeration Contractor |
| `trade_code` | EL, HV, HY, PL or RE |
| `status` | ACTIVE or ACTIVE IN RENEWAL |
| `person_name` | The licensed individual (qualifying party) |
| `business_name` | Company the licence is attached to |
| `in_escrow` | True when OCILB lists the licence only under 'ESCROW' |
| `effective_date` | Start of the current licence term |
| `expiration_date` | End of the current licence term |
| `address` | Company street address |
| `city` | Company city |
| `address_state` | Company state |
| `zip_code` | Company ZIP or ZIP+4 |
| `phone` | Company phone, when filed (66% of licences) |
| `fax` | Company fax, when filed |
| `email` | Company email, when filed (4% of licences) |
| `county` | County of the licence holder as OCILB records it |
| `licensee_state` | State of the licence holder |
| `source_url` | OCILB's roster download page |

Sample:

```json
{
  "license_number": "HV.11969",
  "trade_code": "HV",
  "license_type": "HVAC Contractor",
  "status": "ACTIVE",
  "person_name": "TIMOTHY M LAVELLE",
  "business_name": "GORMAN LAVELLE CORP",
  "in_escrow": false,
  "effective_date": "04/01/2026",
  "expiration_date": "03/31/2029",
  "address": "3459 E 52nd Pl",
  "city": "Cleveland",
  "address_state": "OH",
  "zip_code": "44127-1659",
  "phone": "(216) 641-4600",
  "fax": null,
  "email": null,
  "county": "Cuyahoga",
  "licensee_state": "OH",
  "state": "OH",
  "source_url": "https://elicense4.com.ohio.gov/Lookup/GenerateRoster.aspx"
}
```

### Inputs

| Field | Required | Type | Default | Description |
|---|---|---|---|---|
| `trade` | no | string | — | One OCILB trade: EL (electrical), HV (HVAC), HY (hydronics), PL (plumbing), RE (refrigeration) or TA (training agency). Words work too: 'electrical', 'hvac', 'plumbing'. Leave empty for all five contractor trades (training agencies are only returned when asked for). An unrecognised value is ignored with a log line; if nothing you gave is recognised, the run returns a free row saying so instead of the whole state. |
| `trades` | no | array | `[]` | Several trades in ONE run, e.g. EL and PL. Combined with 'Trade' if you fill both. |
| `status` | no | string | `"all"` | OCILB's roster lists only live licences. 'all' returns both ACTIVE and ACTIVE IN RENEWAL (a licence inside its renewal window); pick one to narrow it. |
| `county` | no | string | — | Ohio county of the LICENCE HOLDER as OCILB records it, e.g. 'Cuyahoga' or 'Franklin County'. Matches Ohio holders only. An unrecognised county is ignored with a log line. |
| `counties` | no | array | `[]` | Several Ohio counties in ONE run. Combined with 'County' if you fill both. |
| `city` | no | string | — | Company city, exact match ignoring case and punctuation, e.g. 'Columbus' (does not also match 'Columbus Grove'). |
| `cities` | no | array | `[]` | Several company cities in ONE run. Combined with 'City' if you fill both. |
| `zip` | no | string | — | Company ZIP, 5 digits (a ZIP+4 is accepted and matched on its first 5). |
| `zips` | no | array | `[]` | Several company ZIPs in ONE run. Combined with 'ZIP code' if you fill both. |
| `name` | no | string | — | Text that the licensee's name or the company name contains (case-insensitive), e.g. 'MECHANICAL' or 'SMITH'. |
| `names` | no | array | `[]` | Several name fragments in ONE run; a licence matching any of them is returned once. The run log says how many licences each one matched. |
| `maxResults` | no | integer | `500` | Cap on licences returned for the whole run (a spend control). The full statewide roster is about 12,200 contractor licences, so 100000 returns everything that matches. The run log states how many matched when the cap cuts it short. |
| `proxyConfiguration` | no | object | `{"useApifyProxy": false}` | Optional. The OCILB site 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: **265 Cuyahoga County HVAC licences** at *$0.004/result* ≈ **$1.06**.

The full statewide export (12,309 licences on 2026-10-07) is about $49. Apify platform usage is billed separately.

### Use cases

- Statewide export — pull all 12,309 active OCILB contractor licences in one run and load them into your CRM.
- Territory list — every HVAC licence held in Cuyahoga County (265 on 2026-10-07), with company address and phone where filed.
- Vendor check — filter by company or licensee name to confirm a subcontractor's licence number, status and expiry.
- Renewal watch — filter status to ACTIVE IN RENEWAL (2,268 licences on 2026-10-07) to find contractors inside their renewal window.

### Why this actor

- Covers the whole OCILB roster, out-of-state licence holders included: 4,441 electrical, 3,090 HVAC, 3,033 plumbing, 939 hydronics and 806 refrigeration licences (2026-10-07).
- Company street address on 99% of licences and phone on 66% (8,149 of 12,309), measured 2026-10-07.
- One row per licence number (12,309 distinct of 12,309 rows), with escrow-only licences flagged.
- Rebuilt from OCILB's own free roster on every run, so a run is as current as the state's file.
- Pay per licence returned; outage, bad-filter and no-match rows are free.

### Limitations & updates

Covers licences on OCILB's roster only: electrical, HVAC, hydronics, plumbing and refrigeration contractors (training agencies on request). Ohio has no statewide general-contractor or home-builder licence, so those are not included. Only live licences are listed (ACTIVE and ACTIVE IN RENEWAL). Phone is filed on 66% of licences and email on 4%; the actor adds no contact data. The county is the licence holder's, not necessarily the company's. The effective date is the start of the current licence term, not the original issue date. If OCILB's site does not answer, the run returns a free row saying so instead of an empty dataset.

### FAQ

**Where does the data come from?**

From the Ohio Construction Industry Licensing Board's free roster download on the state eLicense site (elicense4.com.ohio.gov), which the actor generates and downloads on every run.

**Does this include general contractors or home builders?**

No. Ohio has no statewide general-contractor or residential builder licence; those are registered by cities and counties. OCILB licenses commercial electrical, HVAC, hydronics, plumbing and refrigeration contractors, and that is what this actor returns.

**How many licences are there, and how many have a phone or email?**

Counted 2026-10-07: 12,309 contractor licences. Company street address on 12,216 (99%), phone on 8,149 (66%), fax on 541 (4%), email on 458 (4%). Phone and email are whatever the licensee filed with OCILB; the actor does not add any.

**What does the county mean?**

It is the county OCILB records for the licence HOLDER, which is not always where the company is: a Cuyahoga County licensee can work for a company in Geauga County. Use city or ZIP to filter on the company's address instead. Largest counties on 2026-10-07: Cuyahoga 1,022, Franklin 693, Hamilton 585, Montgomery 410, Summit 407.

**Are expired or revoked licences included?**

No. OCILB's roster lists only live licences: ACTIVE (10,041) and ACTIVE IN RENEWAL (2,268, inside the renewal window), counted 2026-10-07.

**What happens if I type a trade or county the actor does not know?**

That value is ignored and the run log says so. If none of the values you gave for a filter is recognised, the run returns one free row explaining it instead of the whole state, so a typo never bills you for 12,000 rows.

**How am I charged?**

$0.004 per licence returned. The default input returns the first 500 licences statewide ($2.00); the full statewide export is about $49. Rows explaining an outage, an unrecognised filter or an empty result are free.

### Which actor to choose

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

- **Virginia Contractor License Lookup (DPOR Bulk)** — You need the same kind of statewide licence export for Virginia, with email.
- **Arkansas Contractor License Lookup & Verify (ACLB)** — You need Arkansas contractor licences, in bulk or one at a time.
- **Multi-State Contractor & Trade License Lookup** — You want the same contractor checked across several states in one run.
- **Iowa Contractor License Lookup & Export (DIAL)** — You need Iowa contractors — every active DIAL registration statewide, with phone and email, filtered by trade, county, city or ZIP.
- **Mississippi Contractor License Lookup & Export (MSBOC)** — You need Mississippi contractors — the active MSBOC roster with phone, street address and classifications, by county or class.
- **Nebraska Contractor Registration Lookup & Export (NDOL)** — You need Nebraska contractors — every current NDOL registration, by service and county, with phone on request.
- **Delaware Contractor License Lookup & Export (DOR + DPR)** — You need Delaware contractors — DOR business licences plus DPR electrical, plumbing and HVACR licences, by city or ZIP.

### 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 Ohio Contractor License Lookup & Export (OCILB)](https://scrapebench.dev/guides/how-to-ohio-contractor-license-lookup/)
- **Use case:** [List Cuyahoga County HVAC Contractor Licences](https://scrapebench.dev/use-cases/cuyahoga-county-hvac-contractors/)

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/ohio-contractor-license-lookup/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 Ohio OCILB HVAC contractor licences held in Cuyahoga County, with company names and phone numbers."

That input returns 265 licences (2026-10-07); about two in three carry a phone number. Runs started this way bill exactly like any other run.

# Changelog

This Actor's version history is a separate document: https://apify.com/scrapebench/ohio-contractor-license-lookup/changelog.md

# Actor input Schema

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

One OCILB trade: EL (electrical), HV (HVAC), HY (hydronics), PL (plumbing), RE (refrigeration) or TA (training agency). Words work too: 'electrical', 'hvac', 'plumbing'. Leave empty for all five contractor trades (training agencies are only returned when asked for). An unrecognised value is ignored with a log line; if nothing you gave is recognised, the run returns a free row saying so instead of the whole state.

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

Several trades in ONE run, e.g. EL and PL. Combined with 'Trade' if you fill both.

## `status` (type: `string`):

OCILB's roster lists only live licences. 'all' returns both ACTIVE and ACTIVE IN RENEWAL (a licence inside its renewal window); pick one to narrow it.

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

Ohio county of the LICENCE HOLDER as OCILB records it, e.g. 'Cuyahoga' or 'Franklin County'. Matches Ohio holders only. An unrecognised county is ignored with a log line.

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

Several Ohio counties in ONE run. Combined with 'County' if you fill both.

## `city` (type: `string`):

Company city, exact match ignoring case and punctuation, e.g. 'Columbus' (does not also match 'Columbus Grove').

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

Several company cities in ONE run. Combined with 'City' if you fill both.

## `zip` (type: `string`):

Company ZIP, 5 digits (a ZIP+4 is accepted and matched on its first 5).

## `zips` (type: `array`):

Several company ZIPs in ONE run. Combined with 'ZIP code' if you fill both.

## `name` (type: `string`):

Text that the licensee's name or the company name contains (case-insensitive), e.g. 'MECHANICAL' or 'SMITH'.

## `names` (type: `array`):

Several name fragments in ONE run; a licence matching any of them is returned once. The run log says how many licences each one matched.

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

Cap on licences returned for the whole run (a spend control). The full statewide roster is about 12,200 contractor licences, so 100000 returns everything that matches. The run log states how many matched when the cap cuts it short.

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

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

## Actor input object example

```json
{
  "trade": "HV",
  "trades": [],
  "status": "all",
  "county": "Cuyahoga",
  "counties": [],
  "cities": [],
  "zips": [],
  "names": [],
  "maxResults": 500,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Each row is one OCILB licence: licence number, trade, status, dates, licensee, company, address, phone and email where filed.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapebench/ohio-contractor-license-lookup").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("scrapebench/ohio-contractor-license-lookup").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 '{}' |
apify call scrapebench/ohio-contractor-license-lookup --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapebench/ohio-contractor-license-lookup"
        }
    }
}
```

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/tqe59AHxxGiiEFf52/builds/wrY6bqEVfhgDfg3Q7/openapi.json
