domainnotallowed
The credentials are valid, but the request uses a domain that is not on the allowlist that applies to them. The API refuses the request before any browser starts. Nothing about timing will change that, so the same request fails until the allowlist or the request changes. This page is part of the error code reference.
| HTTP status | 403 Forbidden |
error.type |
authorization_error |
error.retryable |
false |
| Credits used | 0 |
Example response
{ "error": { "type": "authorization_error", "code": "domain_not_allowed", "message": "Domain 'blocked.example' is not in the allowlist", "retryable": false, "docs": "https://docs.renderscreenshot.com/errors/domain_not_allowed" }, "request_id": "req_abc123" }
Why an allowlist exists
An allowlist limits what a set of credentials can capture. It matters most for credentials that can be seen by other people, such as publishable keys and signed URLs in public HTML. If someone copies such a URL and changes the target, the allowlist stops your account from rendering their pages on your credits.
Common causes
- A hostname variant.
www.example.com,example.com,blog.example.comand a staging host are different hostnames. Check which form you sent and which form is on the list. - User-supplied URLs. Your product passes a URL that a user typed, and it points to a site you never meant to support.
- The wrong key or environment. A key meant for one site is used by another project, for example after copying a
.envfile. - A copied or edited public URL. Someone changed the
urlparameter of a public URL that uses your credentials.
How to fix it
- Read the hostname in
error.messageand theurlyou sent. Log both with therequest_id. - If the domain is yours and should work, add it to the allowlist for those credentials, or use the credentials that belong to that site.
- If the domain is not one you support, the error is correct. Reject the URL in your own app before you call the API, with a message the user can act on.
- Never retry. Mark the job as failed for good, so a queue does not send it again every few minutes.
If you are sure the domain is on the list and the error continues, contact [email protected] with the request_id.
Handle it as a permanent failure
This Python function turns the error into its own exception type, so a job runner can skip the item instead of re-queuing it:
# domain_check.py (Python 3.10+, requests) import os import sys from urllib.parse import urlsplit import requests API = os.environ.get("RS_BASE_URL", "https://api.renderscreenshot.com") HEADERS = {"Authorization": f"Bearer {os.environ['RS_API_KEY']}"} class DomainNotAllowed(Exception): """Permanent failure: do not retry, do not requeue.""" def capture(url: str) -> bytes: res = requests.post(f"{API}/v1/screenshot", json={"url": url}, headers=HEADERS, timeout=(10, 90)) if res.ok: return res.content payload = res.json() if "json" in res.headers.get("Content-Type", "") else {} error = payload.get("error", {}) if error.get("code") == "domain_not_allowed": host = urlsplit(url).hostname raise DomainNotAllowed(f"{host}: {error.get('message')} (request {payload.get('request_id')})") res.raise_for_status() raise RuntimeError(f"unexpected status {res.status_code}") if __name__ == "__main__": try: image = capture(sys.argv[1]) except DomainNotAllowed as e: print(f"skipped, will not retry: {e}", file=sys.stderr) sys.exit(2) with open("shot.png", "wb") as f: f.write(image) print("saved shot.png")
With the Ruby SDK, the error arrives as RenderScreenshot::AuthorizationError. That class also covers insufficient_credits and feature_not_available, so check e.code:
require 'renderscreenshot' client = RenderScreenshot.client(ENV.fetch('RS_API_KEY')) begin client.take(RenderScreenshot::TakeOptions.url('https://blocked.example/pricing')) rescue RenderScreenshot::AuthorizationError => e raise unless e.code == 'domain_not_allowed' # Permanent for this URL: record it and move on. Do not requeue. warn "not allowed: #{e.message} (#{e.request_id})" end
Tested on 2026-10-15 with Python 3.14 plus requests 2.34.2, and with Ruby 4.0.7 plus the renderscreenshot gem 1.0.0, against a local mock that returns the envelope above. The blocked URL exited with code 2 and no retry; an allowed URL saved the image.
Related
- Publishable keys for
rs_pub_andrs_secret_keys in public pages. - Security best practices for handling user-supplied URLs.
- featurenotavailable, the other 403 that a request change can fix.