# Poland Road Transport Operators Scraper - Permits & Licences (`scrapersdelight/pl-road-transport-operators-scraper`) Actor

Scrape Poland's road-transport operators from GITD's KREPTD open-data extracts: about 77,000 goods and passenger permits, licences and intermediaries with legal form, address, voivodeship, permit or licence number and expiry. Flags operators new, changed or removed since the previous extract.

- **URL**: https://apify.com/scrapersdelight/pl-road-transport-operators-scraper.md
- **Developed by:** [Scrapers Delight](https://apify.com/scrapersdelight) (community)
- **Categories:** Lead generation, Business, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.00 / 1,000 per row returneds

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

### What does Poland Road Transport Operators Scraper do?

**Poland Road Transport Operators Scraper** turns the public part of KREPTD — Poland's national register of
road-transport undertakings, kept by GITD (Główny Inspektorat Transportu Drogowego) — into clean rows: one row
per published permit or licence, with the operator's name, legal form, address, voivodeship, permit or licence
number and licence expiry. It reads the five half-yearly extracts GITD publishes on the national open-data portal
dane.gov.pl, decodes them, splits the addresses, and can tell you which operators are new, changed or gone since
the previous extract.

Also searched as: KREPTD scraper, GITD przewoźnicy, rejestr przewoźników drogowych, Polish haulage companies
list, Poland trucking companies database.

- 🚛 **76,919 rows across five registers** in the newest extracts: 28,521 goods operator permits, 758 passenger
  operator permits, 44,229 goods licences, 2,825 passenger licences and 586 passenger-transport intermediaries.
- 🏢 **Operator, legal form, address, voivodeship** on every permit and licence row (voivodeship is published on
  all but 3 of 28,521 goods permits).
- 📅 **Licence expiry with a computed status** — valid / expired on the day you run it, and days left.
- 🔁 **Changes since the previous extract** — new, changed (with the old values) and removed operators. Goods
  permits, June -> December 2025: 919 new, 834 changed, 1,716 removed.
- 🎯 **Filters**: voivodeship, city, postcode prefix, legal form, name words, permit / licence numbers, licence
  status, expiring within N days.
- 🧾 **Provenance on every row**: the extract date, the dane.gov.pl resource id and the exact CSV it came from.
- 🔓 No login, no API key, no browser.

### What data can you get from the KREPTD / GITD extracts?

| | | |
|---|---|---|
| 🏢 Operator name `operatorName` | ⚖️ Legal form `legalForm` + `legalFormCode` | 👤 Sole trader flag `isSoleTrader` |
| 🔢 Permit / licence number `authorisationNumber` | 📋 Register `register` / `registerNameEn` | 🚚 Goods or passengers `transportScope` |
| 📅 Licence valid until `licenceValidUntil` | ✅ Licence status `licenceStatus` | ⏳ Days to expiry `daysUntilExpiry` |
| 📮 Postcode `postalCode` | 🏘️ Locality `locality` | 🏙️ Post town `postTown` |
| 🛣️ Street / village + number `streetAddress` | 📍 Full address `addressFull` | 🗺️ Voivodeship + TERYT code |
| 🏛️ KRS number (intermediaries) `krsNumber` | 🪪 CEIDG entry (intermediaries) `ceidgRegistered` | 🔁 Change type `changeType` |
| 📝 Changed fields `changedFields` | ⏪ Previous values `previousValues` | 🗓️ Extract date `editionDate` |
| 🔗 Source CSV `sourceFileUrl` | 🆔 Stable id `recordId` | 📜 Data licence `dataLicense` (CC0 1.0) |

**Not in the extracts, so not in this actor:** NIP, REGON, number of vehicles, transport managers, permit issue
date and permit status history. GITD publishes those only on kreptd.gitd.gov.pl itself, which refuses connections
from outside Poland and keeps the NIP / vehicle view behind a CAPTCHA.

### How to scrape Polish road-transport operators with Poland Road Transport Operators Scraper

1. [Sign up for a free Apify account](https://console.apify.com/sign-up) — it comes with free monthly credit.
2. Open **Poland Road Transport Operators Scraper** and pick the registers you want (goods permits is preselected).
3. Optionally narrow it down: a voivodeship, a few cities or postcode prefixes, legal forms, name words.
4. Set **Max rows** (0 = everything) and click **Start**.
5. Download the rows as JSON, CSV, Excel or HTML, or read them through the API.

### Input

| Parameter | Type | Default | What it does |
|---|---|---|---|
| `registers` | array | `["goods-permits"]` | Any of `goods-permits`, `passenger-permits`, `goods-licences`, `passenger-licences`, `passenger-intermediaries`. |
| `editionDate` | string | newest | Read the newest extract published on or before this date (`2024-12-31`). |
| `voivodeships` | array | all | Voivodeship names, e.g. `mazowieckie`. |
| `cities` | array | all | Exact locality or post town, case and diacritics ignored (`lodz` = `ŁÓDŹ`). |
| `postalCodePrefixes` | array | all | `00-`, `02`, `60-1` — digits are compared. |
| `legalForms` | array | all | `sole-trader`, `sp-z-oo`, `civil-partnership`, `general-partnership`, `limited-partnership`, `sp-z-oo-sp-k`, `joint-stock`, … |
| `nameContains` / `nameExcludes` | array | — | Words the operator name must / must not contain. |
| `authorisationNumbers` | array | — | Look up numbers: `25661`, `TU-047218`, `OU-004837` (leading zeros and spaces ignored). |
| `licenceStatus` | string | `any` | `valid` or `expired` on the run date. |
| `licenceExpiresWithinDays` | integer | — | Licences still valid that expire within N days. |
| `editionChanges` | string | `off` | `flag`, `new`, `changed`, `removed` or `all-changes` versus the previous extract. |
| `onlyNewSinceLastRun` + `monitorKey` | boolean / string | `false` / `default` | Skip rows already delivered to you by earlier runs. |
| `sortBy` | string | `source` | `name`, `postalCode`, `voivodeship`, `licenceValidUntil`. |
| `maxItems` | integer | `100` | Row cap; `0` = no limit. |
| `proxyConfiguration` | object | none | Only used if a direct request to dane.gov.pl fails. |

#### Input JSON

```json
{
    "registers": ["goods-permits", "goods-licences"],
    "voivodeships": ["wielkopolskie"],
    "legalForms": ["sp-z-oo"],
    "nameContains": ["trans", "logistic"],
    "maxItems": 500
}
```

#### Pick the register before anything else

**Goods permits** (zezwolenia na wykonywanie zawodu przewoźnika drogowego — przewóz rzeczy) are the haulage
operators. **Goods licences** (licencje towarowe, TU- numbers) and **passenger licences** (licencje osobowe, OU-)
are separate registers with an expiry date. **Passenger-transport intermediaries** (PO-) are the companies that
broker passenger transport; that list has no legal-form or voivodeship column but carries the KRS number for
306 of 586 and a CEIDG flag for the other 280.

#### Use "Changes since the previous extract" for new-operator leads

`new` returns only permit / licence numbers that were not in GITD's previous extract — 919 new goods permits
between the June and December 2025 extracts. `changed` returns operators whose name, address, legal form or
licence expiry moved, with `changedFields` and `previousValues`. `removed` returns rows that disappeared, taken
from the older extract.

#### Small runs read only the top of the file

Without filters or sorting, a run reads only as much of the CSV as it needs: a 20-row run reads 64 KB of the
3.9 MB goods-permit file. Filters, sorting, comparisons and `maxItems: 0` read the whole extract.

### Output

```json
{
  "recordId": "LO-OU-004837-38500",
  "register": "passenger-licences",
  "authorisationType": "licence",
  "transportScope": "passengers",
  "authorisationNumber": "OU-004837",
  "licenceValidUntil": "2026-02-17",
  "licenceStatus": "expired",
  "daysUntilExpiry": -242,
  "operatorName": "TRAVELPL SPÓŁKA Z OGRANICZONĄ ODPOWIEDZIALNOŚCIĄ",
  "legalForm": "Spółka z o.o",
  "legalFormCode": "sp-z-oo",
  "isSoleTrader": false,
  "postalCode": "38-500",
  "locality": "SANOK",
  "postTown": "SANOK",
  "streetAddress": "UL. STANISŁAWA WITKIEWICZA 4",
  "voivodeship": "podkarpackie",
  "voivodeshipCode": "18",
  "editionDate": "2025-12-29",
  "editionTitle": "Licencje osobowe (II półrocze 2025 r.)",
  "sourceResourceId": "989872",
  "sourceFileUrl": "https://api.dane.gov.pl/media/resources/20251229/.Licencje_osobowe.csv",
  "dataLicense": "CC0 1.0"
}
```

A changed row from a real comparison run (passenger permits, December vs June 2025):

```json
{
  "recordId": "ZO-41661-09110",
  "changeType": "changed",
  "changedFields": ["operatorName"],
  "previousValues": { "operatorName": "PAULINA GOŁASZEWSKA A i M TRAVEL TRANSPORT OSOBOWY I CIĘŻAROWY PAULINA GOŁASZEWSKA" },
  "operatorName": "PAULINA WÓJCIK A i M TRAVEL TRANSPORT OSOBOWY I CIĘŻAROWY PAULINA WÓJCIK",
  "editionDate": "2025-12-29",
  "comparedWithEditionDate": "2025-06-30"
}
```

#### Fields and measured fill (newest extracts, every row parsed)

| Field | Goods permits (28,521) | Passenger permits (758) | Goods licences (44,229) | Passenger licences (2,825) | Intermediaries (586) |
|---|---|---|---|---|---|
| `operatorName`, `authorisationNumber`, `postalCode`, `locality`, `addressFull` | 100% | 100% | 100% | 100% | 100% |
| `legalForm`, `legalFormCode`, `isSoleTrader` | 100% | 100% | 99.998% | 100% | `isSoleTrader` 100%, legal form not published |
| `postTown`, `streetAddress` | 100% | 100% | 100% | 100% | 98.8% / 99.0% |
| `voivodeship`, `voivodeshipCode` | 99.99% | 100% | 99.99% | 100% | not published |
| `licenceValidUntil`, `licenceStatus`, `daysUntilExpiry` | — | — | 100% | 100% | not published |
| `krsNumber` / `ceidgRegistered` | — | — | — | — | 52.2% / 100% |

`changeType`, `changedFields`, `previousValues` and `comparedWithEditionDate` are filled when a comparison runs.
Sole traders (osoba fizyczna) are 17,962 of the 28,521 goods permits.

### Use cases

- 🚚 **Truck and van dealers, leasing and fleet finance** — every licensed haulier in a voivodeship, with address.
- ⛽ **Fuel cards, tolling, telematics and tachograph services** — new permit holders each half-year as fresh leads.
- 🛡️ **Transport insurance brokers** — licences expiring in the next 90 days (1,788 on 2026-10-17).
- 🧾 **Freight forwarders and shippers** — check that a carrier's permit or licence is in GITD's published extract.
- 🚌 **Coach and passenger-transport suppliers** — the 758 passenger operator permits and 2,825 passenger licences.
- 📊 **Market analysts** — operators by voivodeship, legal form and how many enter and leave per half-year.

### How much does it cost to scrape the Polish road-transport register?

**$0.001 per row ($1.00 per 1,000 rows)**, no start fee. You pay only for rows delivered to your dataset.

| Rows | Cost |
|---|---|
| 20 | $0.02 |
| 100 | $0.10 |
| 1,000 | $1.00 |
| 28,521 (all goods permits) | $28.52 |
| 76,919 (all five registers) | $76.92 |

### Integrations, API, scheduling & MCP

- **Schedule** a monthly run with `editionChanges: "new"` or `onlyNewSinceLastRun: true` to pick up each new GITD
  extract as it appears.
- **Webhooks, Make, Zapier, n8n, Google Sheets, Slack** — connect them from the actor's Integrations tab.
- **API**: call the actor from [Python](https://apify.com/scrapersdelight/pl-road-transport-operators-scraper/api/python)
  or [JavaScript](https://apify.com/scrapersdelight/pl-road-transport-operators-scraper/api/javascript) with `apify-client`.
- **MCP**: use it from an AI agent through the [MCP tab](https://apify.com/scrapersdelight/pl-road-transport-operators-scraper/api/mcp).

### More transport and Polish register scrapers

| | | |
|---|---|---|
| 🇬🇧 [DVSA Operator Licence Scraper](https://apify.com/scrapersdelight/dvsa-operator-licence-scraper) — UK HGV and PSV operator licences with vehicles and transport managers | 🇬🇧 [Traffic Commissioner Applications](https://apify.com/scrapersdelight/traffic-commissioner-applications-scraper) — new UK operator-licence applications | 🇩🇪 [VUDat Transport Operators](https://apify.com/scrapersdelight/vudat-transport-permits-scraper) — German transport permits |
| 🇵🇱 [Polish Company Data Scraper](https://apify.com/scrapersdelight/pl-dane-spolki-website-contact-scraper) — KRS, NIP, REGON from company websites | 🇵🇱 [Poland Pharmacy Register Scraper](https://apify.com/scrapersdelight/rejestr-aptek-pl-scraper) — licensed pharmacies with NIP | 👉 [All our actors](https://apify.com/scrapersdelight) |

### Limits & empty runs

- **Freshness**: GITD publishes the extracts about twice a year. On 2026-10-17 the newest are dated 2025-12-29
  (both permit registers and passenger licences) and 2025-06-30 (goods licences, intermediaries). Every row
  carries its `editionDate`.
- **Not in the extracts**: NIP, REGON, vehicle numbers, transport managers, permit issue dates.
- **Licence status** is computed from the valid-to date against the day of the run; the extract itself carries no
  status. 7,436 of the 44,229 goods licences in the June 2025 extract have a valid-to date before 2026-10-17.
- **Two permit numbers are each used by two operators** in the December 2025 goods file; both rows are kept and
  the second gets a `-2` suffix on its `recordId`.
- **One dane.gov.pl upload is mislabeled** (the 2024-07-08 "Licencje towarowe" file holds passenger licences); the
  actor checks every file's numbers and skips such an extract, saying so in `RUN_SUMMARY`.
- **No rows** means your filters matched nothing in that extract; nothing is charged.
- A full read of the largest file (6.8 MB) took 10-40 s in our tests, because dane.gov.pl serves each connection
  slowly; small unfiltered runs finish in about 5 s.

### FAQ

#### How much does Poland Road Transport Operators Scraper cost?

$0.001 per delivered row, with no start fee. 100 rows cost $0.10 and the whole goods-permit register (28,521 rows)
$28.52.

#### How many operators can Poland Road Transport Operators Scraper return?

76,919 rows across the five registers in the newest extracts. Set `maxItems` to `0` for everything.

#### Does Poland Road Transport Operators Scraper return the NIP or the number of vehicles?

No. GITD does not include NIP, REGON, vehicle counts or transport managers in the extracts it publishes on
dane.gov.pl, and this actor never fills a field it cannot read from the source.

#### Can I get only new hauliers with Poland Road Transport Operators Scraper?

Yes: set `editionChanges` to `new`. Against the previous extract that gave 919 new goods permits for December 2025.
For a schedule, `onlyNewSinceLastRun` also skips everything you already received.

#### How often is the data updated?

Whenever GITD publishes a new extract on dane.gov.pl — about every six months. The actor always looks up the newest
one at run time.

#### Can I read an older extract?

Yes, with `editionDate`. Goods and passenger permits go back to 2018-12-17, licences to 2019-2020, intermediaries
to 2024-07-08. Older files are laid out differently in places (the 2020 goods-licence file has no postcode inside
the address, so `postTown` and `streetAddress` stay empty), and those fields are then null.

#### Can I schedule Poland Road Transport Operators Scraper?

Yes. A monthly schedule with `editionChanges: "new"` delivers nothing until GITD publishes a new extract, then the
new operators.

#### Can I use Poland Road Transport Operators Scraper through the Apify API or MCP?

Yes — see the API tab for Python, JavaScript and cURL, and the MCP tab for AI agents.

#### Do I need a login, API key or proxy?

No. The extracts are public open data; the actor downloads them directly.

#### Why did my run return no results?

Your filters matched nothing — for example a city spelled differently from the extract, or a legal-form filter on
the intermediaries register, which has no legal-form column. `RUN_SUMMARY` lists rows parsed and matched per register.

#### Your feedback

Found a bug or need another field? Open an issue on the [Issues tab](https://apify.com/scrapersdelight/pl-road-transport-operators-scraper/issues/open)
and we will look at it.

# Actor input Schema

## `registers` (type: `array`):

Which GITD registers to read. Rows in the newest extracts: goods permits 28,521 · passenger permits 758 · goods licences 44,229 · passenger licences 2,825 · passenger-transport intermediaries 586.

## `editionDate` (type: `string`):

Leave empty for the newest extract. Or give a date to read the newest extract published on or before it, e.g. 2024-12-31. Permits go back to 2018-12-17, licences to 2019-2020, intermediaries to 2024-07-08.

## `voivodeships` (type: `array`):

Only operators registered in these voivodeships. Empty = all of Poland. The intermediaries register has no voivodeship column, so its rows are dropped when this is set.

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

Keep operators whose locality (Miejscowość) or post town equals one of these, e.g. "Warszawa", "Poznań", "lodz". Case and diacritics are ignored.

## `postalCodePrefixes` (type: `array`):

Keep operators whose postcode starts with one of these, e.g. "00-" or "02" (Warsaw), "60-1". Only digits are compared.

## `legalForms` (type: `array`):

Keep these legal forms (Charakter prawny). The intermediaries register has no legal-form column.

## `nameContains` (type: `array`):

Keep operators whose name contains any of these words, e.g. "trans", "logistics", "bus".

## `nameExcludes` (type: `array`):

Drop operators whose name contains any of these words, e.g. "taxi".

## `authorisationNumbers` (type: `array`):

Look up specific numbers, e.g. "25661", "TU-047218", "OU-004837". Leading zeros and spaces are ignored.

## `licenceStatus` (type: `string`):

Computed from the licence's valid-to date against the day of the run. Permits and intermediary licences have no expiry in the extract: "valid" keeps them, "expired" drops them.

## `licenceExpiresWithinDays` (type: `integer`):

Only licences still valid today that expire within this many days, e.g. 90. Permits are dropped when this is set.

## `editionChanges` (type: `string`):

Compare the extract with GITD's previous one. "New" = numbers not in the previous extract; "changed" = name, address, legal form or expiry moved (with changedFields + previousValues); "removed" = gone since (rows from the older extract). Goods permits Jun -> Dec 2025: 919 new, 834 changed, 1,716 removed.

## `onlyNewSinceLastRun` (type: `boolean`):

Skip rows this actor already delivered to you in earlier runs with the same monitor key (kept in a named key-value store). Good for a schedule that should only pick up new extracts.

## `monitorKey` (type: `string`):

Name of the delivered-rows memory used by the option above, e.g. "mazowieckie-hauliers". Different keys keep separate histories.

## `sortBy` (type: `string`):

Order of the rows. "As published" is fastest: a small run without filters reads only the top of the file.

## `maxItems` (type: `integer`):

Stop after this many rows. 0 = no limit (all five registers together are about 76,900 rows).

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

Not needed: dane.gov.pl answers direct requests. A proxy you set here is used only if a direct request fails.

## Actor input object example

```json
{
  "registers": [
    "goods-permits"
  ],
  "voivodeships": [],
  "cities": [],
  "postalCodePrefixes": [],
  "legalForms": [],
  "nameContains": [],
  "nameExcludes": [],
  "authorisationNumbers": [],
  "licenceStatus": "any",
  "editionChanges": "off",
  "onlyNewSinceLastRun": false,
  "monitorKey": "default",
  "sortBy": "source",
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `operators` (type: `string`):

No description

## `runSummary` (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 = {
    "registers": [
        "goods-permits"
    ],
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapersdelight/pl-road-transport-operators-scraper").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 = {
    "registers": ["goods-permits"],
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("scrapersdelight/pl-road-transport-operators-scraper").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 '{
  "registers": [
    "goods-permits"
  ],
  "maxItems": 20
}' |
apify call scrapersdelight/pl-road-transport-operators-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapersdelight/pl-road-transport-operators-scraper"
        }
    }
}
```

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/gGSqSvbo1SdiqBZmb/builds/cYnFSJMdxOUwSVHm9/openapi.json
