Google Scholar API: Search Papers and Citations as JSON
Google's Scholar pages don't point to a developer API, so a third-party one is the practical route. The Perceptlayer Google Scholar API gives you five GET endpoints that return JSON: search, author, author-citation, author-co-authors and cite. Each successful call costs 1 credit, and failed calls cost nothing. Send your key in the X-API-Key header and you can have a result list in one request. Only search has a recorded response, so the other four sections list parameters and leave the details to their endpoint pages.
Is there an official Google Scholar API?
Google doesn't point to one on its Scholar pages. Google's Scholar about page describes a search product and doesn't mention a developer API. That isn't proof that none exists, so check Google's own documentation before you rely on this. If you need paper search, author profiles or citation counts as structured data, you either build a parser yourself or call a service that returns the fields as JSON.
That second route is what this guide covers. The Perceptlayer endpoints return named fields, so a script can read title and inline_links.cited_by.total without touching HTML. Data is collected from publicly available sources and returned as found at the time of the call. You get no guarantee of completeness, so treat counts as a snapshot.
If you only need open metadata, other services fit better. OpenAlex, Crossref and Semantic Scholar publish documented APIs for scholarly metadata. Use Scholar-specific endpoints when you need what Google Scholar shows: its ranking, its "cited by" counts and its author profiles.
What does a Google Scholar search request look like?
One GET to /v1/google-scholar/search with a query returns a page of papers. This request asks for ten results for "machine learning", in English, published since 2020:
curl "https://api.perceptlayer.com/v1/google-scholar/search?q=machine+learning&hl=en&num=10&as_ylo=2020" \
-H "X-API-Key: $API_KEY"
If you don't have a key yet, get a free API key first. The authentication docs cover the header and the api_key query-parameter fallback for clients that can't set headers. Keys start with sk_live_.
You can also run the call without writing code. The Google Scholar API page has a playground: pick the endpoint, fill in the parameters and run a real call with your key.
Which parameters does the search endpoint take?
The search endpoint has no required parameters. Everything is optional, though a request without q or cites gives you little to look at. The table gives each parameter's type and allowed values, which is all the catalogue documents. Defaults and page sizes aren't specified.
| Parameter | Type | Notes |
|---|---|---|
q |
string | The search query, up to 500 characters |
hl |
string | Optional; the example request uses en |
start |
integer | Optional |
num |
integer | Optional |
as_ylo |
integer | Optional; the example request uses 2020 |
as_yhi |
integer | Optional |
scisbd |
integer | One of 0, 1, 2 |
cites |
string | Optional; see the cites_id note below |
cluster |
string | Optional |
The recorded request combines hl, num and as_ylo. For a loop that stops safely and doesn't double-bill, see paginating a web data API in Python. The search endpoint page lists the same parameters.
What does the search response contain?
The response wraps everything in success and data. Inside data, search_parameters echoes your inputs, search_information reports the totals, and organic_results holds the papers. Here's an excerpt of a recorded response for the request above:
{
"success": true,
"data": {
"search_parameters": {
"engine": "google_scholar",
"q": "machine learning",
"hl": "en",
"start": 0,
"num": 10,
"as_ylo": "2020",
"scisbd": 0
},
"search_information": {
"query_displayed": "machine learning",
"total_results": 38300,
"result_stats": "About 38,300 results (0.12 sec)"
},
"organic_results": [
{
"position": 1,
"title": "Machine learning",
"result_id": "WHD7vRZpYhIJ",
…
"publication_info": {
"summary": "S Marsland - Computing Handbook, 2022 - api.taylorfrancis.com",
…
}
},
{
"position": 2,
"title": "Machine learning",
"result_id": "K_YKyl3arXoJ",
…
"inline_links": {
"cited_by": {
"total": 292,
"link": "https://scholar.google.com/scholar?cites=8839961739954681387&as_sdt=2005&sciodt=0,5&hl=en",
"cites_id": "8839961739954681387"
},
…
}
}
]
}
}
The fields you'll use most are listed here. Each one appears in the recorded response above.
| Field | What it holds |
|---|---|
position |
Rank of the result in the list |
title |
The paper or chapter title |
result_id |
Scholar's identifier for the result |
link |
URL of the paper or its host page |
snippet |
The text excerpt Scholar shows under the title |
publication_info.summary |
Authors, venue, year and host in one string |
inline_links.cited_by.total |
Citation count |
inline_links.cited_by.cites_id |
Identifier for the citing set |
Not every result has every field. In the recording, the first result has no inline_links block, while the second has cited_by.total set to 292. Read optional fields with a default instead of assuming they exist.
How do you get citation counts from the response?
Read inline_links.cited_by.total on each entry in organic_results, and treat a missing block as "no count". In the recording, cited_by.total is the citation count field. This short script prints each title with its count and rank:
import os
import requests
resp = requests.get(
"https://api.perceptlayer.com/v1/google-scholar/search",
params={"q": "machine learning", "hl": "en", "num": 10, "as_ylo": 2020},
headers={"X-API-Key": os.environ["API_KEY"]},
timeout=30,
)
resp.raise_for_status()
for item in resp.json()["data"]["organic_results"]:
cited = item.get("inline_links", {}).get("cited_by", {}).get("total")
print(item["position"], item["title"], cited)
Check X-Credits-Used and X-Credits-Remaining on the response if you track spend. A successful call reports 1 for the first. A failed call reports X-Credits-Used: 0 and isn't billed.
Follow a paper's citations with cites
The cited_by.link in the recording carries a cites= query value, and the same value appears as cites_id. The search endpoint has a cites parameter, typed as a string. The catalogue doesn't describe what it does, so try passing a cites_id there on one paper and inspect the response before you build a loop around it.
What do the author, co-author, citation and cite endpoints do?
Four more endpoints cover authors, an author's citation entry and the cite lookup. We only have a recorded response for search, so this section lists their parameters, and the endpoint pages carry the details. All four take GET and cost 1 credit.
| Endpoint | Required | Optional |
|---|---|---|
/v1/google-scholar/author |
user |
hl, num, start, sort |
/v1/google-scholar/author-citation |
user, citation_id |
hl |
/v1/google-scholar/author-co-authors |
user |
hl |
/v1/google-scholar/cite |
q |
hl |
All three author endpoints require user. sort on the author endpoint accepts title or pubdate, and it also takes num and start. author-citation additionally requires a citation_id, and cite requires q. See the author, author-citation, author-co-authors and cite pages for what each returns. A request for an author's co-authors looks like this, with your own user value:
curl "https://api.perceptlayer.com/v1/google-scholar/author-co-authors?user=USER_ID&hl=en" \
-H "X-API-Key: $API_KEY"
Author profiles are personal data in the sense that they name real people. Use them for research and bibliometrics, and don't use them to contact people or build profiles without a lawful basis. Endpoints that return personal data can be restricted. If a call returns restricted_endpoint (403), accept the restricted-endpoint terms in the dashboard and retry.
How much does a Google Scholar API call cost?
Every endpoint above costs 1 credit per successful call, and a failed call costs nothing. Credits are prepaid, so when your balance reaches zero the API returns insufficient_credits (402) and nothing more is debited. There's no automatic top-up. The credits docs cover the headers, and the pricing page shows what credits cost.
| Source of credits | Credits |
|---|---|
| Free tier | 1,000 every month |
| Starter pack | 10,000 |
| Build pack | 50,000 |
| Growth pack | 200,000 |
Larger packs (Pro, Scale and Volume) also exist, up to 5,000,000 credits. The free tier needs a verified email address and no credit card. Purchased credits last 12 months, with no subscription and no seats.
A worked example: a literature scan that runs 20 search calls, one per query, makes 20 calls × 1 credit = 20 credits, well inside the free tier. At 10,000 search calls a month you'd spend 10,000 calls × 1 credit = 10,000 credits, which equals one Starter pack. For what a pack costs, see pricing.
What goes wrong, and how do you handle it?
Errors come back as an HTTP status and a JSON body shaped {"error": {"code", "message", "request_id"}}. The codes you're most likely to meet here are invalid_api_key (401), invalid_parameters (422), rate_limited (429), source_error (502) and temporarily_unavailable (503). The errors docs list all of them.
For 429 and 503, read the Retry-After header and wait that many seconds. Requests have no idempotency key, so a call whose reply was lost to a client timeout may have succeeded and been billed. Retrying web API calls without paying twice covers how to handle that, and the rate limit docs give the limits.
If you're building an agent that looks up papers on demand, the same endpoints work through the MCP server. The call_endpoint tool takes an endpoint ID and its parameters. See MCP server for web scraping or the MCP docs.
Next step: run the search call above in the playground on the Google Scholar API page, then copy the cURL into your own script.
APIs in this post
Frequently asked questions
Does Google Scholar have an official API?
Google's Scholar about page doesn't mention one, though we can't prove none exists. To get results and citation counts as JSON, you call a service that returns them as fields. The Perceptlayer Google Scholar API exposes five endpoints for this, and each successful call costs 1 credit.
How much does the Google Scholar API cost?
Each successful call to any of the five endpoints costs 1 credit, and failed calls cost nothing. The free tier gives 1,000 credits every month after you verify an email. Paid packs start at 10,000 credits (the Starter pack), so 10,000 calls × 1 credit = 10,000 credits. See pricing for what credits cost.
Is there an endpoint for authors and co-authors?
Yes, there are two, though we have no recorded response for them. The author endpoint takes a required user and optional hl, num, start and sort (title or pubdate). The author-co-authors endpoint takes user and optional hl. Each call costs 1 credit. Use them for research, and not to contact people.
How do I filter Google Scholar results by year?
Pass as_ylo for the earliest year and as_yhi for the latest on the search endpoint. Both are integers. The recorded request above used as_ylo=2020, and the response echoed it back inside search_parameters. Filtering doesn't change the price: the call still costs 1 credit.
What happens if a call fails?
You get an HTTP status and a JSON error with a code, message and request_id. Failed calls return X-Credits-Used: 0 and aren't billed. For 429 and 503, wait the number of seconds in Retry-After. If a client timeout hid the reply, the call may still have been billed.