← Guides

How-to

How to run DC Contractor License Lookup & List Scraper (DLCP)

Step-by-step: the exact input, what each field does, and the rows that come back from the District of Columbia's contractor Basic Business Licences.

You want a list of the contractors licensed to work in Washington, DC, or you want to check one, and you have found that the District has no contractor board to search. A DC contractor holds a Basic Business Licence (BBL) from the Department of Licensing and Consumer Protection (DLCP) with a contracting “business activity”, and those licences sit in one open table with every restaurant, rental unit and street vendor in the city: 280,169 rows when we counted on 2026-10-09. This actor keeps the three contracting activities, splits the address, and returns one row per licence: 5,909 active licences, or 20,910 in every status.

What you’ll need

Nothing but an Apify account. The actor talks to DC GIS’s open-data server directly.

No API key, no proxy and no CAPTCHA. The licence table is public open data (CC BY 4.0) on DC GIS’s own query API, and the proxy setting ships switched off. The only charge is $0.004 per licence returned, plus Apify’s own platform usage.

Step 1: Open the actor

Open DC Contractor License Lookup & List Scraper (DLCP) on the Apify Store and press Try for free. The actor’s own page on this site lists its live health and pricing.

The DC Contractor License Lookup & List Scraper (DLCP) 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 DC Contractor License Lookup & List Scraper (DLCP) in the Apify Console
The input form, as it appears in the Apify Console.
FieldTypeRequiredWhat it does
activitystringnogeneral_contractor, home_improvement or asbestos. Empty = all three.
activitiesarraynoSeveral activities in one run. (default [])
statusstringnoEmpty = Active (or every status when you look up licence numbers). all, expired, closed, cancelled, suspended, revoked.
licenseNumber / licenseNumbersstring / arraynoBBL licence numbers to verify, digits only.
name / namesstring / arraynoText the business name or trade name contains, case-insensitive.
addressState / addressStatesstring / arraynoTwo-letter state of the business premises, e.g. DC, MD, VA.
city / citiesstring / arraynoPremises city, exact match ignoring case. DC premises file “Washington”.
zip / zipsstring / arraynoPremises ZIP, 5 digits.
ward / wardsstring / arraynoDC ward, 1 to 8 (premises inside the District only).
maxResultsintegernoCap on licences for the whole run, a spend control. (default 500, max 100000)

The field to think about first is addressState. A DC licence is what a contractor needs to work in the District, not where it is based, so of the 5,909 active licences on 2026-10-09, 2,863 had a Maryland premises address, 1,278 a Virginia one and only 1,154 a DC one. If you want firms you can drive to in the city, set addressState to DC; if you sell to the suburbs, set it to MD or VA, or a city such as Silver Spring.

The second is status. Leave it empty and you get Active licences. DLCP keeps the full history, though, and it files expiry five different ways (Expired, Expired - Enforcement, and three “Expired - penalty” statuses); expired collects all five. Different kinds of filter combine, so a licence has to match every one you set: for a plain licence check, fill licenseNumbers and nothing else, and the actor searches every status for you.

A working input:

{
  "addressState": "DC",
  "maxResults": 2000
}

Step 3: Run it

Press Start. The run log says how many licences it read and how many matched before anything is returned.

On Apify on 2026-10-09 the input above read the 5,909 active licences in about 2 seconds and logged “1154 licence(s) match; returning 1154”. The empty default input logged “5909 licence(s) match; returning 500 (maxResults reached)”, which is how a capped run tells you it is not the whole list. A value the actor does not recognise (an activity of “roofing”, a ZIP of “abc”) is dropped with a log line, and if none of your values for a filter is recognised you get one free row saying so, never every licence in the District.

Step 4: Read the output

Each run returns a labelled table, not raw JSON:

The output fields returned by DC Contractor License Lookup & List Scraper (DLCP)
The output view: every field the actor returns, named and typed.

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

{
  "license_number": "410521000073",
  "license_activity": "General Contractor/Construction Manager",
  "status": "Active",
  "status_date": "2026-10-06",
  "initial_issue_date": "2020-11-05",
  "license_start_date": "2026-10-06",
  "expiration_date": "2030-10-31",
  "business_name": "Aku Consulting Inc.",
  "trade_name": "GOTA Engineering",
  "entity_type": "Domestic Business Corporation",
  "owner_name": null,
  "registered_agent": "REGISTERED AGENTS INC.",
  "address": "2402 17th Street SE, Washington, DC, 20020, USA",
  "street": "2402 17th Street SE",
  "city": "WASHINGTON",
  "address_state": "DC",
  "zip_code": "20020",
  "premise_in_dc": true,
  "ward": "Ward 8",
  "mailing_address": "2402 17th Street SE, Washington, DC, 20020, USA",
  "state": "DC",
  "source_url": "https://maps2.dcgis.dc.gov/dcgis/rest/services/FEEDS/DCRA/MapServer/0/query?where=CUSTOMERNUMBER%3D%27410521000073%27&outFields=%2A&f=json"
}
FieldExample valueMeaning
license_number410521000073DC Basic Business Licence number, one row per licence
license_activityGeneral Contractor/Construction ManagerWhich of the three contracting activities
statusActiveStatus as DLCP files it
initial_issue_date2020-11-05When the licence was first issued
expiration_date2030-10-31End of the current term
trade_nameGOTA EngineeringThe DBA, when it differs from the legal name
registered_agentREGISTERED AGENTS INC.Registered agent company or person
wardWard 8DC ward, for premises inside the District

The address comes three ways. address is the string exactly as filed; street, city, address_state and zip_code are that string split up, which worked on 5,892 of the 5,909 active licences (the other 17 were filed in some other shape and keep only address). mailing_address is the billing address, a separate field. ward is filled on the 1,122 active licences inside the District that DC GIS assigns a ward to.

What is not there: a phone number or an email. The table has neither, on any row, and the actor does not add one. The table also has latitude and longitude columns, but every row that fills them carries the same value, (39, -77), a placeholder rather than a location, so the actor leaves them out.

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 licence returned, plus Apify’s own platform usage. The DC-premises run above is 1,154 rows, so $4.62. Every active licence (5,909) is $23.64, and the full history in every status (20,910) is $83.64. Rows explaining an outage, an unrecognised filter or an empty result are free.

Where the data comes from

This reads the “Basic Business Licenses” table that DC GIS publishes for DLCP on Open Data DC, queried through its ArcGIS REST API on every run. The dataset page says it is refreshed daily, and on 2026-10-09 the data was dated that morning. Every night a canary runs this actor against that live source and checks that a DC home-improvement run still returns at least 40 active licences with a licence number, status, street, city, expiry and mailing address: what “verified” means.

The Basic Business Licenses dataset page on Open Data DC
The Basic Business Licenses dataset on Open Data DC, captured 2026-10-09: 280,169 records, data updated daily.

This is an easy target, and you can skip us: the dataset page has a Download button, and if you want the District once, download it and filter it. The work is in the filtering. Contracting is three of more than a hundred business activities in the table, one of them stored under a name truncated mid-word (“General Contractor/Construction Manager (A, B, C,”), and the address is one free-text string you would have to split yourself.

See it used

Licensed Home Improvement Contractors in Washington, DC builds a list of the 152 active home improvement contractors with a premises address inside the District, by ward.

For the Virginia side of the same metro area, Virginia Contractor License Lookup (DPOR Bulk) exports Virginia’s licensed contractors, and those rows carry an email address on most rows.

Last updated 2026-10-09