← Guides

How-to

How to run Utah Contractor Directory & Leads Scraper (DOPL)

Step-by-step: the exact input, what each field does, and the rows that come back from UT DOPL (Construction Business Registry).

You want a contact list of Utah contractors for one trade and one county: the roofers in Salt Lake County, say, with a phone and an email for each. Utah’s Division of Professional Licensing (DOPL) publishes exactly that in its Construction Business Registry (CBR), but the search page has no county filter, its City box matches any city containing your text, and the licence number, expiry and street address sit behind a Details pop-up you open one listing at a time. Salt Lake County’s 63 roofers would mean 63 pop-ups. This actor runs the search, opens every detail record and filters to the county for you.

Read this before anything else: the CBR is an opt-in directory, not the licence roll. It lists only businesses with an active DOPL licence that chose to be listed, and the registry says so on its own page. DOPL licenses far more contractors than appear here. On 2026-10-06 the registry held 5,032 contractor listings statewide. If you need every licence holder, or want to check one licence, use DOPL’s Online License Verification instead. If you are prospecting, the opt-in works for you: every row is a business that asked to be found.

The DOPL Construction Business Registry search page, with its note that only opted-in licensees are listed
The registry's own page says it does not list every licensed contractor in Utah, only those with an active licence who opted in.

What you’ll need

Nothing but an Apify account. The actor talks to UT DOPL (Construction Business Registry) directly.

No API key, no proxy and no CAPTCHA. The registry’s search is a plain form POST that answers without a login, and the proxy setting ships switched off. You pay $0.002 per listing returned, plus Apify’s own platform usage.

Step 1: Open the actor

Open Utah Contractor Directory & Leads Scraper (DOPL) on the Apify Store and press Try for free. The actor’s own page on this site lists its live health and pricing.

The Utah Contractor Directory & Leads Scraper (DOPL) listing on the Apify Store
The listing on the Apify Store. Pricing and the nightly health record are both public.

Step 2: Fill in the input

The input form for Utah Contractor Directory & Leads Scraper (DOPL) in the Apify Console
The input form, as it appears in the Apify Console.
FieldTypeRequiredWhat it does
listOptionsOnlybooleannoIf true, skip the scrape and return Utah’s 29 counties plus every category and classification the Construction Business Registry (CBR) searches by, with its code. Free, not…
tradestringnoA DOPL classification by name or code, e.g. ‘Roofing’, ‘S280’, ‘HVAC’, ‘General Building’, ‘B100’. A word from the name works too: ‘roof’ finds S280 Roofing. For electricians…
tradesarraynoSeveral classifications in ONE run, e.g. Roofing and HVAC. Combined with ‘Trade’ if you fill both. A business listed under two of them is returned (and billed) once. (default [])
categorystringnoWhich part of the registry: ‘contractor’ (default), ‘handyman’, ‘electrician’, ‘plumber’, ‘burglar alarm’ or ‘elevator mechanic’. Electricians and plumbers are mostly…
categoriesarraynoSeveral categories in ONE run. Combined with ‘Category’ if you fill both. (default [])
countystringnoUtah county, e.g. ‘Salt Lake’, ‘Utah County’, ‘washington’. The registry has no county field, so county is worked out from each listing’s city (see county_method). Leave empty…
countiesarraynoSeveral counties in ONE run, e.g. Salt Lake and Utah and Davis. Combined with ‘County’ if you fill both. (default [])
citystringnoA Utah city or town, e.g. ‘Provo’, ‘St. George’. Exact city match (‘Salt Lake City’ does not include North Salt Lake). Use instead of, or as well as, a county.
citiesarraynoSeveral cities in ONE run. Combined with ‘City’ if you fill both. (default [])
includeDetailsbooleannoFetch each listing’s detail record: licence number, licence type, expiry, street address, ZIP and qualifier names. One extra request per listing; turn off for a faster run with… (default True)
maxResultsintegernoCap on the listings returned PER search (each classification x each county or city), not per run, so adding places can never silently truncate the later ones. Leave empty to return every…

Two fields decide the list. trade takes a DOPL class code (“S280”), a name (“Roofing”) or a word from one (“roof”); for electricians and plumbers, set category and use the licence level (Master, Journeyman, Apprentice) instead. If you are unsure of a name, switch on listOptionsOnly and you get all 29 counties and every classification with its code, free. county is the other one, and it is the reason to use this actor at all: the registry has no county filter, so the actor takes every listing for your trade statewide and keeps the ones whose city lies in your county. Use city instead when you want one town exactly; “Salt Lake City” will not pull in North Salt Lake.

A working input:

{
  "county": "Salt Lake",
  "trade": "Roofing"
}

Step 3: Run it

