# Ohio Insurance License Lookup (`stackrelay/ohio-insurance-license`) Actor

Search Ohio insurance producer and business entity licenses via the Ohio Department of Insurance Agent/Agency Locator. Returns NPN, full license history, lines of authority, and address.

- **URL**: https://apify.com/stackrelay/ohio-insurance-license.md
- **Developed by:** [StackRelay](https://apify.com/stackrelay) (community)
- **Categories:** Business, Lead generation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 76.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $12.00 / 1,000 license\_enricheds

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/platform/actors/running/actors-in-store#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

## Ohio Insurance Producer License Scraper

Search Ohio insurance producer and business entity licenses via the **Ohio Department of Insurance Agent/Agency Locator** (`gateway.insurance.ohio.gov`). Returns normalized records with NPN, full license history, lines of authority, status, and business address.

> **Disclaimer — please read before running.** This actor is an independent data tool built by StackRelay. It is **not affiliated with, endorsed by, or operated by** the Ohio Department of Insurance. Results are a **best-effort, point-in-time snapshot** of the public ODI Agent/Agency Locator, provided **AS-IS with no warranty** of accuracy, completeness, or timeliness — license status, lines of authority, and addresses can change at any time after a record is fetched. Every record carries a `source_url` linking back to the ODI detail page and a `scraped_at` timestamp: **verify independently at the source before acting on any record.** Output includes personal data about individuals (names, address, phone); if you process data about EU/UK residents you may be an independent data controller under GDPR/UK GDPR. **This actor's output is not a consumer report and must not be used for FCRA-regulated purposes** — credit, insurance underwriting eligibility, employment, or tenant-screening decisions about an individual. By running this actor you agree to the [Developer Terms of Use](DEVELOPER_TERMS.md).

> **Note:** Ohio is NOT part of the NAIC State Based Systems (SBS). This actor wraps Ohio's own public ODI portal. The ODI portal is the source; this actor reads only its public, logged-out lookup and passes data through with formatting normalization only — always confirm any record at its `source_url` before relying on it.

### What it does

1. Calls the ODI Agent/Agency Locator search API with your query
2. Optionally follows each result's detail page to retrieve NPN and full license/LOA data
3. Normalizes all fields and pushes structured records to the Apify dataset

### Input

#### Search field requirements

**Individual search (IND):** At least one of `lastName`, `npn`, `city`, or `zip` is required. `licenseNumber` requires a second field (`lastName`, `npn`, `city`, or `zip`).

**Business entity search (BUS):** At least one of `npn`, `city`, or `zip` is required. `businessName` alone is not accepted by the ODI API — it must be combined with `city`, `zip`, or `npn`.

| Field | Type | Default | Description |
|---|---|---|---|
| `entityType` | `IND` | `BUS` | `IND` | Individual producer or business entity |
| `lastName` | string | — | Agent last name. Partial match supported. |
| `firstName` | string | — | Agent first name. Optional, narrows results. |
| `businessName` | string | — | Agency name. Must pair with `city`, `zip`, or `npn`. |
| `npn` | string | — | National Producer Number. Returns exactly 1 record. |
| `licenseNumber` | string | — | Ohio license number. Must pair with `lastName`, `npn`, `city`, or `zip`. |
| `city` | string | — | Business address city. Works standalone. |
| `zip` | string | — | Business address ZIP. Works standalone. |
| `licenseType` | select | (any) | Filter by license type. See valid values below. |
| `residenceType` | select | (any) | `resident` or `nonResident` |
| `activeOnly` | boolean | false | Only return producers with at least one active Ohio license |
| `fetchDetails` | boolean | true | Follow detail pages for NPN + full license data. See note below. |
| `maxResults` | integer | 200 | Cap on records. Actor paginates automatically up to this limit. |

#### Valid `licenseType` values

| Value | Label |
|---|---|
| `majorLines` | Major Lines |
| `health` | Health |
| `life` | Life |
| `personal` | Personal Lines |
| `propertyCasualty` | Property & Casualty |
| `variable` | Variable Products |
| `limitedLines` | Limited Lines |
| `carRental` | Car Rental |
| `credit` | Credit |
| `crop` | Crop |
| `funeral` | Funeral Expense |
| `selfServiceStorage` | Self Service Storage |
| `travel` | Travel |
| `mga` | Managing General Agent |
| `portableElectronics` | Portable Electronics |
| `suretyBailBond` | Surety Bail Bond |
| `surplusLines` | Surplus Lines |
| `title` | Title |
| `timr` | Title Insurance Marketing Rep |

#### `fetchDetails` flag

When **true** (recommended): the actor makes a second HTTP request per record to retrieve NPN and full Ohio license history. This is ~2x slower but produces a complete dataset.

When **false**: individual (IND) searches return **no NPN and no license data** — only name, address, phone, and status. Business entity (BUS) searches always include NPN regardless of this setting. Only disable `fetchDetails` for high-volume pre-filtering when you plan to re-run matched records with it enabled.

#### Example inputs

**Individual producer (IND) searches**

NPN lookup (fastest, single record):

```json
{ "npn": "20835251" }
```

Last name only, statewide:

```json
{ "lastName": "Johnson" }
```

Name search — active resident Life producers in Columbus:

```json
{ "lastName": "Smith", "city": "Columbus", "activeOnly": true, "residenceType": "resident", "licenseType": "life" }
```

Non-resident producers only, by city:

```json
{ "city": "Columbus", "residenceType": "nonResident", "activeOnly": true }
```

License number lookup (requires a secondary field):

```json
{ "licenseNumber": "1534119", "lastName": "Smith" }
```

**City lead-gen searches**

All active producers in a city:

```json
{ "city": "Columbus", "activeOnly": true, "maxResults": 500 }
```

Niche license-type filter by city — the same pattern works for any of the 19 `licenseType` values above (Title, Surety Bail Bond, Surplus Lines, Travel, Funeral, Car Rental, Credit, Personal Lines, Limited Lines, and more):

```json
{ "city": "Cleveland", "licenseType": "health", "activeOnly": true }
```

Property & Casualty producers in another city:

```json
{ "city": "Cincinnati", "licenseType": "propertyCasualty", "activeOnly": true }
```

**Business entity (BUS) searches**

All active agencies in a city (no ZIP or name needed):

```json
{ "entityType": "BUS", "city": "Cleveland", "activeOnly": true }
```

Business entity by ZIP:

```json
{ "entityType": "BUS", "zip": "43215", "activeOnly": true }
```

Agencies filtered by niche license type:

```json
{ "entityType": "BUS", "city": "Columbus", "licenseType": "surplusLines", "activeOnly": true }
```

Business name search (requires city or ZIP):

```json
{ "entityType": "BUS", "businessName": "Acme Insurance", "city": "Columbus" }
```

### Output

Each dataset record:

```json
{
  "id":            "OH-20835251",
  "source_name":   "Ohio Department of Insurance — Agent/Agency Locator (public lookup)",
  "source_url":    "https://gateway.insurance.ohio.gov/.../DisplayIndividualDetail/...",
  "npn":           "20835251",
  "name":          "Desjane Smith",
  "first_name":    "Desjane",
  "middle_name":   null,
  "last_name":     "Smith",
  "entity_type":   "IND",
  "address_line1": "2112 Stoker Pl",
  "address_line2": null,
  "address_city_state_zip": "HEPZIBAH, GA 30815",
  "address_city":  "Hepzibah",
  "address_state": "GA",
  "address_zip":   "30815",
  "phone":         "(248) 943-3201",
  "status":        "Active",
  "is_active":     true,
  "licenses": [
    {
      "license_number":      "1534119",
      "license_type":        "Individual - Non-Resident - Major Lines",
      "status":              "Active",
      "cancellation_reason": null,
      "issue_date":          "2022-03-15",
      "expiration_date":     "2025-07-01",
      "renewal_date":        null,
      "loas": [
        { "loa": "Accident & Health", "status": "Active", "issue_date": "2022-03-15", "expiration_date": "2025-07-01" },
        { "loa": "Life",              "status": "Active", "issue_date": "2022-03-15", "expiration_date": "2025-07-01" }
      ]
    }
  ],
  "jurisdiction":  "OH",
  "scraped_at":    "2026-05-30T03:00:00.000Z"
}
```

#### Key fields

- **`id`** — `OH-{NPN}` when NPN is available; stable across re-runs for deduplication
- **`is_active`** — `true` when the record-level status is "Active". Note: a producer can be "Active" overall while having individual licenses in `Cancelled` or `Surrendered` status — always inspect the `licenses` array for the specific license type you care about
- **`licenses`** — full Ohio license history, oldest to newest. Each license has its own `loas` array with per-line-of-authority detail
- **`address_state`** — will often be a state other than OH. Non-resident producers licensed in Ohio have their home-state business address on file. This is expected and correct.

### Notes on data accuracy

**Non-Ohio addresses are expected.** Ohio licenses non-resident producers — their business address will be in their home state, not Ohio.

**Expiration dates may appear stale.** Ohio auto-renews producer licenses on a rolling basis and the ODI portal does not always reflect the current renewal date in real time. Trust the `status` field over `expiration_date` for active/inactive determination.

**City and ZIP searches return alphabetical results only.** The ODI API does not support filtering by line of authority within the search — `licenseType` narrows results but is not guaranteed to exclude all non-matching license types from the response. Verify LOA membership in the `licenses` array.

### FAQ

**Does this return the NPN (National Producer Number)?**
Yes. Business entity (BUS) searches always include NPN. For individual (IND) searches, keep `fetchDetails` enabled (the default) and each record returns its NPN plus full license history.

**Why is a producer's address not in Ohio?**
Ohio licenses non-resident producers, who keep their home-state business address on file. A non-Ohio `address_state` is expected and correct for licensees outside Ohio.

**How do I search by agency name?**
Business name alone is not accepted by the ODI API. Set `entityType` to `BUS` and pair `businessName` with `city`, `zip`, or `npn`.

**How current is the data?**
Records are pulled live from the Ohio Department of Insurance portal at run time (`scraped_at` timestamps each record). Note that ODI auto-renews licenses on a rolling basis, so trust the `status` field over `expiration_date` for active/inactive determination.

**Can I pull every active producer in a city for lead generation?**
Yes. Search by `city` (or `zip`) with `activeOnly: true` and raise `maxResults`. The actor paginates automatically up to your limit.

**Is an API key or login required?**
No. This wraps public data from the ODI Agent/Agency Locator — no credentials needed.

### Pricing

Pay per event — priced by how much data you request per record:

| Event | When it's charged | Price |
|---|---|---|
| `license_basic` | `fetchDetails: false` — name, address, phone, status only (no NPN or license history) | $0.0035 / record |
| `license_enriched` | `fetchDetails: true` (default) — full license history with per-line lines-of-authority and dates | $0.012 / record |

Empty searches are never charged. Set `fetchDetails: false` for high-volume pre-filtering, then re-run the matched subset with `fetchDetails: true` to get the full enriched record.

### Data accuracy & legal notes

- **What this data is.** A best-effort, point-in-time snapshot of the public Ohio Department of Insurance Agent/Agency Locator. The actor is a pipe, not an oracle: fields are passed through from the source with formatting normalization only (title-casing, date and phone formats). Coverage and field completeness vary by record and entity type — for IND searches with `fetchDetails` disabled, NPN and license data are intentionally absent.
- **It can be wrong or stale.** License status, lines of authority, and addresses change as producers renew, surrender, or are terminated. ODI also auto-renews on a rolling basis, so `expiration_date` may appear stale even for active licensees — trust `status` over `expiration_date`. A record is accurate only as of its `scraped_at` timestamp. Every record carries a `source_url` back to the ODI detail page — **independently verify any record there before relying on it** for an appointment, audit finding, hiring decision, or any other action.
- **Derived fields are labeled as such.** `is_active` is computed by this actor from the record-level `status` string (`true` only when it equals "Active") — note a producer can be "Active" overall while individual licenses are Cancelled or Surrendered, so inspect the `licenses` array. `id` is constructed by this actor; `name`/`first_name`/`middle_name`/`last_name` and the parsed `address_*` fields are derived from raw source strings; `jurisdiction` is set to `OH`. Treat derived fields as conveniences, not source-of-truth.
- **Personal data / GDPR.** Output includes personal data about individuals (names, address, phone). If you process data about EU/UK residents you may act as an independent data controller under GDPR/UK GDPR and are solely responsible for having a lawful basis and honoring data-subject rights.
- **Prohibited uses (FCRA).** The output is **not a "consumer report"** and StackRelay is not a consumer reporting agency. **Do not use this data for FCRA-regulated purposes** — determining an individual's eligibility for credit, insurance coverage, employment, housing, or similar decisions. Verifying that a producer or agency holds an active Ohio insurance license for regulatory-compliance purposes is the intended use. Do not use the data to harass or profile individuals, and note that bulk city/ZIP lead-generation output remains subject to applicable telemarketing, anti-spam, and privacy laws.
- **Not affiliated.** Independently developed by StackRelay; not affiliated with, endorsed by, or operated by the Ohio Department of Insurance.
- **A disclaimer travels with every run** in the key-value store record `META`, and every dataset row carries `source_name`, `source_url`, and `scraped_at` provenance fields.
- **Full terms:** see [DEVELOPER\_TERMS.md](DEVELOPER_TERMS.md) — provided AS-IS, no warranty, liability capped at fees paid, Kansas governing law. By running this actor you agree to those terms.

### Data source

Public data from the [Ohio Department of Insurance Agent/Agency Locator](https://gateway.insurance.ohio.gov/UI/ODI.Agent.Public.UI/AgentSearch.mvc/DisplaySearch). No credentials or API key required. This actor accesses only the public, logged-out lookup — no login, paywall, or access control is bypassed.

# Actor input Schema

## `entityType` (type: `string`):

IND = individual producer/agent, BUS = business entity/agency.

## `lastName` (type: `string`):

Agent last name. Partial matches supported. (Individual search only.)

## `firstName` (type: `string`):

Agent first name. Optional — narrows results when combined with lastName. (Individual search only.)

## `middleName` (type: `string`):

Agent middle name. (Individual search only.)

## `businessName` (type: `string`):

Agency or business entity name. Partial matches supported. Must be combined with city, zip, or npn — name alone is not accepted by the ODI API. (Business entity search only.)

## `npn` (type: `string`):

National Producer Number. Returns exactly one matching record. Works for both IND and BUS.

## `licenseNumber` (type: `string`):

Ohio-issued license number. Must be combined with at least one of: lastName, npn, city, or zip — the ODI API does not accept license number alone.

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

Filter by city of business address. Works as a standalone search field.

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

Filter by ZIP code of business address. Works as a standalone search field.

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

Filter by license type. Leave blank to return all types.

## `residenceType` (type: `string`):

Filter by resident vs. non-resident Ohio license. Leave blank to return both.

## `activeOnly` (type: `boolean`):

When true, only returns producers with at least one active Ohio license.

## `fetchDetails` (type: `boolean`):

When true (recommended), follows each result's detail page to retrieve NPN and full license/LOA history. When false, individual (IND) searches return no NPN and no license data — only name, address, phone, and status. Business entity (BUS) searches always include NPN regardless of this setting. Only disable for high-volume pre-filtering when you plan to re-run matched records with fetchDetails=true.

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

Cap on records pushed to the dataset. The actor paginates automatically up to this limit.

## `pageSize` (type: `integer`):

Results per API page. 50 is the ODI API maximum.

## Actor input object example

```json
{
  "entityType": "IND",
  "city": "Columbus",
  "licenseType": "",
  "residenceType": "",
  "activeOnly": false,
  "fetchDetails": true,
  "maxResults": 200,
  "pageSize": 50
}
```

# 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 = {
    "city": "Columbus"
};

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

# Run the Actor and wait for it to finish
run = client.actor("stackrelay/ohio-insurance-license").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "city": "Columbus"
}' |
apify call stackrelay/ohio-insurance-license --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=stackrelay/ohio-insurance-license",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/xJ3zuH98SEHA5Qgg1/builds/petB5IEbFlV3GBteY/openapi.json
