Minnesota DLI Professional License Scraper avatar

Minnesota DLI Professional License Scraper

Pricing

from $1.20 / 1,000 results

Go to Apify Store
Minnesota DLI Professional License Scraper

Minnesota DLI Professional License Scraper

Scrape contractor and tradesman license records from Minnesota DLI (Department of Labor and Industry). Downloads bulk CSV regulant lists — residential contractors, electricians, plumbers, roofers, mechanical bond holders and more. No browser needed, direct file download.

Pricing

from $1.20 / 1,000 results

Rating

0.0

(0)

Developer

Haketa

Haketa

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

4 hours ago

Last modified

Share

Minnesota DLI Professional License Scraper — Contractor, Electrician, Plumber, Roofer & Boiler License Data Extractor

The most complete Minnesota Department of Labor and Industry (DLI) license data extraction tool on Apify. Download the full public regulant export for residential contractors, electricians, plumbers, roofers, boiler operators, elevator constructors, high-pressure pipefitters, mechanical contractor bond holders, and manufactured home installers — structured, normalized, and ready for compliance, B2B sales, recruiting, credentialing, and analytics workflows across Minneapolis, Saint Paul, Rochester, Duluth, and every other Minnesota market.

Apify Actor


What This Actor Does

The Minnesota DLI Professional License Scraper is a production-grade Apify Actor that extracts the complete public regulant database published by the Minnesota Department of Labor and Industry (DLI) — the state agency that licenses contractors, registers tradespeople, and tracks bond and enforcement records across Minnesota's construction, mechanical, and building trades industries.

In a single run (typically 30–90 seconds for the full ZIP), the actor returns thousands of structured records spanning ten distinct license categories that DLI publishes as bulk CSV exports — no browser, no login, no API keys, no captcha solving. Each record is normalized into a single flat JSON schema so downstream consumers (warehouses, CRMs, BI tools) can ingest the entire dataset without per-category branching logic.

The ten Minnesota DLI license categories covered:

  • Electrical — Class A/B masters, journeyworkers, installers, power-limited technicians, electrical contractors
  • Plumbing — master, journeyworker, and restricted plumbers plus plumbing contractors
  • Residential Contractors — Residential Building Contractor (RBC) and Residential Remodeler (RR) licenses
  • Contractor Registrations — registered (non-licensed) construction contractors using the residential-exemption pathway
  • Mechanical Contractor Bond — surety bond filings for mechanical / HVAC contractors with bond amount and surety company
  • Boiler — operator and inspector credentials (1st-class, 2nd-class, low-pressure, special)
  • High Pressure Piping — pipefitter and pipefitting contractor licenses
  • Residential Roofer — standalone Minnesota residential roofer licenses
  • Manufactured Home Installer — licensed installers of HUD-code manufactured housing
  • Elevator — elevator constructor mechanics, limited mechanics, and elevator contractors

Each record carries license number, status, original issue date, expiration date, full mailing address, entity classification (Business vs. Personal), DBA, responsible/qualifying individual, phone, email (when published), bond amount + surety (where applicable), and enforcement action flags — making this the fastest path to a clean Minnesota tradesperson and contractor dataset for compliance, lead generation, credentialing, and market intelligence use cases.

Why scrape DLI yourself when this exists?

DLI publishes the raw data as ten separate CSV files (plus one combined ZIP) on secure.doli.state.mn.us. Most teams who try the DIY route hit the same wall of papercuts:

  • Per-category CSVs have slightly different column orderings (Electrical exposes Phone/Email, Mechanical Bond exposes Bond Amount/Surety, Roofer omits both) so naive pd.concat() joins fail
  • Header casing drifts between exports (Lic_Number vs Lic_No vs License_Number) and breaks string-keyed parsers
  • The Bus_Pers field is a single-letter code (B/P) that must route Name into either businessName or individualName
  • Addr1 + Addr2 come as separate columns and must be merged; ZIPs ship with a -0000 suffix that needs stripping
  • Date columns alternate between MM/DD/YYYY and YYYY-MM-DD depending on category
  • No incremental update endpoint exists — you must redownload the full export every run
  • DLI occasionally adds new categories (Residential Roofer was added later; Mechanical Bond was promoted to its own export) — homegrown parsers silently miss new files
  • The official site is HTTPS-only with a strict TLS profile that trips older Python requests setups