Press Start. Rows are pushed to the dataset as they’re found, so the run log fills in as it works.

We ran the input above on 2026-10-06. The registry returned 148 roofing listings statewide, the actor kept the 63 in Salt Lake County, and the whole scrape, detail records included, took 9.2 seconds (timed outside Apify; a platform run adds container start-up on top). Utah County with "trade": "HVAC" kept 81 of 401 statewide HVAC listings in 10.7 seconds. If a run returns nothing but county and classification names, the actor did not recognise one of your inputs and the log says which; those option rows are free. If the registry does not answer, you get one free row saying so, not an empty dataset that reads as “no contractors here”.

Step 4: Read the output

Each run returns a labelled table, not raw JSON:

The output fields returned by Utah Contractor Directory & Leads Scraper (DOPL)
The output view: every field the actor returns, named and typed.

Every row looks like this, a real row from a real run:

{
  "business_name": "Imperial Custom Sheet Metal & Roofing LLC",
  "phone": "(385) 227-7041",
  "email": "isagon1998@gmail.com",
  "city": "West Valley City",
  "county": "Salt Lake",
  "county_method": "city",
  "address": "5279 Woodstep Avenue",
  "zip_code": "84120",
  "state": "UT",
  "license_number": "14229585-5501",
  "license_type": "Contractor",
  "expiration_date": "11/30/2027",
  "person_name": "Isabel Gonzalez",
  "classifications": "S280 - Roofing Qualifier; S220 - Carpentry and Flooring Qualifier",
  "category": "Contractor",
  "cbr_id": "7499119",
  "requested_trade": "S280 - Roofing Contractor",
  "requested_county": "Salt Lake",
  "source_url": "https://services.commerce.utah.gov/cbr/"
}
FieldExample valueMeaning
business_nameImperial Custom Sheet Metal & Roofing LLCBusiness (or, for electricians and plumbers, licensee) name as listed
phone(385) 227-7041Phone number the licensee gave the registry
emailisagon1998@gmail.comEmail address the licensee gave the registry
cityWest Valley CityCity the licensee listed
countySalt LakeUtah county, worked out from the city (see county_method)
county_methodcitycity, city_primary (city spans two counties; the one most of it lies in), or null (city not recognised)
address5279 Woodstep AvenueStreet address, when the licensee gave one
zip_code84120ZIP code from the listing’s address

Most people come for phone and email. Across the two runs above, 141 of 144 listings had a phone and 141 had an email. license_number, expiration_date and the qualifier in person_name came back on all 144, from the detail call. The street address is the weak column: 43 of the 63 roofers gave one and only 38 of the 81 HVAC firms did, because the registry’s contact details are whatever the business typed in, and many typed a city and ZIP only. Treat county as approximate. It comes from the city via the US Census Bureau’s 2020 place-to-county table, and where a city straddles two counties (Draper, Bluffdale, Park City, Santaquin) the row says city_primary and takes the county most of the city lies in. Four of the 63 Salt Lake roofers carry that flag.

Step 5: Export it

Open the Dataset tab and export to CSV, JSON, or Excel, or pull the same rows from the API, which is what you want if this is going to run on a schedule.

What it costs

$0.002 per listing returned, plus Apify’s own platform usage. The Salt Lake roofing run is 63 rows, so about $0.13; the Utah County HVAC run is 81 rows, about $0.16. Discovery Mode, unrecognised inputs and source-problem rows cost nothing. A business that matches two of your searches is returned and charged once.

Where the data comes from

This reads UT DOPL (Construction Business Registry) directly. The target is the registry page’s own AJAX endpoint (a keyless form POST returning an HTML table), plus a per-business detail call that only answers for rows of the session’s last search. Every night a canary runs this actor against that live source and checks that it still returns at least 40 Salt Lake County roofers with a licence number, and that at least 85% of them carry a phone and an email. See what “verified” means.

The detail call is the awkward part: the registry answers it only for listings from the session’s most recent search, so a detail record cannot be fetched on its own later. The category filter is loose as well. Picking “Contractor / ALL CONTRACTORS” on the site returned 5,849 rows on 2026-10-06, of which 5,032 were contractors and the rest electricians, plumbers and alarm licensees; the actor keeps only the category you asked for. If you only want one town’s roofers once, the registry’s own search plus a few pop-ups is fine and free.

See it used

Build a Salt Lake County Roofing Contractor List follows a home-services marketplace recruiting the 63 Salt Lake County roofers who opted in to the registry.

For the same trade-by-county list in another state, use Arkansas Contractor Directory & Leads Scraper (ACLB), which joins the licensing board’s search to its email roster, or California Contractor Directory by Trade & County for CSLB. Both of those read the licensing board’s own licence records, not an opt-in list.

Last updated 2026-10-06