# Louisiana Contractor Licenses Scraper (`automation-lab/louisiana-contractor-license-leads-scraper`) Actor

Search the official LSLBC registry and export license identity, status and dates, classifications, mailing address, phone, and publicly displayed email.

- **URL**: https://apify.com/automation-lab/louisiana-contractor-license-leads-scraper.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.92 / 1,000 item extracteds

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

## Louisiana Contractor Licenses Scraper

Search **Louisiana contractor licenses** in the official Louisiana State Licensing Board for Contractors (LSLBC) registry and export structured contractor records.

The Actor accepts business-name, person-name, license-number, and city searches. It follows each match to the public registry detail, then returns license identity, status and dates, classifications, qualifying parties, mailing address, phone, and publicly displayed email.

Use it for credential checks, compliance-list refreshes, contractor research, and source-attributed sales lists.

### What does Louisiana Contractor Licenses Scraper do?

The Actor automates the public search workflow at `arlspublic.lslbc.louisiana.gov`.

For every input search it:

1. opens an anonymous LSLBC search session;
2. submits the selected filters;
3. reads matching contractor identities;
4. fetches each public contractor detail;
5. normalizes all displayed licenses and classifications;
6. removes duplicate contractors across searches;
7. saves accepted records to the default Apify dataset.

It does not guess emails, enrich records from third-party websites, or claim that a record is current beyond the source timestamp.

### Who is it for?

- **Compliance teams** checking a contractor's displayed license status and expiry.
- **Construction suppliers** refreshing source-attributed Louisiana prospect lists.
- **Insurers and risk teams** reviewing classifications and qualifying parties.
- **Market researchers** comparing licensed businesses by Louisiana city.
- **Data engineers** loading repeatable registry snapshots into a warehouse.
- **Developers** integrating LSLBC results through the Apify API or MCP.

### Why use this Actor?

The public portal is designed for interactive searches, not reusable exports.

This Actor provides:

- multiple searches in one run;
- consistent JSON, CSV, Excel, XML, and RSS dataset exports;
- detail fields instead of search-card summaries only;
- active-only filtering after license details are parsed;
- bounded concurrency and retries;
- stable field names for scheduled workflows;
- direct links to the official source response used for each record.

### What data is extracted?

| Field | Meaning |
| --- | --- |
| `businessName` | Contractor name displayed by LSLBC |
| `licenseNumber` | First displayed license number |
| `licenseType` | Type of the primary license |
| `licenseStatus` | Status of the primary license |
| `isActive` | Whether at least one displayed license is active |
| `effectiveDate` | Primary-license effective date |
| `expirationDate` | Primary-license expiration date |
| `firstIssuedDate` | Primary-license original issue date |
| `mailingAddress` | Public mailing address |
| `city`, `state` | Location shown in search results |
| `phone` | Public phone shown by LSLBC, or `null` |
| `email` | Public email shown by LSLBC, or `null` |
| `classifications` | Classification and qualifying-party objects |
| `licenses` | Every license displayed for the contractor |
| `matchedSearch` | Normalized input filter that found the record |
| `sourceUrl` | Official LSLBC detail endpoint |
| `scrapedAt` | Extraction timestamp in ISO 8601 format |

Contact fields are included only when the official board record displays them.

### How to search the registry

Provide one or more objects in `searches`.

Search by company:

```json
{
  "searches": [{ "companyName": "Acme" }],
  "activeOnly": true,
  "maxItems": 25
}
```

Search by license:

```json
{
  "searches": [{ "licenseNumber": "49607" }],
  "activeOnly": false,
  "maxItems": 5
}
```

Search by city:

```json
{
  "searches": [{ "city": "Baton Rouge" }],
  "activeOnly": true,
  "maxItems": 100
}
```

You can combine filters in one object or submit up to 50 searches.

### Input parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `searches` | array | required | Business, person, license-number, or city filters |
| `searches[].companyName` | string | — | Full or partial business name |
| `searches[].firstName` | string | — | Individual first name |
| `searches[].lastName` | string | — | Individual last name |
| `searches[].licenseNumber` | string | — | 1–12 digits; common LSLBC prefixes are accepted |
| `searches[].city` | string | — | Contractor mailing city |
| `activeOnly` | boolean | `true` | Keep records with at least one Active license |
| `maxItems` | integer | `100` | Maximum unique records, from 1 to 10,000 |
| `maxConcurrency` | integer | `4` | Parallel detail requests, from 1 to 10 |

