# TDLR Texas License Search Scraper (`crawlerbros/tdlr-texas-license-scraper`) Actor

Search Texas Dept. of Licensing and Regulation (TDLR) licenses across 80+ regulated trades: cosmetology, barbering, electricians, HVAC, and more. Search by name or license number, filter by trade and status, get expiration dates and contact info.

- **URL**: https://apify.com/crawlerbros/tdlr-texas-license-scraper.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** Automation, Lead generation, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

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

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

## TDLR Texas License Search Scraper

Search **Texas Department of Licensing and Regulation (TDLR)** license records — cosmetology, barbering, electricians, HVAC/A-C technicians, tow truck operators, elevator inspectors, property tax professionals, auctioneers, and 80+ other regulated trades under the TDLR umbrella. Search by license holder or business name, or jump straight to a license number. Get license status, expiration date, trade category, and contact/address info. HTTP-only against TDLR's own official public license dataset — no login, no CAPTCHA, no proxy required.

### Data source & limitations

TDLR's interactive search UI (`tdlr.texas.gov/LicenseSearch`) is currently unreachable from standard internet infrastructure (a persistent connection-level block, not a CAPTCHA or rate limit). This actor instead uses **TDLR's own official bulk license dataset**, published directly by TDLR on the Texas Open Data Portal (`data.texas.gov`) as a public, structured API — the same underlying license records the search UI draws from, refreshed on a regular schedule by TDLR. No functionality is lost: name search, license number lookup, and trade-category filtering all work the same way.

### What this actor does

- **Two modes:** search by license holder / business `name`, or direct `license number` lookup
- **84 TDLR-defined trade categories** as a filterable dropdown (cosmetology, barbering, electricians, HVAC, tow trucks, elevators, property tax, auctioneers, and more)
- **Filters:** trade category, license status (active/expired), Texas county
- **Note:** TDLR numbers licenses per trade category — the same license number can appear across multiple categories; use the trade-category filter to disambiguate
- **Empty fields are omitted** — a field only appears when TDLR actually published that data for the license

### Output per license

- `licenseNumber` — TDLR license number
- `licenseType` — TDLR trade category (e.g. `Cosmetology Operator`, `Electrical Contractor`)
- `licenseSubtype` — TDLR's internal subtype/tier code, when published
- `ownerName` — individual or business owner name
- `businessName` — business/DBA name
- `businessAddressLine1`, `businessAddressLine2`, `businessCityStateZip`, `businessCounty`, `businessPhone`
- `mailingAddressLine1`, `mailingAddressLine2`, `mailingCityStateZip`, `mailingCounty`, `ownerPhone`
- `latitude`, `longitude` — geocoded business location, when published
- `expirationDate` — ISO date the license expires/expired
- `licenseStatus` — `active` or `expired`, derived by comparing `expirationDate` to today
- `continuingEducationRequired` — `true`/`false`, when TDLR publishes a continuing-education flag for the license
- `sourceUrl` — a live, queryable link to the official record on the Texas Open Data Portal
- `recordType: "license"`, `scrapedAt`

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | string | `byName` | `byName` or `byLicenseNumber` |
| `nameQuery` | string | `Smith` | License holder or business name (mode=byName); matches either field |
| `licenseNumber` | string | `11484` | TDLR license number (mode=byLicenseNumber) |
| `licenseType` | select | – | One of 84 TDLR trade categories |
| `countyFilter` | string | – | Texas county name (e.g. `Harris`), matches business or mailing county |
| `statusFilter` | select | – | `active` or `expired` |
| `maxItems` | int | `20` | Hard cap on emitted license records (1–5000) |

#### Example: search by name

```json
{
  "mode": "byName",
  "nameQuery": "Smith",
  "maxItems": 20
}
```

#### Example: active cosmetology operators in Harris County

```json
{
  "mode": "byName",
  "nameQuery": "Garcia",
  "licenseType": "Cosmetology Operator",
  "countyFilter": "Harris",
  "statusFilter": "active",
  "maxItems": 50
}
```

#### Example: direct license number lookup

```json
{
  "mode": "byLicenseNumber",
  "licenseNumber": "11484",
  "licenseType": "A/C Contractor"
}
```

#### Example: browse a trade category

```json
{
  "mode": "byName",
  "nameQuery": "a",
  "licenseType": "Tow Truck Operator (Consent Tow)",
  "maxItems": 100
}
```

