# Portugal Court Decisions Scraper (DGSI Acórdãos) (`gefese/portugal-court-decisions-scraper`) Actor

Exports Portuguese court decisions (acórdãos) from the public DGSI databases: case number, court, rapporteur judge, descriptors, date, vote, decision and the official summary. Metadata and summaries only, never full texts. Unofficial tool.

- **URL**: https://apify.com/gefese/portugal-court-decisions-scraper.md
- **Developed by:** [Gonzalo Fajardo](https://apify.com/gefese) (community)
- **Categories:** Automation
- **Stats:** 2 total users, 1 monthly users, 86.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 result items

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Portugal Court Decisions Scraper (DGSI acórdãos)

Exports Portuguese court decisions (acórdãos) from the public legal databases at [www.dgsi.pt](https://www.dgsi.pt) as structured data: one record per decision with the case number, court, rapporteur judge, descriptors, decision date, vote, outcome and the court's official summary (sumário). You choose the courts, how many decisions per court, and optionally a keyword and a date range. Output formats: JSON, CSV, Excel, XML or HTML from the Apify dataset.

**Full texts are never returned.** The actor reads only a fixed list of labelled fields from each decision page (listed below) and ignores everything else on the page, including the full text of the decision and the party fields some databases show. There is no full-text option. This keeps the dataset to metadata and summaries.

This is an unofficial tool. It is not affiliated with, endorsed by or operated by the Portuguese courts, the Ministry of Justice or IGFEJ. Every record carries a `source` field naming the original source: DGSI, Bases Jurídico-Documentais (IGFEJ), www.dgsi.pt.

### What data does it return?

| Field | Meaning |
|---|---|
| `url` | Link to the decision page on dgsi.pt |
| `databaseCode`, `court` | Database code (for example `jstj`) and the court name |
| `caseNumber` | Case number (Processo) |
| `conventionalNumber` | Conventional number (Nº Convencional), when the database shows one |
| `judgeRapporteur` | Rapporteur judge (Relator) |
| `descriptors` | Array of descriptors (keywords) assigned by the court |
| `documentNumber` | Document number (Nº do Documento), when shown |
| `decisionDate` | Date of the decision, ISO `yyyy-mm-dd` |
| `vote` | Vote (Votação), for example `UNANIMIDADE` |
| `proceduralType` | Procedural means (Meio Processual), for example `REVISTA` or `APELAÇÃO` |
| `decision` | Outcome (Decisão) |
| `summary` | Official summary (Sumário) exactly as published; `null` when the decision has none |
| `source` | Attribution to the source of the data |
| `scrapedAt` | UTC time of scraping |

Fields a database does not publish are `null` (an empty array for `descriptors`). Available courts: Supremo Tribunal de Justiça (`jstj`), Supremo Tribunal Administrativo (`jsta`), Tribunal dos Conflitos (`jcon`), the five Relações (`jtrp` Porto, `jtrl` Lisboa, `jtrc` Coimbra, `jtrg` Guimarães, `jtre` Évora) and the two Tribunais Centrais Administrativos (`jtca` Sul, `jtcn` Norte).

### How to run it

1. Open the Actor and keep the prefilled input: databases `jstj` and `jtrp`, 10 decisions per database.
2. Click **Start**. The prefilled run reads about 20 decisions and, in a local test, finished in about 25 seconds.
3. Open the **Output** tab, or download the dataset as JSON, CSV or Excel.
4. To change the scope, pick other databases, raise the maximum, add search terms or set a date range (see the input example).

Without search terms each database is read newest first. With `dateFrom` the reading stops as soon as the listing is older than that date; with `dateTo` the actor jumps straight to that date, which costs roughly 15 to 20 extra requests per database. With search terms, the court's own full-text search is used; it returns at most about 500 hits per term, in relevance order, so the date filter is applied to those hits one by one.

### How much does it cost to scrape DGSI decisions?

The price is **0.001 USD per decision** (one `result` event per dataset item), so 1,000 decisions cost 1 USD and the prefilled 20-decision run costs 0.02 USD. There is no start fee. Set a maximum total charge on the run and the actor stops when it is reached. Apify platform usage is separate, but the actor only makes plain HTTP requests and runs with 256 MB of memory.

### Input example

```json
{
  "databases": ["jstj", "jtrp"],
  "maxResultsPerDatabase": 10,
  "queries": [],
  "dateFrom": "",
  "dateTo": ""
}
```

With a keyword and dates: `{"databases": ["jstj"], "maxResultsPerDatabase": 50, "queries": ["usucapião"], "dateFrom": "2015-01-01"}`.

### Output example

Three real items from a local run:

```json
{
  "url": "https://www.dgsi.pt/jstj.nsf/954f0ce6ad9dd8b980256b5f003fa814/d2523b00ca3b3d3e80258e88003cc00d?OpenDocument",
  "databaseCode": "jstj",
  "court": "Supremo Tribunal de Justiça",
  "caseNumber": "5306/20.0T8BRG.G3.S1",
  "conventionalNumber": "2.ª SECÇÃO",
  "judgeRapporteur": "CATARINA SERRA",
  "descriptors": [
    "DIVORCIO SEM CONSENTIMENTO",
    "ATO PROCESSUAL",
    "VÍCIOS DA VONTADE",
    "CAPACIDADE JUDICIÁRIA",
    "FALTA DE CONSCIÊNCIA",
    "PETIÇÃO INICIAL",
    "ABSOLVIÇÃO DA INSTÂNCIA",
    "MAIOR ACOMPANHADO",
    "VONTADE",
    "DECLARAÇÃO NEGOCIAL",
    "CAPACIDADE JURÍDICA",
    "AUTONOMIA PRIVADA",
    "DIREITOS DE PERSONALIDADE",
    "PERÍCIA PSIQUIÁTRICA",
    "INCAPACIDADE ACIDENTAL"
  ],
  "documentNumber": null,
  "decisionDate": "2026-10-01",
  "vote": "UNANIMIDADE",
  "proceduralType": "REVISTA",
  "decision": "NEGADA",
  "summary": "A falta e os vícios da vontade são suscetíveis de relevar no domínio dos actos processuais; relevam, em particular, quando atingem um acto postulativo.",
  "source": "DGSI - Bases Juridico-Documentais, IGFEJ (www.dgsi.pt)",
  "scrapedAt": "2026-10-10T12:16:58Z"
}
```

```json
{
  "url": "https://www.dgsi.pt/jstj.nsf/954f0ce6ad9dd8b980256b5f003fa814/645ffd40f74af36580258e8b004901a7?OpenDocument",
  "databaseCode": "jstj",
  "court": "Supremo Tribunal de Justiça",
  "caseNumber": "2473/24.7T8PDL.L1.S1",
  "conventionalNumber": "7.ª SECÇÃO",
  "judgeRapporteur": "NUNO PINTO OLIVEIRA",
  "descriptors": [
    "SUBSEGURO",
    "CONTRATO DE SEGURO",
    "INUNDAÇÃO",
    "CLÁUSULA CONTRATUAL GERAL",
    "REGIME APLICÁVEL",
    "DEVER DE INFORMAÇÃO",
    "DEVER DE COMUNICAÇÃO",
    "VIOLAÇÃO",
    "TOMADOR",
    "ÓNUS DE ALEGAÇÃO",
    "ÓNUS DA PROVA",
    "FACTO MODIFICATIVO",
    "FACTO IMPEDITIVO",
    "REGRA PROPORCIONAL"
  ],
  "documentNumber": null,
  "decisionDate": "2026-10-01",
  "vote": "UNANIMIDADE",
  "proceduralType": "REVISTA",
  "decision": "NEGADA",
  "summary": "I - O subseguro é um facto modificativo, parcialmente impeditivo, do direito à indemnização.\nII - O não cumprimento do dever de comunicação previsto no n.º 2 do art. 135.º do RJCS, é um facto impeditivo daquele facto modificativo.\nIII - Como o não cumprimento do dever de comunicação seja um facto impeditivo daquele facto modificativo, terá de ser alegado pelo segurado.",
  "source": "DGSI - Bases Juridico-Documentais, IGFEJ (www.dgsi.pt)",
  "scrapedAt": "2026-10-10T12:17:02Z"
}
```

```json
{
  "url": "https://www.dgsi.pt/jtrp.nsf/56a6e7121657f91e80257cda00381fdf/456901471fa16fb280258e88003a76dc?OpenDocument",
  "databaseCode": "jtrp",
  "court": "Tribunal da Relação do Porto",
  "caseNumber": "2971/10.0TXPRT-AL.E1.P1",
  "conventionalNumber": "JTRP000",
  "judgeRapporteur": "MARIA JOANA GRÁCIO",
  "descriptors": [
    "REVOGAÇÃO DE LICENÇA DE SAÍDA JURISDICIONAL",
    "REQUISITOS DO DESPACHO"
  ],
  "documentNumber": "RP202609302971/10.0TXPRT-AL.E1.P1",
  "decisionDate": "2026-09-30",
  "vote": "UNANIMIDADE",
  "proceduralType": "CONFERÊNCIA",
  "decision": "PROVIDO RECURSO DO ARGUIDO",
  "summary": "A decisão de revogação de licença de saída jurisdicional proferida no âmbito de incidente de incumprimento, ao abrigo do disposto no art. 195.º do CEPMPL, não prescinde da descrição factual da conduta do condenado que fundamenta o incumprimento, e, bem assim, da prévia produção de prova sobre os factos em causa.\n(Sumário da responsabilidade da Relatora)",
  "source": "DGSI - Bases Juridico-Documentais, IGFEJ (www.dgsi.pt)",
  "scrapedAt": "2026-10-10T12:17:10Z"
}
```

### Limitations and the free plan

- Metadata and summaries only; full texts are never returned and cannot be switched on.
- Many decisions from before 2000 are summary-only or have an empty summary; some databases (for example the administrative courts) have no summary on recent decisions either. Those records are returned with the fields that exist and `null` or an empty list for the rest.
- Fields differ between courts. For example `documentNumber` is empty for recent `jstj` decisions and `proceduralType` is empty for the central administrative courts.
- The actor is deliberately slow: one request at a time, at least one second apart, and one extra request per decision. About 50 decisions take one to two minutes.
- It reads dgsi.pt's robots.txt at the start of every run and obeys it. If the site answers 403 or 429, reading of that database stops; temporary 503 errors are retried twice.
- The connection to dgsi.pt is always verified (certificate chain and host name). The actor ships the public Let's Encrypt intermediate certificates next to its normal trusted roots, so it can still verify the site if the site sends an incomplete or wrong certificate chain; verification is never switched off.
- Keyword search is handed to the court database's own search, so what matches is decided by that search. Results depend on what the site returns at the time of the run.
- Free plan: the actor has no special restrictions for free accounts. The prefilled run is small (20 decisions, 0.02 USD of results); larger exports are limited by the one-request-per-second pace and by the maximum charge you set.

### FAQ

**Is the data official?** It is copied from the public pages of dgsi.pt. Check the linked decision page for the authoritative version. The summary is the court's own text, copied as published.

**Why no full text?** Full decisions can contain personal details of private individuals. The actor never reads them.

**Do I need an account on dgsi.pt?** No. The pages are public and the actor does not log in.

**Something is wrong or a court changed its pages.** Please report it in the Issues tab of this Actor on Apify, with the input you used.

# Actor input Schema

## `databases` (type: `array`):

Which court databases of dgsi.pt to read. Each database is read separately, newest decisions first, and gets its own limit below.

## `maxResultsPerDatabase` (type: `integer`):

Stops reading a database after this many decisions. Each decision is one billed result and costs one extra request, so about 50 decisions take one to two minutes.

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

Optional keywords, Portuguese works best, for example "usucapião". Each term is sent to the court database's own full-text search, which returns at most about 500 hits per term in relevance order. Leave empty to read the databases newest first.

## `dateFrom` (type: `string`):

Optional. Only decisions dated on or after this day. Without search terms the listing is newest first, so reading stops as soon as it passes this date.

## `dateTo` (type: `string`):

Optional. Only decisions dated on or before this day. Without search terms the actor jumps straight to that date in the listing (about 15 extra requests).

## Actor input object example

```json
{
  "databases": [
    "jstj",
    "jtrp"
  ],
  "maxResultsPerDatabase": 10,
  "queries": []
}
```

# Actor output Schema

## `results` (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 = {
    "databases": [
        "jstj",
        "jtrp"
    ],
    "maxResultsPerDatabase": 10,
    "queries": [],
    "dateFrom": "",
    "dateTo": ""
};

// Run the Actor and wait for it to finish
const run = await client.actor("gefese/portugal-court-decisions-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 = {
    "databases": [
        "jstj",
        "jtrp",
    ],
    "maxResultsPerDatabase": 10,
    "queries": [],
    "dateFrom": "",
    "dateTo": "",
}

# Run the Actor and wait for it to finish
run = client.actor("gefese/portugal-court-decisions-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 '{
  "databases": [
    "jstj",
    "jtrp"
  ],
  "maxResultsPerDatabase": 10,
  "queries": [],
  "dateFrom": "",
  "dateTo": ""
}' |
apify call gefese/portugal-court-decisions-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,gefese/portugal-court-decisions-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/1TpGN2wPrBn6diUXk/builds/kIh1zedqbLtB0hrn2/openapi.json
