# Georgia Contractor License Lookup & Leads Scraper (`scrapebench/georgia-contractor-license-lookup`) Actor

Contractors registered with the City of Atlanta and Gwinnett County to pull permits: general, electrical, plumbing, conditioned air, low-voltage and more, with street address, licence number and expiry; Gwinnett rows add phone and email.

- **URL**: https://apify.com/scrapebench/georgia-contractor-license-lookup.md
- **Developed by:** [ScrapeBench](https://apify.com/scrapebench) (community)
- **Categories:** Lead generation
- **Security:** Limited permissions
- **Stats:** 5 total users, 5 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.002 / contractor record

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Georgia Contractor License Lookup & Leads Scraper

### Pain points

- Atlanta's and Gwinnett County's licensee searches stop at '100+' results and show 10 rows a page, so a whole trade cannot be listed from either.
- Both registers reach back years: many rows are licences that expired long ago, mixed with test rows.
- Georgia's statewide licence search sits behind a browser challenge, so the local registers are the open door to the contractors who actually pull permits there.

### What we solve

- Every contractor licence type both registers hold (27 in Atlanta, 29 in Gwinnett County), read by licence-number range so no search hits the 100-result cap.
- Old rows cleaned out: test and voided rows are never delivered, and licences that expired more than 3 years ago are left out of exports; each row says whether its licence is Unexpired, Expired or carries no expiry date.
- Phone, email and contact name from each licensee's own page, where it publishes them (in the 2026-11-07 copy: about 70% of Atlanta rows and most Gwinnett County rows have a phone).
- Looks up licence numbers or business names live on both registers.

### Summary

Contractors registered to pull permits in two Georgia localities, from their Accela Citizen Access licensee registers. The City of Atlanta: 27 licence types, general contractors (GEN CONT), electrical, plumbing, mechanical, low voltage, fire, pool, sign, utility, grading, landscape, elevator, tree professionals and more, plus architects and engineers. Gwinnett County: 29 contractor licence types, general contractor (company, individual, limited tier, qualifying agent), residential basic and light commercial, conditioned air, electrical, master plumber, low voltage, utility, manufactured homes installer and more. Each row has the licence number as registered (usually the holder's Georgia state licence number), licence type, business name, the local business licence number, street address, city, state and ZIP, the licence expiry and an Unexpired / Expired flag derived from it, and which register it comes from (locality). Rows add the phone, email and contact name from the licensee's own page where it lists them. Firms from other cities and states appear when they registered to work there. Exports read a stored copy of the registers (its date is in the run log); lookups search them live. Pay only per licence returned.

### Who it's for

- Building-material suppliers and distributors selling to contractors working in metro Atlanta
- Subcontractors and staffing firms looking for the general contractors that pull Atlanta and Gwinnett permits
- Property managers and developers checking a contractor's local registration and expiry
- Insurers and bonding agents reaching registered trades

### How to use

This actor does two jobs. Run it, then collect results from the run's dataset (export to JSON/CSV/Excel, or pull via the Apify API).

**Get a list (export):** no names, just filters; returns the whole matching list.

```json
{
  "localities": [
    "Gwinnett County"
  ],
  "categories": [
    "General Contractor Company"
  ],
  "expiry_statuses": [
    "Unexpired"
  ],
  "maxResults": 500
}
```

**Check specific firms (lookup):** put company names or licence numbers in `mode`, `queries`; **Inputs** below says how each is matched.

```json
{
  "mode": "lookup",
  "queries": [
    "HUMPHRIES",
    "GCQA001848"
  ],
  "maxResults": 20
}
```

See **Inputs** below for every available field.

### What you get

One row per record:

| Field | Description |
|---|---|
| `license_number` | Licence number exactly as registered (often the Georgia state licence number, e.g. GCQA001848); listing_id holds the same |
| `license_type` | The register's licence type: GEN CONT, ELEC CONT … (Atlanta); General Contractor Company, Conditioned Air Restricted … (Gwinnett County) |
| `business_name` | Business name; empty on some individual registrations (then extras.first_name holds the holder's first name) |
| `phone` | Phone from the licensee's own page, when listed; phone_e164 holds it as +1XXXXXXXXXX |
| `email` | Email from the licensee's own page, when listed |
| `address` | Street address |
| `city` | City |
| `address_state` | State |
| `zip_code` | ZIP code |
| `expiration_date` | Licence expiry (YYYY-MM-DD) |
| `extras.locality` | Which register the row comes from: Atlanta or Gwinnett County |
| `extras.expiry_status` | Unexpired, Expired or No expiry date, derived from the expiry on the day of the copy (the registers publish no status) |
| `extras.business_license_number` | The holder's local business licence number |
| `extras.person_name` | Contact name from the licensee's own page, when listed |
| `extras.insurance_expires` | Insurance expiry, where registered |
| `extras.first_name` | First name of the registered holder |
| `source_url` | The licensee's own page on the register's search (the part after # keeps rows with a placeholder licence number apart) |

Sample:

```json
{
  "license_number": "GCCO000076",
  "license_type": "General Contractor Company",
  "business_name": "BUILDING CONSTRUCTION SOLUTION",
  "phone": "4042558953",
  "phone_e164": "+14042558953",
  "email": "gordon@buildingconstructionsolutions.com",
  "address": "140 Grosvenor Place",
  "city": "Atlanta",
  "address_state": "GA",
  "state": "GA",
  "extras": {
    "locality": "Gwinnett County",
    "licence_type": "General Contractor Company",
    "person_name": "Gordon Singer",
    "business_license_number": "24-105768"
  },
  "source_url": "https://aca-prod.accela.com/GWINNETT/GeneralProperty/LicenseeDetail.aspx?LicenseeNumber=GCCO000076&LicenseeType=General+Contractor+Company#24-105768%7CBUILDING%20CONSTRUCTION%20SOLUTION%7C140%20Grosvenor%20Place"
}
```

### Inputs

| Field | Required | Type | Default | Description |
|---|---|---|---|---|
| `mode` | no | string | `"auto"` | export: no names, just filters; returns the whole matching list. lookup / verify: put company names (matched if contained in the company name) or licence numbers (exact) in 'queries'. auto picks the mode for you. |
| `query` | no | string | — | A business name (or listing number) to look up live. Kept alongside 'queries' for saved tasks. |
| `queries` | no | array | `[]` | A business name (or listing number) to look up live. Several values in one run; combined with 'query'. |
| `locality` | no | string | — | Only listings in this locality. Kept alongside 'localities' for saved tasks. |
| `localities` | no | array | `[]` | Only listings in this locality. Several values in one run; combined with 'locality'. |
| `city` | no | string | — | Only listings in this city. Kept alongside 'cities' for saved tasks. |
| `cities` | no | array | `[]` | Only listings in this city. Several values in one run; combined with 'city'. |
| `expiry_status` | no | string | — | Only listings in this expiry_status. Kept alongside 'expiry_statuses' for saved tasks. |
| `expiry_statuses` | no | array | `[]` | Only listings in this expiry_status. Several values in one run; combined with 'expiry_status'. |
| `categories` | no | array | `[]` | Only rows from this licence type (one or more). Available: 3rd PARTY, ARCH, ASPH, CIVIL ENG, Certificate of Competency, Conditioned Air Non-Restricted, Conditioned Air Restricted, ELEC CONT, ELEC ENG, ELEV CONT, EXEMPT, Electrical Contractor - Non-Restricted, Electrical Contractor - Restricted, FIRE, FRAM, Fire Extinguisher, GEN CONT, GRAD CONT, General Contractor Company, General Contractor Individual, General Contractor Limited Tier CO, General Contractor Limited Tier IND, General Contractor Limited Tier QA, General Contractor Qualifying Agent, Housing Contractor, … (56 in all; an unknown name returns the full list, free). |
| `licenseTypes` | no | array | `[]` | Same filter as 'Licence type', under the name every state licence actor takes; the two lists are combined. |
| `expiresAfter` | no | string | — | Only licences expiring on or after this date (YYYY-MM-DD). Licences with no published expiry are left out when set. |
| `expiresBefore` | no | string | — | Only licences expiring on or before this date (YYYY-MM-DD): renewals coming due. |
| `maxResults` | no | integer | `500` | Per query in lookup mode; per run in export mode. |
| `proxyConfiguration` | no | object | `{"useApifyProxy": false}` | Used only for live lookups; exports read the stored snapshot. |

### Pricing (Pay Per Event)

You pay per result (`dataset-item`) — **no charge for empty runs**. Example: **1000 contractor licences** at *$0.004/result* ≈ **$4.00**.

Notices (unknown licence type, no match, source unavailable, stale copy) are free.

### Use cases

- Sales lists: every general contractor with an unexpired Gwinnett County registration, with phone, email and street address.
- Trade outreach: electrical, plumbing, conditioned air or low-voltage contractors registered in Atlanta or Gwinnett County.
- Renewal campaigns: registrations expiring in the next 90 days (Expires on or before).
- Contractor checks: confirm a firm is registered with the City or the County and read its expiry.

### Why this actor

- Both registers whole, not the first 100 rows of a search.
- Dead and test rows filtered out, every row flagged Unexpired, Expired or no expiry date.
- Phone and email read from each licensee's page, where it lists them.
- Filters the registers' searches lack: locality, licence type, city and expiry date, each taking a list.
- Pay per licence; notices are free.

### Limitations & updates

Covers the City of Atlanta's licensee register (all 27 licence types) and Gwinnett County's (29 contractor licence types; engineers, inspectors and non-contractor registrations left out), not Georgia's statewide licences. Exports leave out test / voided rows and licences that expired more than 3 years ago, and come from a stored copy. Licence numbers are free text; a number starting with a space or an unusual character may be missed when its slice of the register is large. Phone and email only where the licensee's page lists them. One run returns at most 100,000 rows.

### FAQ

**Where does the data come from?**

Two Accela Citizen Access licensee searches: the City of Atlanta's (aca-prod.accela.com/ATLANTA_GA), where the Office of Buildings registers the contractors and design professionals that pull permits in the city, and Gwinnett County's (aca-prod.accela.com/GWINNETT), where the County registers contractors. Exports come from a stored copy of both; the run log gives its date. Lookups search them live.

**Is this every licensed contractor in Georgia?**

No. It is the City of Atlanta's and Gwinnett County's registers: contractors who registered there to work, wherever they are based. Georgia's statewide licences are issued by the Secretary of State and are not in this list. More Georgia localities are added as they are read.

**Are expired licences included?**

Exports leave out licences that expired more than 3 years ago and test or voided rows. The rest are included with expiry_status Unexpired, Expired or No expiry date: set Expiry Status to Unexpired for current registrations only. Lookups return every expiry.

**Why does one firm appear several times?**

Each register keeps one registration per licence number and type, and a firm can be registered in both places; a firm that registered under several licence numbers has one row for each. Filter on expiry_status Unexpired to keep the current ones, or on locality for one register.

**Is there a phone or email?**

Yes, when the licensee's own page lists them, on both registers. In the 2026-11-07 copy, 11,179 of 16,019 Atlanta rows had a phone and 8,520 an email; every row has the street address the register holds.

**How do I look up a firm or a licence number?**

Put business names or licence numbers in queries and set mode to lookup. Both registers are searched (set Locality for one) and both match from the start of the value: 'HUMPHRIES' finds HUMPHRIES AND COMPANY, LLC; a licence number is typed as registered.

**How am I charged?**

One event per licence returned. Notices are free.

### Guides & use cases

Written up on **[scrapebench.dev](https://scrapebench.dev)** — the bench that runs and verifies this actor against the live source every night:

- **How-to:** [How to run Georgia Contractor License Lookup & Leads Scraper](https://scrapebench.dev/guides/how-to-georgia-contractor-license-lookup/)
- **Use case:** [Atlanta General Contractors (City registration)](https://scrapebench.dev/use-cases/atlanta-general-contractors/)

More actors, coverage and nightly verification results: **[scrapebench.dev](https://scrapebench.dev)**

### Works with AI assistants (MCP)

Callable as an MCP tool, so Claude, Cursor, VS Code Copilot and other MCP clients can run it directly. Grab the config from the [MCP tab](https://apify.com/scrapebench/georgia-contractor-license-lookup/api/mcp) on this page — Apify hosts the server and keeps that snippet current, and OAuth signs you in on first connect, so no API token goes in your config file.

Then just ask:

> "Find Humphries and Company's contractor registrations in Georgia: licence numbers, types, addresses and expiry dates."

That is a lookup for the business name HUMPHRIES (run live on Atlanta's register 2026-11-06: 14 registrations, one unexpired). Keep maxResults small on a first call. Runs started this way bill exactly like any other run.

### Data & lawful use

This actor collects publicly available information that the City of Atlanta (Department of City Planning, Office of Buildings) and Gwinnett County (Department of Planning and Development) publishes for public
lookup — licence records, business listings and the contact details professionals list there.
Some of it identifies individuals (sole proprietors, licence holders, agents), so treat any
names, phone numbers and emails in your results as personal data.

When you run this actor, you decide what is collected and what it is used for, so you are the
controller of that data and we act only as your processor (Apify Standard Actor Contract).
You need a lawful basis for your use, must honour opt-out and deletion requests, and must
follow the marketing rules that apply to you (CAN-SPAM, TCPA, GDPR, CCPA and similar).
Don't use the output for unsolicited bulk messaging, for screening covered by the FCRA, or
for anything the source's own terms forbid.

Your results are stored in your own Apify account. We don't keep a copy of your results and
don't sell or share them.

### Disclaimer

This is an independent tool. It is not affiliated with, endorsed by or sponsored by
the City of Atlanta (Department of City Planning, Office of Buildings) and Gwinnett County (Department of Planning and Development). Names and marks are used only to describe the data source. Records are
provided as published by the source and may be out of date or incomplete. For anything
consequential (hiring, a permit, a legal decision), confirm the record with the issuing
agency. You are responsible for making sure your use complies with applicable law and the
source's terms.

### Need help?

Open an issue on this actor's **Issues** tab and we'll respond there. Bug reports, missing
fields and feature requests are all welcome. Guides and examples: [scrapebench.dev](https://scrapebench.dev).

If you are a person named in this data and want your record removed from our copy, email
apify-help@scrapebench.dev; the source agency remains the official record.

Your run may be used to improve our services. If something looks off, or you want this actor to fit your use better, please share your run data with us: [Apify Console → Settings → Security → Share run data with developers](https://console.apify.com/settings/security). It lets us see exactly what went wrong and keep improving the actor.

If this actor saved you time, a short review on its Store page helps other buyers find it.

# Actor input Schema

## `mode` (type: `string`):

export: no names, just filters; returns the whole matching list. lookup / verify: put company names (matched if contained in the company name) or licence numbers (exact) in 'queries'. auto picks the mode for you.

## `query` (type: `string`):

A business name (or listing number) to look up live. Kept alongside 'queries' for saved tasks.

## `queries` (type: `array`):

A business name (or listing number) to look up live. Several values in one run; combined with 'query'.

## `locality` (type: `string`):

Only listings in this locality. Kept alongside 'localities' for saved tasks.

## `localities` (type: `array`):

Only listings in this locality. Several values in one run; combined with 'locality'.

## `city` (type: `string`):

Only listings in this city. Kept alongside 'cities' for saved tasks.

## `cities` (type: `array`):

Only listings in this city. Several values in one run; combined with 'city'.

## `expiry_status` (type: `string`):

Only listings in this expiry_status. Kept alongside 'expiry_statuses' for saved tasks.

## `expiry_statuses` (type: `array`):

Only listings in this expiry_status. Several values in one run; combined with 'expiry_status'.

## `categories` (type: `array`):

Only rows from this licence type (one or more). Available: 3rd PARTY, ARCH, ASPH, CIVIL ENG, Certificate of Competency, Conditioned Air Non-Restricted, Conditioned Air Restricted, ELEC CONT, ELEC ENG, ELEV CONT, EXEMPT, Electrical Contractor - Non-Restricted, Electrical Contractor - Restricted, FIRE, FRAM, Fire Extinguisher, GEN CONT, GRAD CONT, General Contractor Company, General Contractor Individual, General Contractor Limited Tier CO, General Contractor Limited Tier IND, General Contractor Limited Tier QA, General Contractor Qualifying Agent, Housing Contractor, … (56 in all; an unknown name returns the full list, free).

## `licenseTypes` (type: `array`):

Same filter as 'Licence type', under the name every state licence actor takes; the two lists are combined.

## `expiresAfter` (type: `string`):

Only licences expiring on or after this date (YYYY-MM-DD). Licences with no published expiry are left out when set.

## `expiresBefore` (type: `string`):

Only licences expiring on or before this date (YYYY-MM-DD): renewals coming due.

## `maxResults` (type: `integer`):

Per query in lookup mode; per run in export mode.

## `proxyConfiguration` (type: `object`):

Used only for live lookups; exports read the stored snapshot.

## Actor input object example

```json
{
  "mode": "auto",
  "queries": [],
  "localities": [],
  "cities": [],
  "expiry_statuses": [],
  "categories": [],
  "licenseTypes": [],
  "maxResults": 500,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

One row per business listing; notices are free.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapebench/georgia-contractor-license-lookup").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("scrapebench/georgia-contractor-license-lookup").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 '{}' |
apify call scrapebench/georgia-contractor-license-lookup --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapebench/georgia-contractor-license-lookup"
        }
    }
}
```

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/XylUvgFPqMEYcII1n/builds/h6dR17J4pe1Ogh3M7/openapi.json