### Use cases

- **Contractor vetting** — confirm an electrician, HVAC tech, or contractor's TDLR license is active before hiring
- **Compliance & HR** — verify cosmetology/barbering staff licenses across multiple salon locations
- **Towing & auto industry** — check tow truck operator or auto parts recycler licensing status
- **Property tax industry** — validate property tax consultant/appraiser credentials
- **Lead & vendor validation** — confirm a business's TDLR license number resolves to a real, active license
- **Market research** — enumerate licensed businesses by trade category and county

### FAQ

**What is the data source?**
The Texas Department of Licensing and Regulation's official license dataset, published on the Texas Open Data Portal (`data.texas.gov`). This actor is an independent, third-party tool and is not affiliated with or endorsed by TDLR or the State of Texas.

**Why not scrape the TDLR search website directly?**
The interactive search UI was unreachable during testing (a persistent connection-level block affecting all external access, not a CAPTCHA or IP rate limit). The Texas Open Data Portal serves the identical underlying license records as a stable, public API, so no data or functionality is lost.

**How fresh is the data?**
The Texas Open Data Portal dataset is refreshed by TDLR on a regular cadence (typically daily). It is not a live real-time feed of the search UI, but it reflects the same licensing records.

**Why do some records lack `licenseType`?**
A small number of dataset rows don't have a trade category populated by TDLR itself; those fields are simply omitted rather than shown as blank.

**Why can the same license number return multiple records?**
TDLR assigns license numbers per trade category rather than globally, so a number like `11484` can independently belong to an A/C Technician, an A/C Contractor, a Master Electrician, and a Property Tax Consultant. Use `licenseType` to narrow to a specific one.

**Does this actor need a login, CAPTCHA solve, or proxy?**
No. The Texas Open Data Portal is fully public. The actor uses Apify's free `AUTO` proxy group only as a courtesy fallback.

**How is `licenseStatus` determined?**
It's derived by comparing the license's `expirationDate` to the current date — `active` if the expiration date is today or later, `expired` otherwise. TDLR's dataset does not publish a separate status field.

# Actor input Schema

## `mode` (type: `string`):

How to look up licenses.

## `nameQuery` (type: `string`):

Matches either the individual owner name or the business name (e.g. `Smith` or `Star Electrical`). Case-insensitive partial match. Optional if `licenseType` and/or `countyFilter` is set — leaving it blank then browses all licenses matching those filters.

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

The TDLR license number, e.g. `11484`. Note: TDLR numbers licenses per trade category, so the same number can be shared across different license types — use `licenseType` to disambiguate.

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

Only emit licenses of this TDLR-defined trade category. Leave unset for all types.

## `countyFilter` (type: `string`):

Only emit licenses whose business or mailing county matches (e.g. `Harris`, `Travis`, `Dallas`). Case-insensitive exact match against TDLR's own county name.

## `statusFilter` (type: `string`):

Only emit licenses that are currently active or expired, based on the license expiration date. Leave unset for both.

## `sortBy` (type: `string`):

Order results are fetched/emitted in. Defaults to license number.

## `maxItems` (type: `integer`):

Hard cap on emitted license records.

## Actor input object example

```json
{
  "mode": "byName",
  "nameQuery": "Smith",
  "licenseNumber": "11484",
  "licenseType": "",
  "statusFilter": "",
  "sortBy": "licenseNumber",
  "maxItems": 20
}
```

# Actor output Schema

## `licenses` (type: `string`):

Dataset containing all scraped TDLR license records.

# 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 = {
    "mode": "byName",
    "nameQuery": "Smith",
    "licenseNumber": "11484",
    "licenseType": "",
    "statusFilter": "",
    "sortBy": "licenseNumber",
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/tdlr-texas-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 = {
    "mode": "byName",
    "nameQuery": "Smith",
    "licenseNumber": "11484",
    "licenseType": "",
    "statusFilter": "",
    "sortBy": "licenseNumber",
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/tdlr-texas-license-scraper").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 '{
  "mode": "byName",
  "nameQuery": "Smith",
  "licenseNumber": "11484",
  "licenseType": "",
  "statusFilter": "",
  "sortBy": "licenseNumber",
  "maxItems": 20
}' |
apify call crawlerbros/tdlr-texas-license-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

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