Each search must contain at least one non-empty filter.

### Output example

A current license-number search returns records shaped like this:

```json
{
  "businessName": "ACME ENTERPRISES, INC.",
  "licenseNumber": "CL.49607",
  "licenseType": "Commercial License Certificate",
  "licenseStatus": "Active",
  "isActive": true,
  "effectiveDate": "02/20/2025",
  "expirationDate": "02/19/2028",
  "firstIssuedDate": "02/19/2009",
  "mailingAddress": "15751 Martin Road Roseville, MI 48066",
  "city": "Roseville",
  "state": "MI",
  "phone": "(586) ***-4800",
  "email": "b***@acme-enterprises.com",
  "classifications": [
    {
      "name": "BUILDING CONSTRUCTION",
      "qualifyingParty": "J*** L***"
    }
  ],
  "licenses": [
    {
      "number": "CL.49607",
      "type": "Commercial License Certificate",
      "status": "Active",
      "effectiveDate": "02/20/2025",
      "expirationDate": "02/19/2028",
      "firstIssuedDate": "02/19/2009"
    }
  ],
  "matchedSearch": { "licenseNumber": "49607" },
  "sourceUrl": "https://arlspublic.lslbc.louisiana.gov/Public/_DisplayOnlineDetails/…",
  "scrapedAt": "2026-09-07T15:45:13.427Z"
}
```

This is public registry data. Values can change when LSLBC updates its records.

### How much does it cost to extract Louisiana contractor licenses?

Pricing is pay per event:

- **$0.005** once when a run starts;
- a tiered fee for each contractor record saved.

The current BRONZE reference price is **$0.0032 per contractor**. The exact tier applicable to your Apify plan is displayed before starting a run.

Examples at the BRONZE rate:

| Saved contractors | Estimated Actor charge |
| ---: | ---: |
| 1 | $0.0082 |
| 25 | $0.0850 |
| 100 | $0.3250 |
| 1,000 | $3.2050 |

Empty searches incur only the start event. Duplicate, filtered, and failed records are not charged as items. Apify platform usage and proxy charges may appear separately according to your plan.

### Getting started

1. Open the Actor in Apify Console.
2. Add at least one registry search.
3. Leave `activeOnly` enabled for current-license lead lists.
4. Set a small `maxItems` while testing.
5. Click **Start**.
6. Inspect the dataset's **Contractors** view.
7. Export JSON, CSV, Excel, XML, or RSS as needed.
8. Save the input as an Apify Task for recurring runs.

### Schedule compliance and lead-list refreshes

Create an Apify Task with stable search inputs, then attach a daily, weekly, or monthly schedule.

Store the resulting dataset ID or export each run into your database. Compare records by `licenseNumber` and `businessName` to identify source changes.

The Actor produces snapshots. It does not send change alerts or compare runs itself.

### Integration patterns

Useful workflows include:

- check a license before vendor onboarding;
- refresh active contractors for a selected city;
- feed public contact fields into a CRM with source attribution;
- join classifications to supplier territory data;
- archive scheduled snapshots for internal compliance review;
- trigger an Apify webhook after a successful run;
- connect datasets to Google Sheets, Make, Zapier, or a warehouse.

Always retain `sourceUrl` and `scrapedAt` when auditability matters.

### Run with the Apify API using cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~louisiana-contractor-license-leads-scraper/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "searches": [{"city": "Baton Rouge"}],
    "activeOnly": true,
    "maxItems": 25
  }'
```

Keep API tokens in environment variables or a secret manager.

### Run with JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

const run = await client
  .actor('automation-lab/louisiana-contractor-license-leads-scraper')
  .call({
    searches: [{ companyName: 'Acme' }],
    activeOnly: true,
    maxItems: 10,
  });

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Run with Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor(
    "automation-lab/louisiana-contractor-license-leads-scraper"
).call(run_input={
    "searches": [{"licenseNumber": "49607"}],
    "activeOnly": False,
    "maxItems": 5,
})

items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)
```

### Use with MCP and AI assistants

Add the Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/louisiana-contractor-license-leads-scraper"
```

#### Claude Desktop, Cursor, and VS Code setup

Use this equivalent MCP configuration in Claude Desktop, Cursor, or VS Code:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/louisiana-contractor-license-leads-scraper"
    }
  }
}
```