This actor solves all of that: it streams the CSVs (or the combined ZIP) directly, applies a 100+ entry header alias table to survive schema drift, normalizes dates and ZIPs, routes Name into the correct field by entity type, applies your filters, and outputs deterministic JSON — no parsing scripts, no schema babysitting, no glue code.


Quick Start

One-Click Run

  1. Click "Try for free" on the Apify Store page for haketa/minnesota-dli-license-scraper
  2. Pick specific categories (prefilled with Mechanical_Contractor_Bond and Residential_Roofer) or tick Download ZIP (All Categories) to grab everything in one shot
  3. Hit Start — full export ready in under two minutes
  4. Download as JSON, CSV, Excel, or HTML from the Apify dataset view, or stream to Google Sheets / BigQuery / your CRM via built-in integrations

API Run (Python)

from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("haketa/minnesota-dli-license-scraper").call(run_input={
"categories": ["Residential_Contractors", "Plumbing", "Electrical"],
"statusFilter": "issued",
"maxRecords": 0
})
for record in client.dataset(run["defaultDatasetId"]).iterate_items():
print(record["licenseNumber"], record["name"], record["city"], record["status"])

API Run (Node.js / TypeScript)

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('haketa/minnesota-dli-license-scraper').call({
useZip: true,
statusFilter: 'issued',
maxRecords: 0,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(`Got ${items.length} active Minnesota DLI license records`);
const minneapolis = items.filter(r => (r.city || '').toLowerCase() === 'minneapolis');
console.log(` of which ${minneapolis.length} are in Minneapolis`);

API Run (cURL)

curl -X POST "https://api.apify.com/v2/acts/haketa~minnesota-dli-license-scraper/runs?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"categories": ["Residential_Roofer"],
"statusFilter": "issued",
"maxRecords": 0
}'

How It Works

DLI publishes ten category-specific CSV files plus a single combined ZIP containing all ten, refreshed continuously as licenses are issued, renewed, expired, suspended, or revoked. This actor downloads them directly over HTTPS — no headless browser, no Puppeteer, no Playwright, no API key.

Source FileURL PatternCoverage
MNDLILicRegCertExport_Electrical.csvhttps://secure.doli.state.mn.us/ccld/data/MNDLILicRegCertExport_Electrical.csvElectrical contractors, masters, journeyworkers, installers, PLTs
MNDLILicRegCertExport_Plumbing.csvsame path with _PlumbingMaster/journeyworker/restricted plumbers, plumbing contractors
MNDLILicRegCertExport_Residential_Contractors.csv..._Residential_ContractorsRBC, RR licenses
MNDLILicRegCertExport_Contractor_Registrations.csv..._Contractor_RegistrationsRegistered (non-licensed) construction contractors
MNDLILicRegCertExport_Mechanical_Contractor_Bond.csv..._Mechanical_Contractor_BondMechanical/HVAC contractor bonds with surety + bond amount
MNDLILicRegCertExport_Boiler.csv..._BoilerBoiler operators, inspectors, special licenses
MNDLILicRegCertExport_High_Pressure_Piping.csv..._High_Pressure_PipingHigh-pressure pipefitters, pipefitting contractors
MNDLILicRegCertExport_Residential_Roofer.csv..._Residential_RooferResidential roofer licenses
MNDLILicRegCertExport_Manufactured_Home_Installer.csv..._Manufactured_Home_InstallerManufactured-home installers
MNDLILicRegCertExport_Elevator.csv..._ElevatorElevator constructors, limited mechanics, contractors
MNDLILicRegCertExport.ziphttps://secure.doli.state.mn.us/ccld/data/MNDLILicRegCertExport.zipCombined archive of all ten files

Engineering details

  • Direct HTTPS GET via got-scraping with a desktop Chrome User-Agent — no headless browser, no API key
  • Two ingestion modes — individual category CSVs (categories) or combined MNDLILicRegCertExport.zip (useZip: true)
  • In-memory ZIP extraction via unzipper — archive streamed to /tmp, expanded, each CSV parsed in sequence
  • 3-attempt retry with linear backoff (2 s, 4 s) on every download
  • 100+ entry HEADER_ALIASES map absorbs DLI's column-name drift (Lic_Number, License_Number, Lic_No, Lic_Nbr, Registration_Number, Certificate_Number all map to licenseNumber)
  • Entity-type routingBus_Pers=BbusinessName; PindividualName; merged name preserved as convenience
  • Address mergingAddr1 + Addr2 joined with a comma; ZIP normalization strips trailing -0000; date normalization coerces MM/DD/YYYY, YYYY/MM/DD, YYYY-MM-DD to ISO
  • Status filterissued keeps active licenses only; all keeps every status
  • 200-record batched writes keep memory flat even on the full ZIP
  • Graceful partial-save on failure — if DLI hiccups mid-run, every record collected so far is committed before the actor exits non-zero

Input Parameters

{
"categories": ["Mechanical_Contractor_Bond", "Residential_Roofer"],
"useZip": false,
"statusFilter": "all",
"maxRecords": 200,
"requestDelay": 200,
"proxyConfiguration": { "useApifyProxy": false }
}

Parameter reference

ParameterTypeDefaultDescription
categoriesarray<string>[] (= all 10)DLI license categories to scrape — one CSV download per category. Allowed values: Electrical, Plumbing, Residential_Contractors, Contractor_Registrations, Mechanical_Contractor_Bond, Boiler, High_Pressure_Piping, Residential_Roofer, Manufactured_Home_Installer, Elevator. Leave empty to scrape all categories.
useZipbooleanfalseWhen true, downloads the single combined MNDLILicRegCertExport.zip archive and extracts all ten CSVs in one round trip. Overrides categories. Recommended for full-export jobs.
statusFilterstringallissued returns only currently active/issued licenses. all returns every record including expired, revoked, suspended, surrendered, and retired.
maxRecordsinteger200Cap total output across all categories. 0 = unlimited. The default of 200 exists to keep first-time test runs cheap; set 0 for production scrapes.
requestDelayinteger200Milliseconds to sleep between category downloads in individual-CSV mode. Has no effect in ZIP mode.
proxyConfigurationobject{ useApifyProxy: false }Optional Apify proxy settings. Almost never needed — DLI does not rate-limit or geo-block its public file downloads.

Output Schema

Every record — regardless of which DLI category it came from — uses the same flat JSON schema. Category-specific fields like bondAmount, bondCompany, phone, and email are present only when the underlying CSV publishes them.

Field reference

FieldTypeAlways PresentDescription
licenseNumberstringyes (when present in source)DLI-issued license, registration, or certificate number — typically a 2-letter category prefix plus digits
licenseTypestringusuallyLicense type as reported by DLI (e.g., Electrical Contractor, Master Plumber)
licenseSubtypestringsometimesSpecialty or sub-class (e.g., Class A, Restricted, Limited)
sourceCategorystringyesOne of the ten file categories — Electrical, Plumbing, etc. — useful for downstream routing
entityTypestringyesNormalized Business or Personal (derived from DLI's single-letter B/P code)
businessNamestringwhen entityType=BusinessFirm / company name
individualNamestringwhen entityType=PersonalPerson name
namestringyesConvenience merged name field (business name or individual name)
dbastringoptionalDoing-Business-As name
responsibleIndividualstringoptionalQualifying person on file for firm/contractor licenses
statusstringyesRaw status (Issued, Expired, Revoked, Suspended, Surrendered, etc.)
issueDatestringusuallyOriginal issue date in YYYY-MM-DD format
expirationDatestringusuallyCurrent expiration date in YYYY-MM-DD format
addressstringusuallyFull mailing address (Addr1 + Addr2 merged)
citystringusuallyCity
statestringusuallyTwo-letter US state abbreviation
zipCodestringusuallyZIP code (-0000 suffix stripped)
countystringoptionalMinnesota county name (when published)
phonestringoptionalContact phone number
emailstringoptionalContact email address
bondAmountstringMechanical_Contractor_Bond onlySurety bond face value (e.g., 25000)
bondCompanystringMechanical_Contractor_Bond onlyIssuing surety/bond company
enforcementActionstringoptionalActive enforcement-action flag
renewalInProgressstringoptionalIndicator that a renewal is currently being processed
scrapedAtstringyesISO-8601 timestamp of extraction

Example: Residential Building Contractor (Business)

{
"licenseNumber": "BC999999",
"licenseType": "Residential Building Contractor",
"licenseSubtype": "BC",
"sourceCategory": "Residential_Contractors",
"entityType": "Business",
"businessName": "NORTHERN LIGHTS BUILDERS LLC",
"individualName": null,
"name": "NORTHERN LIGHTS BUILDERS LLC",
"dba": "NORTHERN LIGHTS HOMES",
"responsibleIndividual": "ANDERSON, ERIK J",
"status": "Issued",
"issueDate": "2018-04-12",
"expirationDate": "2027-03-31",
"address": "1234 NICOLLET AVE, SUITE 200",
"city": "Minneapolis",
"state": "MN",
"zipCode": "55403",
"county": "Hennepin",
"phone": "612-555-0100",
"email": "info@example-builders.test",
"bondAmount": null,
"bondCompany": null,
"enforcementAction": null,
"renewalInProgress": null,
"scrapedAt": "2026-05-16T09:00:00.000Z"
}

Example: Master Plumber (Personal) — abbreviated

{
"licenseNumber": "PM099999",
"licenseType": "Master Plumber",
"sourceCategory": "Plumbing",
"entityType": "Personal",
"individualName": "JOHNSON, MARK D",
"name": "JOHNSON, MARK D",
"status": "Issued",
"issueDate": "2009-06-30",
"expirationDate": "2026-09-30",
"address": "789 GRAND AVE",
"city": "Saint Paul",
"state": "MN",
"zipCode": "55105",
"county": "Ramsey",
"scrapedAt": "2026-05-16T09:00:00.000Z"
}

Example: Mechanical Contractor Bond — abbreviated

{
"licenseNumber": "MB099999",
"licenseType": "Mechanical Contractor Bond",
"sourceCategory": "Mechanical_Contractor_Bond",
"entityType": "Business",
"businessName": "TWIN CITIES HVAC SERVICES INC",
"name": "TWIN CITIES HVAC SERVICES INC",
"status": "Issued",
"city": "Rochester",
"state": "MN",
"zipCode": "55901",
"county": "Olmsted",
"bondAmount": "25000",
"bondCompany": "MIDWEST SURETY COMPANY",
"scrapedAt": "2026-05-16T09:00:00.000Z"
}

License Status Reference

DLI's status column carries these canonical values. Use statusFilter: "issued" to keep only the first row; use all for everything.

StatusPractice/Operate?Meaning
IssuedYesLicense is currently active and in good standing
ExpiredNoFailed to renew by the deadline; may be reinstated
RevokedNoTerminated by Board action
SuspendedNoTemporarily barred from practice
SurrenderedNoVoluntarily relinquished (often pre-disciplinary)
RetiredNoRetired credential — no longer practicing
CancelledNoAdministratively cancelled
PendingConditionalApplication in progress

Tip: When statusFilter is set to issued, the actor performs a case-insensitive exact match on Issued. All other statuses are filtered out and tallied in the totalSkipped log line.


Use Cases

Construction & Trades B2B Lead Generation

Suppliers, distributors, software vendors, and equipment rental companies use the Minnesota DLI dataset to build clean targeted lead lists for the Upper Midwest construction market:

  • Pull every active Residential Building Contractor in the Twin Cities metro for a roofing-material or siding catalog mail drop
  • Segment Mechanical Contractor Bond holders by bond amount to focus on larger HVAC firms for distributor onboarding
  • Build territory routes by joining city / county on Hennepin, Ramsey, Olmsted, Dakota, Anoka, Washington
  • Enrich CRM accounts (Salesforce, HubSpot, Pipedrive) with current license status, expiration, and responsible-individual fields keyed off the DLI license number
  • Target license-class upgrades — sell exam prep, CE, or insurance to journeyworkers approaching the master's exam window

Construction Compliance, Credentialing & Verification

GCs, developers, property managers, REITs, and GL insurers in Minnesota use DLI data to enforce credential rules on every job:

  • Pre-bid verification of every sub's electrical, plumbing, HVAC, or roofing license before awarding work
  • Automate monthly re-checks for every subcontractor on the master vendor list — flip a record from Issued to Expired and trigger a procurement alert
  • Capture enforcementAction flags so a sub with a fresh administrative penalty surfaces in the next compliance review
  • Build audit-ready logs with the timestamped scrapedAt field for OSHA, MSHA, or insurance carrier audits
  • Validate bond coverage for mechanical contractors at policy bind by joining bondCompany + bondAmount with the GL underwriter's bond minimums

Insurance Underwriting (Contractor & Surety)

GL carriers, surety bond agencies, and workers comp carriers writing Minnesota contractor policies use DLI data to:

  • Verify license validity at quote, bind, and annual renewal
  • Price residential roofer policies using the standalone Residential Roofer roster (a hard market in MN after multiple hail-driven loss years)
  • Cross-check Mechanical Contractor Bond filings against the surety's own book to find book-of-business overlap
  • Monitor portfolio risk — flag insureds whose status changes mid-policy from Issued to Suspended or Revoked
  • Process bond claims faster with pre-verified licensee information including the responsible qualifying individual

Recruiting, Staffing & Trade Workforce Analytics

Tradesperson recruiters, union halls, and apprenticeship programs use the DLI roster as the closest thing Minnesota has to a complete licensed-trade workforce census:

  • Source candidates for journeyworker electrician, plumber, or pipefitter openings by city or county
  • Map apprentice-to-journeyworker conversion by tracking individuals across years of snapshots
  • Quantify trade workforce supply for IBEW, UA, Sheet Metal, and other local trade unions
  • Identify retired or expired credentials as a re-engagement pool for back-to-work programs

Real Estate & Property Development Due Diligence

Homebuyers, real estate attorneys, title insurers, and home inspectors use DLI data to verify the people who worked on a property:

  • Validate that the contractor on a permit was licensed at the date the work occurred (combined with archived run snapshots)
  • Identify the responsible qualifying individual behind an LLC contractor that has since dissolved
  • Run pre-purchase verification on the roofers and remodelers who touched the home — critical in hail-prone Minnesota where roof age and roofer credentials drive insurability
  • Support construction-defect litigation discovery with full license history across multiple categories

Market Research, Competitive Intelligence & M&A

Private equity firms and management consultants use DLI data to size and segment Minnesota's construction market:

  • Quantify total active residential contractor count in MN over time as a leading indicator for housing-starts demand
  • Build target lists for HVAC, plumbing, or electrical roll-up plays with bond amount as a proxy for firm size
  • Track new-license issuance rates as an inflow indicator for the regional trades labor pool
  • Benchmark license-density per capita across MN metros — Twin Cities vs. greater Minnesota

Government, Regulatory Research & Investigative Journalism

State legislators, academic policy researchers, and investigative reporters use DLI data to study Minnesota's construction-industry regulation:

  • Investigate enforcement-action patterns — which categories see the most discipline?
  • Map license density vs. housing permit volume to study under- or over-supply of trades labor
  • Track post-disaster contractor influx — out-of-state roofer registrations spike after major hail events
  • Cover unlicensed contracting by joining DLI records to municipal permit databases and flagging the gap

Marketing, Direct Mail & Litigation

Trade media, direct-mail houses, attorneys, and forensic experts also tap the dataset to:

  • Build print-distribution lists for trade magazines targeting MN plumbers, electricians, or HVAC techs
  • Power trade-show invite mailings for IBS, AHR Expo, NECA, MCAA regional events
  • Verify expert witness credentials before engagement
  • Build chronologies of an individual or firm's license history across snapshots
  • Pull complete public address-of-record history for service-of-process / subpoena prep

Sample Queries & Recipes

Recipe 1: All active residential contractors statewide (lead list)

{ "categories": ["Residential_Contractors", "Contractor_Registrations"], "statusFilter": "issued", "maxRecords": 0 }

Recipe 2: Full Minnesota DLI export in one shot (fastest path)

{ "useZip": true, "statusFilter": "all", "maxRecords": 0 }

Recipe 3: Active master plumbers (compliance / recruiting)

{ "categories": ["Plumbing"], "statusFilter": "issued", "maxRecords": 0 }

Then filter downstream: [r for r in items if (r.get("licenseType") or "").lower().startswith("master")]

Recipe 4: All Mechanical Contractor Bond filings with surety info

{ "categories": ["Mechanical_Contractor_Bond"], "statusFilter": "issued", "maxRecords": 0 }

Records ship with bondAmount + bondCompany populated.

Recipe 5: Residential roofer roster (insurance underwriting)

{ "categories": ["Residential_Roofer"], "statusFilter": "issued", "maxRecords": 0 }

Recipe 6: Sample 50 records before committing to a full scrape

{ "categories": ["Electrical"], "statusFilter": "all", "maxRecords": 50 }

Recipe 7: Boiler operators + high-pressure pipefitters (industrial workforce)

{ "categories": ["Boiler", "High_Pressure_Piping"], "statusFilter": "issued", "maxRecords": 0 }

Integration Examples

Google Sheets

Set up an Apify schedule running this actor nightly at 02:00 Central, add the "Export to Google Sheets" integration, and receive a fresh MN DLI license CSV in your Sheet every morning ready for VLOOKUPs, pivot tables, and conditional-format dashboards.

Make.com / Zapier / n8n

Use the official Apify connector on any major automation platform. Trigger downstream workflows on new records (alert sales on net-new Twin Cities contractors), status changes (IssuedSuspended opens a compliance ticket), address changes (territory rebalancing), or new enforcement actions (Slack / Teams push).

Power BI / Tableau / Looker

Connect the Apify REST API as a data source and refresh on the actor's schedule. Useful MN DLI dashboards: active license count by category/county, roofer issuance rate (hail-event indicator), mechanical bond size distribution, license expiration calendar (30/60/90-day), contractor density heat maps across Hennepin, Ramsey, Dakota, Anoka, Washington, Olmsted, Saint Louis, Stearns counties.

Postgres / Snowflake / BigQuery / Redshift

Use the Apify webhook integration to POST run results directly to your warehouse ingestion endpoint after every scheduled run. The flat JSON schema maps 1:1 to a single normalized table (license_number as PRIMARY KEY, source_category for routing, dates as DATE, bond_amount as NUMERIC) — no JSON unnesting required.

Salesforce / HubSpot / Pipedrive CRM Enrichment

Trigger an Apify run nightly, then upsert against your Account records keyed on DLI license number. Status-change events can auto-create Tasks, open Cases, or trigger sequences. Pair with the responsibleIndividual field to populate Contact records for the qualifying person at firm-licensed accounts.

Direct Mail & Email Service Providers

Export the dataset as CSV and load into Lob, Click2Mail, Mailchimp, Klaviyo, or HubSpot Marketing — DLI publishes business mailing addresses (and phone/email on some categories) that map cleanly to direct-mail and email-marketing input requirements.


Major Minnesota Markets at a Glance

Metro / RegionCountyPopulationConstruction Relevance
MinneapolisHennepin430K (3.7M metro)Largest construction market in MN; densest electrical, plumbing, HVAC base
Saint PaulRamsey311KState capital; commercial and government construction
RochesterOlmsted121KMayo Clinic expansion drives mechanical, electrical, piping demand
DuluthSaint Louis87KPort/industrial center; high-pressure piping, boiler work
BloomingtonHennepin89KMall of America corridor; commercial GC + HVAC density
PlymouthHennepin80KAffluent western suburb; high residential remodel + roofer volume
EdinaHennepin53KTear-down + luxury remodel hotspot
Maple GroveHennepin71KFastest-growing NW suburb; new-construction roofer demand
Saint Cloud / MankatoStearns / Blue Earth69K / 45KCentral + south-central MN trades hubs
Eagan / BurnsvilleDakota68K / 64KSouth-metro mechanical / HVAC concentration

Cost & Performance

MetricValue
EngineDirect CSV / ZIP download — no browser overhead
Runtime (single category, default maxRecords:200)5–15 seconds
Runtime (full ZIP, unfiltered)30–90 seconds
Cost per runPay-per-event — typically a few cents per full export
Pricing modelPay-per-event (transparent per-record pricing)
Data freshnessLive at run time — DLI exports refresh continuously
Auth requiredNone
Proxy requiredNone (Apify proxy supported but not needed)
ConcurrencySafe to run multiple parallel filtered configurations
Memory footprint256 MB default; up to 4096 MB available for the full ZIP scrape
Retries3 attempts per file with linear backoff (2 s, 4 s)
Failure modeGraceful — partial results are written before non-zero exit

  • Public data only — every field in this dataset is published by the Minnesota Department of Labor and Industry at secure.doli.state.mn.us under Minnesota Government Data Practices Act (Minn. Stat. Ch. 13)
  • No PHI / no patient data — these are professional license records, not health information; HIPAA does not apply
  • No SSNs, DOBs, or financial account data — only license-related public information is published by DLI
  • Address data is the business or practice address of record with DLI (in most cases business mailing address; for individual licensees it may be a home address where that is the address-of-record)
  • Email / phone fields are published only where the licensee provided them to DLI and DLI included them in the public export
  • The dataset must not be used for unlawful purposes including identity fraud, harassment, stalking, or any use that violates the Minnesota Government Data Practices Act, CAN-SPAM, TCPA, GDPR, CCPA, or other applicable laws
  • Robots.txt / ToS — DLI publishes the CSV / ZIP exports for public download; this actor only consumes the documented bulk-export endpoints
  • Compliance with direct-mail, telemarketing, and email-marketing law is the responsibility of the data consumer

Important: DLI license data is provided for licensing transparency. Anyone using this dataset for hiring, lending, insurance, or housing decisions should also consider FCRA-style permissible-purpose obligations and verify the most current status directly with DLI before taking adverse action.


Frequently Asked Questions

How fresh is the data?

DLI updates its bulk CSV and ZIP exports continuously as licenses are issued, renewed, expired, suspended, or revoked. Every run downloads the latest version live from DLI's server — typically no more than a few hours stale.

How many records will I get?

Counts shift constantly. Across all ten categories expect roughly tens of thousands of active records plus a longer tail of expired/inactive history when statusFilter: "all". Set maxRecords: 0 for the full export, or maxRecords: 50 for a cheap sampler.

Does this scraper require login or API keys to DLI?

No. DLI publishes the CSV files and combined ZIP as public downloads with no authentication, no captcha, and no API key. You only need an Apify account.

Does this work for other states (Wisconsin, Iowa, North Dakota, South Dakota)?

Not this actor — DLI is Minnesota-specific. Haketa maintains separate actors for other state licensing boards. See the Related Actors section.

Can I use this for license verification at scale?

Yes. Many GCs and insurers run this nightly, diff against the previous day, and trigger alerts on status changes via Make.com / n8n / Slack / Teams.

Are licensee emails and phones included?

Where DLI publishes them. Electrical, Plumbing, and most personal licensee categories include phone and email when the licensee provided them; bond and registration categories often do not. Check the field on each record.

What's the difference between categories mode and useZip mode?

categories mode makes one HTTPS GET per selected category (faster for partial scrapes). useZip: true makes one GET for the combined archive containing all ten CSVs (faster for full exports). Output records are identical.

Why is the default maxRecords set to 200?

To keep first-time test runs cheap. Set maxRecords: 0 for production scrapes.

Does the actor deduplicate?

DLI's exports are already deduplicated by license number. If the same business holds licenses in multiple categories, each license appears as its own record.

What's responsibleIndividual?

For firm/business licenses, MN DLI requires a qualifying individual (the "responsible individual") who holds the personal credential the firm operates under. This field exposes that person's name when DLI publishes it.

Residential_Contractors vs Contractor_Registrations? Boiler vs High_Pressure_Piping?

Residential Contractors hold a true license (RBC or RR). Contractor Registrations cover smaller sub-threshold contractors using MN's registration pathway. Boiler licenses cover operators/inspectors of pressure vessels; High Pressure Piping licenses cover contractors/pipefitters installing high-pressure pipe systems (typically above 15 psi steam / 160 psi water).

Is residential or proxy access required?

No. DLI does not block, geo-restrict, or rate-limit public file downloads. Optional Apify proxy is supported via proxyConfiguration for orgs that require it.

Is there a historical snapshot version of the data?

Not directly — DLI publishes a point-in-time export. To build a history, schedule this actor daily/weekly and archive each dataset run.

Can I get federal contractor (SAM.gov) data through this actor?

No — see the SAM.gov Federal Contractor Entity Scraper and pair the two datasets.

Does this actor work with the Apify Free Plan?

Yes — full functionality on the free tier.

Can I run this on a schedule automatically?

Yes — Apify's Scheduler triggers any cron expression. Combine with webhooks for a fully automated nightly compliance pipeline.

What formats can I export the data in?

JSON, CSV, Excel (XLSX), HTML, XML, RSS — directly from the Apify dataset view. The API also supports JSON Lines.

Does this dataset include workers comp claims or injury data?

No. DLI's bulk regulant exports cover licensing and registration only. Workers comp claim data is handled separately by DLI's Workers Compensation Division and is not part of these public CSV files.


If you need licensing data from other US states or related construction/government datasets, these sibling actors all live on the same publisher account:


Comparison vs. Alternatives

ApproachSetup timeData freshnessCost (full export)Schema normalizationCompliance audit log
This actor< 1 minuteLiveA few cents per runBuilt-in (100+ header aliases)Automatic (scrapedAt)
Manual CSV / ZIP download5–10 min/dayLiveFreeNoneNone
Custom Python / Node script4–8 hours devLiveFree + infraDIY (and re-DIY when DLI drifts)DIY
Paid license-verification APIHours of vendor setupReal-time per-lookup$100–500+/mo, per-lookupYesYes
DLI public records requestDays–weeksStale by the time you get itVariableNoneNone

Why Pay-Per-Event Pricing?

Most data scrapers either charge a flat monthly subscription (you pay even if you don't use it) or per-Compute-Unit (unpredictable). This actor uses pay-per-event pricing, which means:

  • You only pay when the actor runs
  • Charges scale with how many records you actually save
  • Transparent line-item billing inside the Apify Console
  • No monthly minimums and no commitment
  • Free to evaluate — sample 50 records with maxRecords: 50 for pennies before scaling to the full export

Changelog

VersionDateNotes
1.0.02026-05Initial public release — 10 DLI categories supported, ZIP and per-category modes, 100+ header aliases, status filter, batched dataset writes, graceful partial-save on failure

Keywords

Minnesota DLI license lookup · MN contractor verification · Minneapolis license data · Minnesota plumbing electrician license · DLI license search · Minnesota builder license lookup · Minnesota Department of Labor and Industry scraper · MN DLI scraper · Minnesota residential building contractor data · Minnesota residential remodeler license · Minnesota electrical contractor license · Minnesota master plumber lookup · Minnesota journeyworker plumber data · Minnesota high pressure piping license · Minnesota boiler operator license · Minnesota elevator constructor license · Minnesota residential roofer license · Minnesota manufactured home installer license · Mechanical contractor bond Minnesota · MN HVAC contractor surety bond data · Minneapolis contractor database · Saint Paul contractor lookup · Rochester MN contractor data · Duluth contractor license · Bloomington MN contractor list · Plymouth Minnesota contractor verification · Edina MN remodeler license · Maple Grove roofer license · Hennepin County contractor database · Ramsey County license data · Olmsted County contractor list · MN contractor lead generation · Minnesota construction compliance API · DLI CSV download · MN tradesperson workforce data · Apify Minnesota DLI actor · contractor license verification Minnesota · Minneapolis HVAC bond lookup · Saint Paul electrician database · Minnesota contractor enforcement action data · Twin Cities contractor lead list · Minnesota construction permit cross-reference · MN contractor credentialing automation


Support

  • Bug reports: Use the Issues tab on the Apify Store page for haketa/minnesota-dli-license-scraper
  • Feature requests: Same place, please describe your use case (Wisconsin / Iowa / North Dakota / South Dakota equivalents are popular asks)
  • Direct contact: Through the Apify developer profile

If this actor saves you time, a 5-star rating on the Apify Store helps other Minnesota construction, compliance, and insurance teams discover it. Thank you!