# Brazilian Property Auction Scraper (`dami_studio/leilao-imovel-scraper`) Actor

Judicial and extrajudicial property auctions across Brazil. Minimum bid, appraisal, discount, both praça dates with their own minimum bids, auction house, selling bank, occupancy, areas, court case reference, and the matrícula and edital PDFs. Filter by state, city, auction type and price.

- **URL**: https://apify.com/dami\_studio/leilao-imovel-scraper.md
- **Developed by:** [Dami's Studio](https://apify.com/dami_studio) (community)
- **Categories:** Real estate, Business, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.90 / 1,000 property 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

## Brazilian Property Auction Scraper

Judicial and extrajudicial property auctions across Brazil, as rows you can sort. You get the
minimum bid, the appraisal the discount is calculated from, both auction rounds with their dates
and their own minimum bids, the auction house running it, whether the place is occupied, and direct
links to the matrícula and the edital PDFs.

One aggregator sits behind this, the one that carries the private auction houses and the bank
portfolios in a single index: around **31,000 live listings** on the day this was written, of which
**13,700 are judicial or extrajudicial** and about **18,700 are not Caixa stock**. Counts read off
the portal's own filter panel on 19 September 2026.

### The awkward parts, before the feature list

**A single search will not return more than about 969 properties.** The portal serves 19 per page
and stops answering after page 51, whatever number it prints at the top. Ask for 5,000 rows from one
wide query and you will get 969 and a warning in the log saying so. The way past it is to split the
run: by state, by city, by property type, by price band. This actor already splits by state
for you when you name states. That ceiling is the portal's, not ours, and nothing on our side can
lift it.

**Names are deliberately missing.** Auction notices are written by the auction houses and they name
people: the debtor, sometimes the creditor, sometimes the owner mid-sentence with no label at all.
We read the seller's free-text notes for the case number, the court, the district and the registry
number, and then we throw the prose away. There is no `description` field and there will not be one.
Every string that does go out is checked against a personal-data pattern list before it is written,
and anything that trips it is dropped with a warning in the log.

**Caixa is in here, but this is not the Caixa actor.** The aggregator indexes Caixa's stock
alongside everything else, so the four Caixa sale types are available as filters. If Caixa is all
you want, read it from Caixa directly. That source carries paperwork this one does not (ofício,
inscrição imobiliária, the averbação line, Caixa's own edital and item numbers).

**Auction dates move.** A property whose first round is a week away can be pulled, settled or
re-scheduled without notice. Treat a row as true at `scrapedAt` and no later.

### What a row looks like

A real judicial listing, exactly as it came back:

```json
{
  "propertyId": "3020681",
  "listingUrl": "https://www.leilaoimovel.com.br/imovel/sp/sao-paulo/residencial-apartamento-desocupado-de-92-83-m-no-condominio-parque-marajoara-sol-jardim-marajoara-sao-paulo-desocupado-imovel-3020681",
  "state": "SP",
  "city": "São Paulo",
  "neighbourhood": "Jardim Marajoara",
  "street": "Av. Interlagos",
  "addressFull": "Avenida Interlagos, 492- Apartamento nº 12",
  "propertyType": "Apartamento",
  "auctionCategory": "Judicial",
  "auctionHouse": "Máximo Leilões",
  "occupancyStatus": "Desocupado",
  "appraisedValueBrl": 720592.07,
  "minimumBidBrl": 360296.03,
  "discountPercent": 50,
  "rounds": [
    { "round": 1, "startsAt": "2026-09-17T16:00:00", "minimumBidBrl": 720592.07 },
    { "round": 2, "startsAt": "2026-10-07T16:00:00", "minimumBidBrl": 360296.03 }
  ],
  "auctionDate": "2026-10-07T16:00:00",
  "auctionEndsAt": "2026-10-07T16:00:00",
  "totalAreaSqm": null,
  "privateAreaSqm": 92.83,
  "bedrooms": null,
  "garageSpaces": 1,
  "paymentTerms": "Somente à vista",
  "courtCaseNumber": "4000053-82.2015.8.26.0002",
  "court": "1ª Vara Cível do Foro Regional de Santo Amaro",
  "judicialDistrict": "Capital",
  "registrationNumber": "216.352 - 216.453",
  "registryOffice": null,
  "deedPdfUrl": "https://d24y7usudqxuz0.cloudfront.net/bens/0000000100/matricula-vaga-6a6bb212e3299.pdf",
  "noticePdfUrl": "https://d24y7usudqxuz0.cloudfront.net/bens/0000000100/edital-6a70f62388f40.pdf",
  "photoUrls": ["https://image.leilaoimovel.com.br/images/81/apartamento-em-sao-paulo-sp-3020681-…-g.webp"],
  "listedAt": "2026-09-17",
  "geoPrecision": "Localização Precisa",
  "isNewListing": true,
  "scrapedAt": "2026-09-20T03:47:57.000Z"
}
```

`rounds` is the field the rest of this exists for. A Brazilian judicial auction runs in two praças:
the first at or near the appraisal, the second (usually a couple of weeks later) at a fraction of
it. `minimumBidBrl` at the top of the row is the price that is live right now; the array tells you
what each round asks and when it opens.

#### Every field

| Field | What it holds |
|---|---|
| `propertyId`, `listingUrl` | the portal's own code, and the page it came from |
| `state`, `city`, `neighbourhood`, `street`, `addressFull` | location, broken out and as printed |
| `propertyType` | Apartamento, Casa, Terreno, Área rural, Comercial, Galpão, Garagem and the rest |
| `auctionCategory` | Judicial, Extrajudicial, Venda Direta, Comprei PGFN, Particular, Outro, or one of the four Caixa types |
| `auctionHouse` | the firm running the sale |
| `occupancyStatus` | Desocupado / Ocupado, where the notice states it |
| `appraisedValueBrl`, `minimumBidBrl`, `discountPercent` | the appraisal, the live minimum bid, and the gap between them |
| `rounds[]` | one entry per praça: `round`, `startsAt`, `minimumBidBrl` |
| `auctionDate` | the next round still ahead; falls back to the closing date |
| `auctionEndsAt` | when the listing closes |
| `totalAreaSqm`, `privateAreaSqm` | whichever the notice gives |
| `bedrooms`, `garageSpaces` | where stated |
| `paymentTerms` | "Somente à vista", instalments, and so on |
| `courtCaseNumber`, `court`, `judicialDistrict` | the proceeding behind a judicial auction |
| `registrationNumber`, `registryOffice` | matrícula and ofício where the notice prints them |
| `deedPdfUrl`, `noticePdfUrl` | the matrícula and the edital, as links. The files are not downloaded |
| `photoUrls` | listing photos, up to 30 |
| `listedAt`, `isNewListing`, `geoPrecision` | when it appeared, whether it is new, how exact the geocode is |
| `scrapedAt` | when this row was read |

A field that the notice does not state comes back `null`. It is never guessed.

### Input

```json
{
  "auctionCategories": ["judicial", "extrajudicial"],
  "states": ["SP", "RJ"],
  "propertyTypes": ["apartamento", "casa"],
  "minDiscountPercent": 40,
  "maxPriceBrl": 400000,
  "sortBy": "discount-desc",
  "maxItems": 200
}
```

Everything is optional except that you have to give at least one filter, or paste property URLs.
An empty run writes a single sample row, free, showing you the shape.

- **`auctionCategories`**: judicial, extrajudicial, venda-direta, comprei-pgfn, particular, outro,
  plus caixa-leilao-sfi, caixa-licitacao-aberta, caixa-venda-online, caixa-compra-direta.
- **`states`**: two-letter codes. Each one is searched separately, which is also how you get more
  than 969 rows out of a wide query.
- **`cities`**: municipality names. Accents and case do not matter. Setting cities drops the state
  filter, because the cities already pin the location. A city the portal does not list comes back as
  a diagnostic row naming it rather than silently vanishing.
- **`sellerInstitutions`**: Caixa, Banco do Brasil, Santander, Itaú, Bradesco, Inter, BRB, BTG, BV,
  Safra, Sicoob, Porto Seguro, Embracon, Emgea, Assefaz, Reverts.
- **`propertyTypes`**, **`paymentOptions`**, **`keyword`**, **`minPriceBrl`**, **`maxPriceBrl`**,
  **`minDiscountPercent`**, **`auctionBefore`** (YYYY-MM-DD).
- **`sortBy`**: decides which end of the list you get when your search is bigger than `maxItems`.
  Cheapest first, biggest discount first, closing soonest first, newest listings first.
- **`includeAuctionDetails`**: on by default. Off reads the results list only: you keep the price,
  appraisal, discount, address, type and closing date, and you lose the rounds, the auction house,
  the areas and the PDFs. It is several times faster. Both settings cost the same per property.
- **`propertyUrls`**: paste listing pages to re-read specific properties.
- **`maxItems`**: hard cap. You are charged per property returned.

### Pricing

Pay per property returned, plus a small fee per run. Sample rows and diagnostic rows are free. If a
search matches nothing, if a city is not listed, if a property has been withdrawn, or if the portal
refuses the run, you are told why and charged nothing for it. Rows your own `minDiscountPercent` or
`maxPriceBrl` drop are not charged either.

`includeAuctionDetails: false` costs the same per property as leaving it on, so turn it off for
speed, not to save money.

### Speed, measured

From real runs on 20 September 2026:

| Run | Rows | Time |
|---|---|---|
| Judicial, SC, list only | 6 | 7.6 s |
| Judicial + extrajudicial, RJ | 14 | 10.1 s |
| Judicial + extrajudicial, MG | 60 | 40.1 s |
| Same, list only | 60 | 23.5 s |
| Judicial + extrajudicial, SP | 100 | 93.7 s |
| Judicial + extrajudicial, SP | 100 | 112.6 s |
| Judicial + extrajudicial, BA | 120 | 105.8 s |

So roughly **0.7 to 1.1 s per property** with the pages open, and about **0.4 s** without.

Those are good days. The portal is slower from some networks than others, and a run that lands on a
bad one can take three times as long for the same rows. It still returns everything; it just takes
longer. Nothing about that changes what you are charged, which is per property either way.

### What this does not do

- **No more than ~969 rows from one query.** Covered above. Split by state or city.
- **No seller prose.** No `description` field, for the reason in the second section.
- **No PDF contents.** You get the matrícula and edital links; parsing them is your side.
- **No bid history and no live bid amounts.** Fixed-price online sales show a running bid on the
  portal; this returns the listed minimum, not the current high bid.
- **No logins, no accounts, no saved searches.** Everything here is what a logged-out visitor sees.
- **`bedrooms` and `totalAreaSqm` are frequently null** on judicial listings, because the notice
  simply does not state them. Private-sale listings fill more of the fields.
- **Coverage is one aggregator's index.** A small auction house that does not syndicate to it will
  not appear, however real its auctions are.
- **Nothing here is legal or investment advice.** An edital and a current matrícula decide what you
  are actually buying; a row in a dataset does not.

### FAQ

**What is the difference between a judicial and an extrajudicial auction?**
A judicial auction is ordered by a court inside a case, and the row carries the case number, the
court and the district. An extrajudicial one is run by a creditor, usually a bank enforcing a
mortgage, outside court under the alienação fiduciária rules. Both appear here; filter with
`auctionCategories`.

**What are 1ª and 2ª praça?**
The two rounds of a judicial auction. The first opens at or near the appraised value. If nobody
bids, the second opens days or weeks later at a much lower minimum, which is where the large
discounts in this data come from. Both are in `rounds`, each with its own date and minimum bid.

**How is `discountPercent` calculated?**
It is the portal's own figure: how far the live minimum bid sits below `appraisedValueBrl`. It is
not recomputed here, so it always matches what a buyer sees on the page.

**Can I get every auction in Brazil in one run?**
Not from one query; see the 969-row ceiling. Name all 27 states and the actor runs one search per
state, which raises the reachable total accordingly.

**Does it return Caixa properties?**
Yes, through the four Caixa filters. For Caixa alone, its own source carries more of the paperwork.

**Why is there no owner or debtor name?**
Because auction notices carry them and we strip them. See the second section.

**Do I need an account or an API key anywhere?**
No. Nothing here needs a login.

**How fresh is the data?**
Each row is read live when the run executes; `scrapedAt` records the moment. Auction dates and
prices can change after that.

# Actor input Schema

## `auctionCategories` (type: `array`):

Which kind of auction to pull. Judicial auctions are ordered by a court; extrajudicial ones are run by a bank or creditor outside court. Leave empty for all of them. The four Caixa categories are included for completeness, but if Caixa stock is all you want, the dedicated Caixa actor reads it from Caixa directly and returns more of its paperwork.

## `states` (type: `array`):

Two-letter Brazilian state codes, one per line: SP, RJ, MG, BA and so on. Leave empty to search the whole country. Each state is searched as its own query, which is also how you get past the portal's result ceiling — see the README.

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

Municipality names, one per line. Accents and case do not matter — "sao jose do rio preto" matches. When you set cities the state filter is dropped, because the cities already pin the location. A name the portal does not list is reported back rather than silently ignored.

## `propertyTypes` (type: `array`):

Leave empty for every type.

## `sellerInstitutions` (type: `array`):

Only properties being sold by these banks or funds. Leave empty for all sellers, including the court-ordered auctions that have no bank behind them.

## `keyword` (type: `string`):

Free text matched against the listing, for example a condominium name, a street or "praia". Leave empty to skip it.

## `minPriceBrl` (type: `integer`):

Floor on the minimum bid, in reais. 0 means no floor.

## `maxPriceBrl` (type: `integer`):

Ceiling on the minimum bid, in reais. 0 means no ceiling.

## `minDiscountPercent` (type: `integer`):

Keep only properties whose minimum bid is at least this far under the appraisal. 0 keeps everything.

## `paymentOptions` (type: `array`):

Most of this stock is cash only. Set this to see just the properties that accept financing, instalments or FGTS.

## `auctionBefore` (type: `string`):

Only auctions closing on or before this date, as YYYY-MM-DD. Leave empty for no cut-off.

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

Which end of the list to take first. This matters when your search finds more than the run's limit: the order decides which properties you get.

## `includeAuctionDetails` (type: `boolean`):

On (recommended): opens every property's own page and returns the auction rounds with their dates and minimum bids, the auction house, the areas, occupancy, the registry and case references and links to the matrícula and edital PDFs. Off: reads the results list only — far faster, but you get no auction dates, no auction house, no PDFs and no areas. Both settings charge the same per property.

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

Hard cap on properties returned across every state and filter in this run. You are charged per property returned.

## `propertyUrls` (type: `array`):

Paste property pages from the portal, one per line. Works on its own or alongside a search.

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

Leave this alone unless you must exit from a particular network. The actor picks a working address by itself.

## Actor input object example

```json
{
  "auctionCategories": [
    "judicial",
    "extrajudicial"
  ],
  "states": [],
  "cities": [],
  "propertyTypes": [],
  "sellerInstitutions": [],
  "paymentOptions": [],
  "includeAuctionDetails": true,
  "maxItems": 50,
  "propertyUrls": [],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

One row per property: the portal's property code and page URL, state, city, neighbourhood, street and full address, property type, auction type (judicial, extrajudicial, direct sale and the rest), the auction house, occupancy, the appraisal, the minimum bid and the discount, every auction round with its date and its own minimum bid, the closing date, the three area figures, bedrooms and parking, payment terms, the court case number, court, district, registry number and registry office where the notice states them, links to the matrícula and edital PDFs, photos, and the date the listing appeared. Empty input, an unknown filter value or a property that has been withdrawn writes an uncharged sample or diagnostic row instead.

# 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 = {
    "auctionCategories": [
        "judicial",
        "extrajudicial"
    ],
    "states": [],
    "cities": [],
    "propertyTypes": [],
    "sellerInstitutions": [],
    "keyword": "",
    "minPriceBrl": 0,
    "maxPriceBrl": 0,
    "minDiscountPercent": 0,
    "paymentOptions": [],
    "auctionBefore": "",
    "sortBy": "",
    "includeAuctionDetails": true,
    "maxItems": 50,
    "propertyUrls": [],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("dami_studio/leilao-imovel-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 = {
    "auctionCategories": [
        "judicial",
        "extrajudicial",
    ],
    "states": [],
    "cities": [],
    "propertyTypes": [],
    "sellerInstitutions": [],
    "keyword": "",
    "minPriceBrl": 0,
    "maxPriceBrl": 0,
    "minDiscountPercent": 0,
    "paymentOptions": [],
    "auctionBefore": "",
    "sortBy": "",
    "includeAuctionDetails": True,
    "maxItems": 50,
    "propertyUrls": [],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("dami_studio/leilao-imovel-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 '{
  "auctionCategories": [
    "judicial",
    "extrajudicial"
  ],
  "states": [],
  "cities": [],
  "propertyTypes": [],
  "sellerInstitutions": [],
  "keyword": "",
  "minPriceBrl": 0,
  "maxPriceBrl": 0,
  "minDiscountPercent": 0,
  "paymentOptions": [],
  "auctionBefore": "",
  "sortBy": "",
  "includeAuctionDetails": true,
  "maxItems": 50,
  "propertyUrls": [],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call dami_studio/leilao-imovel-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/leilao-imovel-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/bvAV8b2PtfimleHyf/builds/0wfvgX6svrw9d46Wc/openapi.json