Example prompts:

- “Verify Louisiana contractor license 49607 and summarize its current status.”
- “Find up to 20 active contractors matching Acme and return their classifications.”
- “Build a source-attributed list of 50 active Baton Rouge contractors with public phone and email fields.”

### Accuracy, freshness, and limitations

- LSLBC states that its public pages are provided as a courtesy and may not reflect recent changes.
- Only records returned by the public portal are available.
- Contact fields can be absent and are returned as `null`.
- Search matching behavior is controlled by LSLBC.
- Broad city or name searches can produce many candidates; use `maxItems` to bound the run.
- An opaque detail link may expire after the run and is evidence of the extraction route, not a permanent record URL.
- The Actor fails when the source returns an unrecognized or challenged page instead of silently producing empty data.
- Source markup changes can require parser maintenance.

For an authoritative licensing decision, verify the current record with LSLBC.

### Responsible use and legality

The Actor accesses anonymous, publicly displayed regulator records.

You are responsible for:

- following applicable laws and Apify's terms;
- using personal contact data for a lawful purpose;
- respecting opt-out, suppression, and outreach requirements;
- avoiding harassment, discrimination, or deceptive marketing;
- securing exported datasets and limiting retention;
- verifying important decisions against the official source.

The Actor is not legal advice and does not certify that a contractor is suitable for a project.

### Troubleshooting

Review the run log and the input first. The questions below cover the most common source and data-shape issues.

### FAQ

#### Why did my run return no records?

Check spelling and broaden one filter at a time. A license may not appear if the public portal does not currently return it. Set `activeOnly` to `false` when inspecting any status returned by a direct license search.

#### Why is email or phone null?

LSLBC does not display those fields for every contractor. The Actor does not infer, purchase, or scrape contact details from other websites.

#### Why did the run fail instead of returning an empty dataset?

The Actor detected an upstream network, rate-limit, or response-shape problem. Review the log and retry later. A failure prevents a source outage from being mistaken for a valid zero-result search.

#### Can I download every Louisiana contractor?

This Actor is optimized for bounded public registry searches. It does not promise a complete statewide roster. Use specific business, person, license, or city searches and a responsible item limit.

#### Can I search several cities or businesses together?

Yes. Add multiple objects to `searches`; results are deduplicated across the run.

### Related Automation Lab Actors

- [North Carolina Contractor License Lookup Scraper](https://apify.com/automation-lab/north-carolina-contractor-license-lookup-scraper) for NCLBGC records.
- [Arizona ROC Contractor License Scraper](https://apify.com/automation-lab/arizona-roc-contractor-license-scraper) for Arizona contractor licenses.
- [California Contractor License Lookup](https://apify.com/automation-lab/california-contractor-license-lookup-v2) for CSLB records.

Choose the Actor for the regulator that owns the license data you need.

### Support

When reporting a problem, include:

- the run URL;
- a redacted input;
- the expected search behavior;
- whether the same search currently works in the public LSLBC portal.

Do not paste private credentials or unrelated personal data into a support request.

# Actor input Schema

## `searches` (type: `array`):

One or more LSLBC searches. Each search must contain at least one field.

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

Keep only contractors with at least one license currently shown as Active.

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

Maximum unique contractor records saved across all searches.

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

Number of contractor detail pages fetched in parallel. Keep the default for source-friendly operation.

## Actor input object example

```json
{
  "searches": [
    {
      "companyName": "Acme"
    }
  ],
  "activeOnly": true,
  "maxItems": 20,
  "maxConcurrency": 4
}
```

# Actor output Schema

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

Default dataset containing all matched Louisiana contractor 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 = {
    "searches": [
        {
            "companyName": "Acme"
        }
    ],
    "activeOnly": true,
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/louisiana-contractor-license-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 = {
    "searches": [{ "companyName": "Acme" }],
    "activeOnly": True,
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/louisiana-contractor-license-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 '{
  "searches": [
    {
      "companyName": "Acme"
    }
  ],
  "activeOnly": true,
  "maxItems": 20
}' |
apify call automation-lab/louisiana-contractor-license-leads-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/louisiana-contractor-license-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/XTx6CJh6gnnhIGspd/builds/hhoXsFm2OlHubtcBk/openapi.json
