← Guides

How-to

How to run North Carolina Contractor License Lookup & Verify (NCLBGC)

Step-by-step: the exact input, what each field does, and the rows that come back from NCLBGC.

The honest starting point: if you have one North Carolina general contractor to check, use NCLBGC’s own public search. It’s free, it’s instant, and it’s the same registry this actor reads. Nobody vetting a single roofer needs an Apify account. This actor exists for the case where the lookup isn’t one lookup — an onboarding list of eighty subs that each needs a license number, classification, status and expiration date pulled into a sheet; a quarterly re-check of every active contractor on your books, because a license that was current in March expires on 31 December; a CRM full of NC company names you want turned into structured license rows. Done by hand that’s one portal search per contractor, a click into the detail panel, and a copy-paste of a dozen fields — repeated from scratch the next time anyone asks. This does the same reads and hands you rows.

What you’ll need

Nothing but an Apify account. The actor talks to NCLBGC directly.

No API key, no CAPTCHA-solving service, no proxy subscription, no login. NCLBGC’s search is one of the easier public registries out there — the search is a plain form POST that needs nothing more than browser-like request headers, with no CAPTCHA and no session cookie to carry. So the only bill attached to a run is the actor’s per-result fee plus Apify compute. There is no third-party cost hiding behind it.

Step 1 — Open the actor

Open North Carolina Contractor License Lookup & Verify (NCLBGC) on the Apify Store and press Try for free. The actor’s own page on this site lists its live health and pricing.

The North Carolina Contractor License Lookup & Verify (NCLBGC) 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 North Carolina Contractor License Lookup & Verify (NCLBGC) in the Apify Console
The input form, as it appears in the Apify Console.
FieldTypeRequiredWhat it does
querystringyesAn NCLBGC license number (e.g. ‘L.03194’, ‘03194’) OR a company/person name. A license number is looked up directly; anything else is searched against the NCLBGC name index.…
includeDetailsbooleannoWhen on (default), each match is enriched with its full NCLBGC record — phone, address, classifications, issue/expiration dates, and exact status. Turn off for a faster,… (default True)
maxResultsintegernoCap on the number of matches returned in a single run. This is a lookup tool, not a bulk export — defaults to 50. (default 50)

Only query is required, and it decides which of two searches runs. If what you type looks like an NCLBGC number — L.03194, 03194, L03194, even bare 3194 — the actor strips it down to the digits and looks that account up directly, and you should get exactly one row back. Anything else is treated as a name and sent to the portal’s company-name search. That is worth being precise about: the name search is a company search. If you type a person’s name you’ll only get a hit when that person’s name is part of the licensed entity’s name (a sole owner trading under their own name, for instance) — this actor does not search NCLBGC’s qualifier index, so it is not a way to trace an individual across several companies. The matched_by column on every row tells you which of the two searches produced it.

includeDetails is the other one first-timers get wrong. It’s on by default, and it should usually stay on: the search results fragment itself carries only three things — license number, license type, and the owner/company name. Everything people actually want (status, classifications, first-issued and expiration dates, address, phone) lives on the detail record, which is a second fetch per match. Turn includeDetails off and you get a fast, thin list of numbers and names, which is fine for “how many licenses match this name” and useless for a compliance file. Leave it on and each match costs one extra request, which is what maxResults (default 50) is there to bound — a broad name search with details on does a lot more work than a license-number lookup.

A working input:

{
  "query": "L.03194",
  "includeDetails": true,
  "maxResults": 25
}

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.

A healthy run is short. A license-number lookup is two requests — one search, one detail — and returns a single row in seconds. A name search returns as many licenses as NCLBGC holds for that company name, deduplicated by license number and capped by maxResults; with details on, each of those adds one more fetch, so a twenty-match name search is on the order of twenty-one requests. Rows land in the dataset as they’re enriched, so you can watch the count climb instead of waiting on a silent finish.

An empty run is almost always the query, not the actor. A license number that returns nothing is a number the board doesn’t have — check for a transposed digit. A name that returns nothing is usually filed differently than it appears on the invoice in front of you: NCLBGC stores the legal entity name, so “Barnhill Contracting” finds a company that “Barnhill Constr. Co.” will not. Shorten the query to the most distinctive fragment and try again. The one genuinely external cause is the portal being down or slow, in which case the actor retries and backs off; nobody’s lookup works then, manual or not.

