# CourtListener Court Opinions Scraper — Free Case Law Search (`devilscrapes/courtlistener-court-opinions-scraper`) Actor

Search 240,000+ U.S. court opinions on CourtListener's free, keyless full-text API and export clean, paginated case-law rows — case name, court, filing date, citations, cite count, and a direct opinion URL. No API key, no PACER account, no docket-reseller subscription.

- **URL**: https://apify.com/devilscrapes/courtlistener-court-opinions-scraper.md
- **Developed by:** [DevilScrapes](https://apify.com/devilscrapes) (community)
- **Categories:** Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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

<div align="center">
  <img src=".actor/icon.svg" width="160" alt="Devil Scrapes mark" />

## CourtListener Court Opinions Scraper

**💰 $5.05 / 1 000 results**  ·  pay only for results  ·  no credit card to try

*The devil's in the data — we bring back every case that matches your query.* 😈

Search 240,000+ U.S. court opinions on CourtListener's free, keyless full-text API and export clean, paginated case-law rows — case name, court, filing date, citations, cite count, and a direct opinion URL. No API key, no PACER account, no docket-reseller subscription.

</div>

***

### 🎯 What this scrapes

This Actor searches **CourtListener's free, keyless full-text case-law
API** (opinions only — not RECAP/PACER dockets) and returns one
structured row per matching case. Each row carries the case name, court,
filing date, citation(s), cite count, and a direct link to the opinion.

CourtListener's search already covers 240,000+ U.S. court opinions for
free — the work we sell is the handling: following CourtListener's
cursor-based pagination correctly, isolating one malformed result so it
doesn't crash the whole run, and shipping a clean, nullable dataset
schema instead of a raw API passthrough.

### 🔥 What we handle for you

- 🛡️ **We rotate browser fingerprints** (curl-cffi impersonation) so every request looks like a real browser, not Python.
- 🔁 **We retry with exponential backoff** on `408 / 429 / 503` and honour `Retry-After` — up to 5 attempts per page.
- 🌐 **We rotate residential proxies** through Apify Proxy on every retry — fresh session, fresh exit IP.
- 🧱 **We isolate per-row failures** — one malformed result is skipped and logged, the run keeps going.
- 🧊 **We keep the dataset clean** — Pydantic-validated rows, nullable fields typed correctly, a stable `url` on every row.
- 💰 **You pay only for cases that land.** A search that matches nothing still succeeds — you're never charged for a failed run.

### 💡 Use cases

- **Legal research** — pull every opinion matching a legal question, party name, or topic for a memo or brief.
- **Litigation support** — build a bulk case-law dataset for a matter without a PACER/docket subscription.
- **Legal-tech products** — feed a clean, structured case-law dataset into your own search or citation tool.
- **Compliance / due diligence** — check whether a party, company, or topic shows up in published case law.
- **Academic research** — pull opinions filed within a date range or court for empirical legal studies.

### ⚙️ How to use it

1. Click **Try for free** at the top of the page.
2. Enter a **Query** — free text, e.g. `"miranda rights"`.
3. Optionally narrow with **Court** (a CourtListener short code like `scotus`), **Filed after** / **Filed before** dates, or change **Order by**.
4. Set **Max results** (up to 1,000).
5. Click **Start**. Rows stream into the run's dataset as CourtListener's cursor pages are followed.
6. Export from **Storage → Dataset** as JSON, CSV, or Excel — or fetch via the API.

### 📥 Input

| Field | Type | Required | Default | Notes |
|---|---|:--:|---|---|
| `query` | `string` | yes | — | Free-text search against CourtListener's full-text opinion index. |
| `court` | `string` | no | — | Court short code (e.g. `scotus`). Omit to search all courts. |
| `filedAfter` | `string` | no | — | `YYYY-MM-DD` — only opinions filed on or after this date. |
| `filedBefore` | `string` | no | — | `YYYY-MM-DD` — only opinions filed on or before this date. |
| `orderBy` | `string` | no | `"score desc"` | One of `score desc`, `dateFiled desc`, `dateFiled asc`, `citeCount desc`. |
| `maxResults` | `integer` | no | `100` | Cap on total rows across all cursor pages (1-1,000). |
| `proxyConfiguration` | `object` | no | `{"useApifyProxy": true}` | Apify Proxy configuration. |

#### Example input

```json
{
  "query": "miranda rights",
  "maxResults": 100,
  "proxyConfiguration": {"useApifyProxy": true}
}
```

### 📤 Output

Every row is one matched court opinion.

| Field | Type | Notes |
|---|---|---|
| `cluster_id` | `integer` | CourtListener's internal opinion-cluster ID. |
| `case_name` | `string` | Short case name (e.g. `"Miranda v. Arizona"`). |
| `case_name_full` | `string` | Full case name/caption as filed. |
| `court` | `string` | Human-readable court name. |
| `court_id` | `string` | CourtListener's court short code (e.g. `"scotus"`). |
| `court_citation_string` | `string` | Court's citation-reporter abbreviation. |
| `court_jurisdiction` | `string \| null` | Court jurisdiction label, when published. |
| `date_filed` | `string \| null` | ISO `YYYY-MM-DD` filing date, when published. |
| `date_argued` | `string \| null` | ISO `YYYY-MM-DD` argument date, when published. |
| `citation` | `array<string>` | Reporter citation(s) for this opinion (may be empty). |
| `cite_count` | `integer` | Number of times this opinion has been cited. |
| `attorney` | `string \| null` | Attorney(s) of record, when published. |
| `url` | `string` | Direct CourtListener URL to the full opinion page. |

#### Example output

```json
{
  "cluster_id": 10353022,
  "case_name": "Miranda v. Arizona",
  "case_name_full": "Ernesto A. Miranda v. State of Arizona",
  "court": "Supreme Court of the United States",
  "court_id": "scotus",
  "court_citation_string": "U.S.",
  "court_jurisdiction": null,
  "date_filed": "1966-06-13",
  "date_argued": null,
  "citation": ["384 U.S. 436"],
  "cite_count": 8421,
  "attorney": "",
  "url": "https://www.courtlistener.com/opinion/10353022/miranda-v-arizona/"
}
```

### 💰 Pricing

Pay-Per-Event — you pay only when these events fire:

| Event | USD | What it is |
|---|---:|---|
| `actor-start` | $0.05 | One-off warm-up charge per run |
| `result-scraped` | $0.005 | Per case-opinion row written to the dataset |

Example: 100 matched rows ≈ **$0.55** total per run; at 1,000 rows that's
**$5.05/1,000** ($0.05 start + 1000 x $0.005). No subscription, no
minimum, no card to start — Apify gives every new account free credit.

### 🚧 Limitations

This Actor covers **opinion search only** (`type=o`) — RECAP/PACER
dockets and oral arguments are out of scope for v1. It returns
metadata and search snippets, not full opinion-body text. CourtListener's
rate limits aren't stress-tested beyond a handful of requests, so
sustained heavy pagination may hit retries. `maxResults` is capped at
1,000 rows per run.

### ❓ FAQ

**Does this need a CourtListener account or API key?**

No. CourtListener's `/api/rest/v4/search/` endpoint is free and keyless
for opinion search.

**Does this cover PACER/RECAP dockets?**

No — v1 is opinion search (`type=o`) only. Dockets and oral arguments
are a candidate for a future version.

**What happens if my query matches nothing?**

The run finishes successfully with zero rows and a status message
naming the query — you're not charged for a failed run.

**Can I filter by court or date range?**

Yes — set `court` to a CourtListener short code (e.g. `scotus`) and/or
`filedAfter`/`filedBefore` to narrow results server-side.

### 💬 Your feedback

Spotted a bug, hit a weird edge case, or need dockets/oral-argument
coverage? Open an issue on the Actor's **Issues** tab on Apify Console —
we ship fixes weekly and we read every report.

***

<div align="center">

Built by **[Devil Scrapes](https://apify.com/DevilScrapes)** 😈 — a small fleet of
opinionated public-data Actors. Honest pricing, real engineering, zero fine print.

</div>

# Actor input Schema

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

Free-text search against CourtListener's full-text opinion index (maps to the API's `q` parameter).

## `court` (type: `string`):

Restrict to one court by its CourtListener short code (e.g. "scotus" for the Supreme Court). Leave blank to search all courts.

## `filedAfter` (type: `string`):

Only return opinions filed on or after this date (YYYY-MM-DD).

## `filedBefore` (type: `string`):

Only return opinions filed on or before this date (YYYY-MM-DD).

## `orderBy` (type: `string`):

Result ordering, passed through to CourtListener's `order_by` parameter.

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

Cap on total rows collected across all cursor pages.

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

Apify Proxy configuration. CourtListener is a public keyless API, but Apify Proxy is attached per house rule.

## Actor input object example

```json
{
  "query": "miranda rights",
  "orderBy": "score desc",
  "maxResults": 100,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `datasetItems` (type: `string`):

All dataset items as JSON.

## `datasetItemsCsv` (type: `string`):

Same data exported to CSV.

## `datasetView` (type: `string`):

Open the run dataset in the Console.

# 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 = {
    "query": "miranda rights",
    "orderBy": "score desc",
    "maxResults": 100,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("devilscrapes/courtlistener-court-opinions-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 = {
    "query": "miranda rights",
    "orderBy": "score desc",
    "maxResults": 100,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("devilscrapes/courtlistener-court-opinions-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 '{
  "query": "miranda rights",
  "orderBy": "score desc",
  "maxResults": 100,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call devilscrapes/courtlistener-court-opinions-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,devilscrapes/courtlistener-court-opinions-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/pjzg2yyl8VeCIj3xW/builds/PXYLe2XoUae16nai3/openapi.json
