DEV Community

Alex Spinov
Alex Spinov

Posted on

Unpaywall Has a Free API — Find Open Access Versions of Any Paywalled Paper

You find the perfect paper for your research. You click the link. And you hit a $40 paywall.

But what if that same paper is legally available for free somewhere else?

Unpaywall checks 50,000+ open-access sources to find free legal copies of paywalled papers. It covers 30M+ articles. And it has a free API.

How It Works

Give Unpaywall a DOI, and it tells you:

  • Is there a free legal version?
  • Where is it hosted? (university repo, preprint server, author page)
  • What type of open access? (gold, green, hybrid, bronze)

Quick Start

import requests

def find_free_version(doi, email):
    resp = requests.get(f"https://api.unpaywall.org/v2/{doi}", params={"email": email})
    data = resp.json()

    if data.get("is_oa"):
        best = data.get("best_oa_location", {})
        print(f"FREE version found!")
        print(f"  URL: {best.get('url_for_pdf') or best.get('url')}")
        print(f"  Host: {best.get('host_type')} ({best.get('repository_institution', 'N/A')})")
        print(f"  OA type: {data.get('oa_status')}")
    else:
        print(f"No free version found for {doi}")

# Example: famous AlphaFold paper
find_free_version("10.1038/s41586-021-03819-2", "your@email.com")
Enter fullscreen mode Exit fullscreen mode

Output:

FREE version found!
  URL: https://europepmc.org/articles/pmc8371605?pdf=render
  Host: repository (Europe PMC)
  OA type: green
Enter fullscreen mode Exit fullscreen mode

Batch Check Multiple Papers

dois = [
    "10.1038/s41586-021-03819-2",  # AlphaFold
    "10.1126/science.abj8754",      # Some Nature paper
    "10.1016/j.cell.2021.12.006",   # Cell paper
    "10.1145/3442188.3445922",      # ACM paper
]

for doi in dois:
    resp = requests.get(f"https://api.unpaywall.org/v2/{doi}", 
                        params={"email": "your@email.com"})
    data = resp.json()
    title = data.get("title", "Unknown")[:50]
    status = "FREE" if data.get("is_oa") else "PAYWALLED"
    oa_type = data.get("oa_status", "closed")
    print(f"[{status:>9}] ({oa_type:>7}) {title}")
Enter fullscreen mode Exit fullscreen mode

Build a Paywall Bypass Checker

def check_reading_list(dois, email):
    results = {"free": [], "paywalled": []}

    for doi in dois:
        resp = requests.get(f"https://api.unpaywall.org/v2/{doi}", 
                           params={"email": email})
        data = resp.json()
        title = data.get("title", doi)

        if data.get("is_oa"):
            best = data.get("best_oa_location", {})
            url = best.get("url_for_pdf") or best.get("url", "")
            results["free"].append({"title": title, "url": url})
        else:
            results["paywalled"].append({"title": title, "doi": doi})

    print(f"\nResults: {len(results['free'])} free, {len(results['paywalled'])} paywalled")
    print(f"\nFree papers:")
    for p in results["free"]:
        print(f"  {p['title'][:60]}")
        print(f"    {p['url']}")
    return results
Enter fullscreen mode Exit fullscreen mode

Combine with Crossref for Full Pipeline

def search_and_find_free(query, email, top=5):
    # Step 1: Search Crossref for papers
    resp = requests.get("https://api.crossref.org/works", params={
        "query": query, "rows": top, "sort": "is-referenced-by-count", "order": "desc"
    })
    papers = resp.json()["message"]["items"]

    # Step 2: Check each for free version
    for paper in papers:
        doi = paper.get("DOI")
        title = paper.get("title", ["N/A"])[0][:50]
        cites = paper.get("is-referenced-by-count", 0)

        oa = requests.get(f"https://api.unpaywall.org/v2/{doi}", 
                         params={"email": email}).json()
        free = "FREE" if oa.get("is_oa") else "PAID"
        print(f"[{free}] {title} ({cites:,} cites)")

search_and_find_free("deep learning medical imaging", "your@email.com")
Enter fullscreen mode Exit fullscreen mode

API Details

  • Endpoint: https://api.unpaywall.org/v2/{doi}?email=you@email.com
  • Rate limit: 100K requests/day
  • Auth: Just your email address (no key)
  • Coverage: 30M+ articles checked against 50K+ sources
  • Data dump: Full dataset available for download

Pro Tips

  1. Always prefer url_for_pdf over url when available
  2. Check oa_locations array for ALL free versions, not just the best one
  3. Green OA = author/repository copy, Gold = publisher open access
  4. Combine with Crossref to search by topic, then check OA status
  5. The browser extension is great for manual checking

Unpaywall + Crossref + OpenAlex = the ultimate free research stack.

Do you hit paywalls often? What is your workflow for finding free papers? Share in the comments.

More research API tools on GitHub.\n\n---\n\n## More Free Research APIs\n\nThis is part of my series on free APIs for researchers and data scientists:\n\n- OpenAlex API — 250M+ Academic Works\n- CORE API — 260M+ Scientific Papers\n- Crossref API — DOI Metadata for 150M+ Papers\n- Unpaywall API — Find Free Paper Versions\n- Europe PMC — 40M+ Biomedical Papers\n- World Bank API — GDP & Economic Data\n- ORCID API — 18M+ Researcher Profiles\n- DBLP API — 6M+ CS Publications\n- NASA APIs — 20+ Free Space Data APIs\n- FRED API — 800K+ US Economic Time Series\n- All 30+ Research APIs Mapped\n\n*Tools: Academic Research Toolkit on GitHub*

Top comments (0)