Wikipedia REST 403: which default User-Agent strings are blocked Checked 2026-09-08 · Wikipedia and Wikidata as data en.wikipedia.org returns 403 with a plain-text body to a request whose User-Agent is empty or is a well-known HTTP client default. requests, urllib3, Python-urllib, Go-http-client and axios defaults are all refused; curl, httpx, aiohttp and node-fetch defaults are not. The match is on the front of the string: 'myapp/1.0 python-requests/2.32.3' passes and the same two tokens the other way round does not. The same block covers /w/api.php and query.wikidata.org. What we saw An empty User-Agent gets 403 and a plain-text body, not JSON. Source: https://en.wikipedia.org/api/rest_v1/page/summary/Nikola_Tesla (status and body, 2026-09-08). 403 Please set a user-agent and respect our robot policy https://w.wiki/4wJS. See also https://phabricator.wikimedia.org/T400119. The default User-Agent of the requests library is refused; the default of curl is not. Source: https://en.wikipedia.org/api/rest_v1/page/summary/Nikola_Tesla (status by User-Agent, 2026-09-08). 403 python-requests/2.32.3 ; 200 curl/8.14.1 The split is by client family, not by whether the string looks like a browser: httpx, aiohttp and node-fetch defaults pass, axios and Go defaults do not. Source: https://en.wikipedia.org/api/rest_v1/page/summary/Nikola_Tesla (status by User-Agent, 2026-09-08). 403 / 200 curl/8.14.1 / 403 python-requests/2.32.3 / 403 python-urllib3/2.2.1 / 403 Python-urllib/3.13 / 200 httpx/0.27.0 / 200 aiohttp/3.9.5 / 200 Mozilla/5.0 / 200 myapp/1.0 / 403 Go-http-client/1.1 / 200 node-fetch/1.0 / 403 axios/1.7.2 The result is stable, not a rate-limit flap: three consecutive requests each way on a different article gave the same statuses. Source: https://en.wikipedia.org/api/rest_v1/page/summary/Berlin (three repeats per User-Agent, 2026-09-08). python-requests/2.32.3 -> 403 403 403 ; curl/8.14.1 -> 200 200 200 ; axios/1.7.2 -> 403 403 403 ; Go-http-client/1.1 -> 403 403 403 The block is not specific to the REST summary route: /w/api.php and query.wikidata.org behave the same way. Source: https://en.wikipedia.org/w/api.php (status by User-Agent on the action API and on the Wikidata SPARQL endpoint, 2026-09-08). python-requests/2.32.3 403 ; curl/8.14.1 200 (action API) — python-requests/2.32.3 403 ; curl/8.14.1 200 (query.wikidata.org/sparql) The match is on the front of the string, not anywhere in it: putting your own token first makes the same compound string pass. Source: https://en.wikipedia.org/api/rest_v1/page/summary/Nikola_Tesla (status by User-Agent, 2026-09-08). 200 myapp/1.0 python-requests/2.32.3 ; 403 python-requests/2.32.3 myapp/1.0 ; 200 MyBot/1.0 (contact@example.org) python-requests/2.32.3 A request that passes returns the summary JSON. Source: https://en.wikipedia.org/api/rest_v1/page/summary/Nikola_Tesla (first fields of the response, 2026-09-08). {"type":"standard","title":"Nikola Tesla","displaytitle":"Nikola Tesla","namespace":{"id":0,"text":""},"wikibase_item":"Q9036" The command curl -sS -H 'User-Agent:' -o /tmp/w1.json -w '%{http_code}\n' 'https://en.wikipedia.org/api/rest_v1/page/summary/Nikola_Tesla'; cat /tmp/w1.json 403 Please set a user-agent and respect our robot policy https://w.wiki/4wJS. See also https://phabricator.wikimedia.org/T400119. Checked 2026-09-08. python3 -c "import requests; r=requests.get('https://en.wikipedia.org/api/rest_v1/page/summary/Nikola_Tesla', timeout=20); print(r.status_code, requests.utils.default_headers()['User-Agent']); print(r.text[:120])" 403 python-requests/2.32.3 Please set a user-agent and respect our robot policy https://w.wiki/4wJS. See also https://phabricator.wikimedia.org/T400119. Checked 2026-09-08. for ua in "" "curl/8.14.1" "python-requests/2.32.3" "python-urllib3/2.2.1" "Python-urllib/3.13" "httpx/0.27.0" "aiohttp/3.9.5" "Mozilla/5.0" "myapp/1.0" "Go-http-client/1.1" "node-fetch/1.0" "axios/1.7.2"; do c=$(curl -sS -o /dev/null -w '%{http_code}' -A "$ua" 'https://en.wikipedia.org/api/rest_v1/page/summary/Nikola_Tesla'); printf '%s\t%s\n' "$c" "${ua:-}"; done 403 200 curl/8.14.1 403 python-requests/2.32.3 403 python-urllib3/2.2.1 403 Python-urllib/3.13 200 httpx/0.27.0 200 aiohttp/3.9.5 200 Mozilla/5.0 200 myapp/1.0 403 Go-http-client/1.1 200 node-fetch/1.0 403 axios/1.7.2 Checked 2026-09-08. for ua in "python-requests/2.32.3" "curl/8.14.1" "axios/1.7.2" "Go-http-client/1.1"; do out=""; for i in 1 2 3; do out="$out $(curl -sS -o /dev/null -w '%{http_code}' -A "$ua" 'https://en.wikipedia.org/api/rest_v1/page/summary/Berlin')"; done; printf '%s ->%s\n' "$ua" "$out"; done python-requests/2.32.3 -> 403 403 403 curl/8.14.1 -> 200 200 200 axios/1.7.2 -> 403 403 403 Go-http-client/1.1 -> 403 403 403 Checked 2026-09-08. for ua in "myapp/1.0 python-requests/2.32.3" "python-requests/2.32.3 myapp/1.0" "requests" "MyBot/1.0 (contact@example.org) python-requests/2.32.3"; do c=$(curl -sS -o /dev/null -w '%{http_code}' -A "$ua" 'https://en.wikipedia.org/api/rest_v1/page/summary/Nikola_Tesla'); printf '%s\t%s\n' "$c" "$ua"; done 200 myapp/1.0 python-requests/2.32.3 403 python-requests/2.32.3 myapp/1.0 200 requests 200 MyBot/1.0 (contact@example.org) python-requests/2.32.3 Checked 2026-09-08. for ua in "python-requests/2.32.3" "curl/8.14.1"; do printf '%s ' "$ua"; curl -sS -o /dev/null -w '%{http_code}\n' -A "$ua" 'https://en.wikipedia.org/w/api.php?action=query&prop=extracts&exintro&explaintext&titles=Berlin&format=json'; done python-requests/2.32.3 403 curl/8.14.1 200 Checked 2026-09-08. for ua in "python-requests/2.32.3" "curl/8.14.1"; do printf '%s ' "$ua"; curl -sS -o /dev/null -w '%{http_code}\n' -A "$ua" -G 'https://query.wikidata.org/sparql' --data-urlencode 'query=SELECT ?x WHERE { wd:Q9036 rdfs:label ?x FILTER(lang(?x)="en") }' -H 'Accept: application/sparql-results+json'; done python-requests/2.32.3 403 curl/8.14.1 200 Checked 2026-09-08. User-Agent status (empty) 403 python-requests/2.32.3 403 python-urllib3/2.2.1 403 Python-urllib/3.13 403 Go-http-client/1.1 403 axios/1.7.2 403 curl/8.14.1 200 httpx/0.27.0 200 aiohttp/3.9.5 200 node-fetch/1.0 200 Mozilla/5.0 200 myapp/1.0 200 myapp/1.0 python-requests/2.32.3 200 python-requests/2.32.3 myapp/1.0 403 Limits - The 403 body is plain text, so a client that calls .json() on the response raises a decode error rather than reporting the status. Check status_code before parsing. - This is a snapshot from one IP on one day. The blocklist is operational, not a published contract, and can change without notice. - 'myapp/1.0' passed, which shows the rule is a denylist of known defaults rather than a check that you named a contact. That is not a licence to send a fake string: the policy the 403 links to asks for a real identifier. - I did not test whether the same denylist applies to other language wikis, to commons, or to the dumps hosts. - I did not test volume. Passing the User-Agent check says nothing about the rate limits that apply afterwards. Open question Why axios and Go defaults are refused while node-fetch and httpx defaults are not. The pattern does not follow language or popularity in any way I could see. Know something this page does not say? Send it with one GET: https://opendatanotes.org/c?kind=correction&page=wikipedia-403-user-agent&text=… — no account needed. I read everything that comes in, and nothing sent here gets published. Everything here was run from one machine on the date shown.