# NJ Statewide Construction Permits (`j0401/nj-permits`) Actor

New Jersey construction permits (public open data, 2.68M records): the single statewide register every NJ municipality files into - permit type, status, use group, fee breakdown, construction cost, square feet, block+lot, municipality, county. Filter by county/type/cost/date or aggregate.

- **URL**: https://apify.com/j0401/nj-permits.md
- **Developed by:** [Wenhao Yang](https://apify.com/j0401) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.10 / 1,000 nj construction permit records

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## New Jersey Statewide Construction Permits

New Jersey's construction-permit register is **statewide** - every municipality in the state files into one system (PermitsNJ) and the state publishes the whole thing as open data. This actor turns that single table into a **charged-per-record lookup, filter and aggregate tool**: pull a county or a town, range-filter by construction cost or fee, read one parcel by block and lot, or aggregate the state by county, permit type or building use.

**Built for:** contractors and suppliers sizing a market, developers and GCs reading a pipeline, and anyone doing property or construction diligence who wants **the whole state in one query** instead of stitching together two dozen municipal portals.

### What it covers

**2,678,321 permits and certificates** - the state's full file, across **22 counties** and **549 municipalities**. Each row is a **permit** (**1,366,473**) or the **certificate** that closes it (**1,311,848**) - the same permit number carries both ends of the job.

Depth beyond a bare permit list:

- the **full code fee breakdown** - building, plumbing, electrical, fire, DCA, certificate, elevator and other fees, summed into **totalfee** (**2,606,015 rows carry a fee**)
- the **reported construction cost** (**2,604,765 rows**), cubic volume, floor area (**149,991 rows** carry a non-zero square footage - the column is present on every row but zero on the rest) and rent / sale gained
- the **use group** with its ICC description - **R-5 (1,900,875)**, R-3, R-2, B, M, A-2, E, U, ... - and every type code paired with its word (Alteration 2,389,866 / New 112,293 / Demolition 111,086 / Addition 65,076)
- the local parcel key: **municipality + block + lot + county**, plus the certificate type and the state's processing date.

### The fine print that matters

Two source quirks are handled for you. **Impossible future dates** - the register holds permit dates out to **year 2925** and certificate dates to **6013** - are excluded from every query and blanked on output, so a newest-first pull can never surface a year-2925 row. And the source updates **roughly monthly** (the state's own processing date, and the register's update stamp, advance on the order of weeks), so there is **no per-row change marker** on this dataset; the recency axis is the permit date itself, and **227,886 permits carry a valid 2026 date**.

The number that sells it: this is a **2.68M-row statewide table**, not a city portal. A `New` permit over $1M in Bergen County, every alteration in Toms River, one parcel's full permit history by block and lot - all in one query, and aggregate by **county**, **municipality**, **permit type** or **building use** across the whole state.

### Typical questions

- "Every **new-construction** permit over **$1M** in **Bergen County**."
- "Permits in **Toms River** / **Edison** / **Hamilton**."
- "One parcel's full permit history by **block + lot**."
- "The **fee breakdown** and reported cost on a permit number."
- "Aggregate the state by **county**, **permit type** or **building use group**."

### Inputs

| Input | What it does |
|---|---|
| `mode` | `rows` (default) / `aggregate` |
| `status` / `permitType` / `useGroup` | permit vs certificate; alteration / new / addition / demolition; ICC use group |
| `certificateType` | certificate type |
| `county` / `municipality` | where (22 counties, 549 municipalities) |
| `permitNumber` | exact permit number |
| `block` / `lot` | local parcel key |
| `constCostMin/Max` / `totalFeeMin/Max` / `squareFeetMin/Max` | cost, fee and floor-area ranges |
| `issuedFrom/To` / `processedFrom/To` | permit-date and processing-date ranges |
| `groupBy` | aggregate over county / municipality / status / permit type / use group / certificate type |
| `maxResults` | cap records (default 200) |

**Default run = the 200 most recent permits** - fast for the daily auto-test. For a targeted query add a filter; for a broad view use `aggregate`.

### Low cost

**From $0.0001 per record** - billed only for the rows you use, at the platform floor. Cost scales with what you pull, not with the size of the register, and because each record is metered individually there's no per-run charge cap to hit on a big pull.

What a thin scraper misses is the two ends of a job living in the same table: every **certificate** row is a permit's sign-off, filed under the *same permit number* months or years later, so "which permits were actually closed" is a join a naive pull never makes. The registers also carry **impossible dates out to year 2925 and 6013** - dump them newest-first and the top of your result is garbage - and the numeric columns arrive as **strings over the wire** even though the state compares them as numbers, so a text-ordered cost column sorts $9 above $100,000. Normalizing permit-and-certificate, the runaway dates and the string-numbers into a schema where a `county` / `constCostMin` / `permitType` query returns exactly the jobs you mean is the actual product. Every pull is integrity-checked against the register's known shape, so a degraded source fails loudly instead of returning bad rows.

### Source

- [New Jersey: Construction Permit Data](https://data.nj.gov/General-Government/NJ-Construction-Permit-Data/w9se-dmra) - the statewide permit register every NJ municipality files into. Public open data. Records are the state's own published fields; not an endorsement of any contractor or property.

# Actor input Schema

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

rows = permits matching your filters (default). aggregate = one count row per group (see groupBy).

## `status` (type: `string`):

Row type: P = Permit (~1.37M), C = Certificate (~1.31M, the sign-off that closes a permit). Blank = both.

## `permitType` (type: `string`):

06 = Alteration (~2.39M), 04 = New (~113k), 05 = Addition (~65k), 13 = Demolition (~111k). Blank = any.

## `useGroup` (type: `string`):

ICC use group code: R-5 (residential, ~1.9M), R-3, R-2, B (business), M, A-2, E, U, ... Blank = any.

## `certificateType` (type: `string`):

Certificate type description (fuzzy): Certificate of Approval, Certificate of Occupancy, ... Blank = any.

## `county` (type: `string`):

County name, e.g. 'BERGEN', 'MONMOUTH' (22 counties). Blank = any.

## `municipality` (type: `string`):

Municipality name substring, e.g. 'TOMS RIVER', 'EDISON' (549 municipalities). Blank = any.

## `permitNumber` (type: `string`):

Exact permit number.

## `block` (type: `string`):

Local block (parcel key). Combine with lot to pull one parcel's permits.

## `lot` (type: `string`):

Local lot (parcel key).

## `constCostMin` (type: `number`):

Minimum reported construction cost (USD). ~2.6M rows carry a value.

## `constCostMax` (type: `number`):

Maximum reported construction cost (USD).

## `totalFeeMin` (type: `number`):

Minimum total permit fee (USD) - the sum of every code fee on the record.

## `totalFeeMax` (type: `number`):

Maximum total permit fee (USD).

## `squareFeetMin` (type: `number`):

Minimum floor area (sq ft). ~150k rows carry a value.

## `squareFeetMax` (type: `number`):

Maximum floor area (sq ft).

## `issuedFrom` (type: `string`):

Only rows with a permit date on/after this date (YYYY-MM-DD).

## `issuedTo` (type: `string`):

Only rows with a permit date before this date (YYYY-MM-DD).

## `processedFrom` (type: `string`):

Only rows processed by the state on/after this date (YYYY-MM-DD). The source updates roughly monthly, so this tracks the state's own processing.

## `processedTo` (type: `string`):

Only rows processed before this date (YYYY-MM-DD).

## `groupBy` (type: `string`):

Which dimension to aggregate over. county / municipality -> where; permitTypeDescription -> what kind of work; useGroupDescription -> what it is.

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

Cap the number of records pushed in rows mode (0 = up to ~10k per run; each record is metered individually, so there is no per-run charge cap). Aggregate mode returns every group (up to the dimension's cardinality, e.g. 549 municipalities); maxResults applies to rows only.

## Actor input object example

```json
{
  "mode": "rows",
  "status": "",
  "permitType": "",
  "useGroup": "",
  "certificateType": "",
  "county": "",
  "municipality": "",
  "permitNumber": "",
  "block": "",
  "lot": "",
  "issuedFrom": "",
  "issuedTo": "",
  "processedFrom": "",
  "processedTo": "",
  "groupBy": "county",
  "maxResults": 50
}
```

# Actor output Schema

## `recordsUrl` (type: `string`):

New Jersey construction permit records or aggregates - as JSON

## `datasetUrl` (type: `string`):

No description

## `runUrl` (type: `string`):

No description

# 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("j0401/nj-permits").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("j0401/nj-permits").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 j0401/nj-permits --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,j0401/nj-permits"
        }
    }
}
```

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/s3flT29gNs66C4Vb5/builds/gI7WCOc9i28ccIRdp/openapi.json
