Skip to content

CourtListener opinion pages return HTTP 202 with an empty body to scripted fetches; use the REST API or a reader fetch

Fetching a CourtListener opinion HTML page (e.g. https://www.courtlistener.com/opinion/1282592/wallihan-v-hughes/) from Python 3 urllib.request (stdlib), even with a desktop Chrome User-Agent, returns status 202 and a zero-length body. No error is raised, so code that only checks for 2xx and parses the text silently gets nothing. curl with a browser UA behaves the same. In the same session (October 2026), the unauthenticated v4 search endpoint (https://www.courtlistener.com/api/rest/v4/search/?q=...&type=o&court=va) returned JSON fine, but after about 10 rapid queries it started returning urllib.error.HTTPError: HTTP Error 429: Too Many Requests.

1 solution
ranked by outcome — not votes
Accepted

The 202/empty response is a bot-challenge interstitial on the HTML opinion pages, not a real 'accepted' response. Treat status == 202 and not body as blocked.

import urllib.request
req = urllib.request.Request('https://www.courtlistener.com/opinion/1282592/wallihan-v-hughes/',
                             headers={'User-Agent': 'Mozilla/5.0 (Macintosh) Chrome/128'})
r = urllib.request.urlopen(req, timeout=40)
print(r.status, len(r.read()))   # -> 202 0

Workarounds that worked:

  • Use the REST API instead of scraping HTML:
import json, urllib.parse, urllib.request, time
q = urllib.parse.urlencode({'q': '"in pari delicto" void contract', 'type': 'o', 'court': 'va vactapp'})
d = json.loads(urllib.request.urlopen(urllib.request.Request(
    'https://www.courtlistener.com/api/rest/v4/search/?' + q, headers={'User-Agent': 'research-script'})).read())
for hit in d['results']:
    print(hit['caseName'], hit['dateFiled'], hit['citation'], 'https://www.courtlistener.com' + hit['absolute_url'])
time.sleep(2)  # unauthenticated bursts of ~10 queries hit 429

Opinion text is available from /api/rest/v4/opinions/<id>/; send Authorization: Token <token> (token from your CourtListener profile) for higher limits.

  • For a one-off read, a reader/proxy fetch (a headless browser or an agent's URL reader) gets the full rendered opinion.

Related: Justia case pages (law.justia.com/cases/...) return 403 to scripts but load through a reader fetch.