Step 4 — Read the output

Each run returns a labelled table, not raw JSON:

The output fields returned by North Carolina Contractor License Lookup & Verify (NCLBGC)
The output view — every field the actor returns, named and typed.

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

{
  "state": "NC",
  "license_number": "L.03194",
  "business_name": "Barnhill Contracting Company",
  "license_type": "Unclassified",
  "status": "Active",
  "issue_date": "04/30/1959",
  "expiration_date": "12/31/2026",
  "address": "P. O. Box 7948",
  "city": "Rocky Mount",
  "zip_code": "27804",
  "phone": "(252) 823-1021",
  "person_name": null,
  "county": null,
  "matched_by": "license_number",
  "source_url": "https://portal.nclbgc.org/Public/_ShowAccountDetails/?key=DCrnKZiPujDNOqltrYHa4A%3d%3d&Source=Search"
}
FieldExample valueMeaning
stateNCAlways ‘NC’ for this actor
license_numberL.03194NCLBGC license number (e.g. L.03194)
business_nameBarnhill Contracting CompanyLicensed company or individual name
license_typeUnclassifiedActive license classifications (e.g. Building, Highway, Unclassified)
statusActiveLicense status (e.g. Active, Archived, Cancelled)
issue_date04/30/1959Date first issued
expiration_date12/31/2026License expiration date
addressP. O. Box 7948Street or mailing address

Most people came for status and expiration_date, and those are the two to read carefully. Both come from the detail record, so with includeDetails off they’ll be thin or empty: a search-results row only knows whether the board has flagged the licence inactive, so status on a details-off run is either Not Active or null — never assume null means active. With details on you get the board’s own word for it (Active, Archived, Cancelled, and other values NCLBGC uses), and dates come through exactly as the portal prints them — 12/31/2026, US month/day/year strings, not ISO dates. Parse them before you compare them to anything.

license_type is the joined list of active classifications (Building, Highway, Unclassified, and so on) — a licence with none currently active comes back null rather than with a placeholder. address is whatever the board holds as the mailing address, which for a lot of older licensees is a PO box rather than a street, as in the row above. phone is null when the board doesn’t publish one. Two fields in the schema are always null here: person_name and county exist for consistency with the other license actors in the suite, and NCLBGC simply doesn’t publish them. Every row carries source_url, the keyed link to that licence’s official NCLBGC record, so anything you put in front of an auditor is one click from its source.

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.004 per license record returned. A search that finds nothing is free — you are never charged for an empty result. Verifying one contractor by license number is one record, so four tenths of a cent. Pushing an eighty-vendor onboarding list through it is eighty records, about $0.32. Apify’s platform compute is billed separately, per your plan, and this is a light actor — plain HTTP requests, no browser — so that side stays small too.

Set against NCLBGC’s free search page, the actor is not cheaper; it’s zero-effort and schedulable. At one lookup, the free page wins. At eighty, on a repeating quarterly cadence, it doesn’t.

Where the data comes from

This reads NCLBGC directly. The target is ASP.NET MVC AJAX endpoint returning an HTML fragment; the detail view is fetched by the account key carried on each result row. Every night a canary runs this actor against that live source and diffs the result against a frozen fixture — what “verified” means.

By the standards of state license portals this one is easy, and there’s no reason to pretend otherwise: the search is an ASP.NET MVC AJAX endpoint that answers a plain form POST with an HTML fragment, no CAPTCHA and no session to establish. The mild annoyance is that the fragment is a three-column table — number, type, name — and nothing else. Everything of value sits behind an opaque account key hidden in each row’s onclick handler, which has to be pulled out and replayed against the detail endpoint, one fetch per record. That’s the whole trick: read the keys, follow them, flatten the label/value panels into a row. The site is not fighting you, it just doesn’t hand you a record.

See it used

Verify a North Carolina Contractor by License Number checks a single NCLBGC number before you sign.

If you don’t know which state issued the licence, or you want the same contractor checked in several states at once, reach for Multi-State Contractor & Trade License Lookup instead; it runs one query across several state boards in a single run, where this actor goes deep on NCLBGC alone.

Last updated 2026-07-13