How to Fix Microlink Screenshot API Timeout Errors
Find out whether your client, Microlink, or the target page caused a screenshot timeout, then choose a wait strategy and fix the underlying error.
Start by identifying which layer ended the request. Your HTTP client can time out before Microlink finishes; Microlink’s browser work can reach its plan’s request limit; or the target page can be slow, blocked, or waiting on content that never appears. Record the elapsed time, HTTP status, Microlink JSON status and error code, and response headers before changing settings.
Microlink’s documentation gives a 30-second request timeout for the free endpoint and 60 seconds for Pro. Your own HTTP client needs a timeout long enough to receive a response within the applicable limit. Raising a client timeout cannot extend Microlink’s limit, and adding a browser wait cannot make a blocked page accessible.
1. Identify which timeout occurred
Make one request and capture its response details. Microlink responses include a status such as success, fail, or error; failed responses include an error code and message. If your client throws a socket or request timeout without receiving an HTTP response, the client may have stopped waiting first. If Microlink returns an error response, inspect its code and description to determine what happened in the browser request.
| What you observe | Likely area to investigate | Next step |
|---|---|---|
| Your client throws a timeout and has no HTTP response | Caller-side deadline or network connection | Set the client timeout to cover the expected API duration, up to the applicable Microlink request limit; log the exception and elapsed time. |
Microlink returns an error with EBRWSRTIMEOUT or ETIMEOUT |
Browser work did not finish within the request budget | Check the page’s readiness condition, remove unnecessary work, and use only a timeout supported by your plan. |
HTTP 429 and ERATE |
Quota exhausted | Check rate-limit headers and wait for the reset or use an appropriate plan and key. |
EPROXYNEEDED |
Target blocked requests from the free endpoint’s datacenter IP | Treat this as an access restriction, not a wait problem. Microlink documents proxy capability on Pro. |
| Request succeeds but the screenshot is blank, partial, or still loading | The page state was captured too early, or its content did not load | Inspect the returned screenshot and wait for a selector that proves the required content is ready. |
For SDK users, Microlink documents error details such as status, code, statusCode, description, URL, and headers on MicrolinkError. Log the fields your client exposes, along with the target URL and a request identifier if available. Do not log API secrets or sensitive query parameters.
2. Set the caller timeout and Microlink request budget
Microlink documents a maximum request timeout of 30 seconds for its free endpoint and 60 seconds for Pro. Configure the caller’s HTTP timeout so it does not give up first. The cURL client timeout shown in Microlink’s docs is an example, not a universal caller limit. The request timeout and the client timeout are separate settings.
For example, if you use cURL, its --max-time controls how long cURL waits for the HTTP operation. Choose a value that fits your plan’s Microlink limit and your application’s own deadline:
curl --max-time 60 'https://api.microlink.io/?url=https%3A%2F%2Fapp.example.com%2Freport&screenshot=true&meta=false&waitUntil=domcontentloaded&waitForSelector=.chart%20svg'
This is an illustrative request, not a guarantee that the example page or selector exists. Use a client timeout appropriate to your plan; if your application has a stricter overall deadline, account for that separately.
3. Wait for the page state you actually need
A screenshot can be too early even when navigation has completed. On a client-rendered page, wait for a stable element that appears only after the needed data is rendered. Microlink supports waitUntil lifecycle values including auto, load, domcontentloaded, networkidle0, and networkidle2, plus waitForSelector, waitForTimeout, scrolling, and clicking.
For example, if the report is ready when its chart SVG exists, request that condition:
curl 'https://api.microlink.io/?url=https%3A%2F%2Fapp.example.com%2Freport&screenshot=true&meta=false&waitUntil=domcontentloaded&waitForSelector=.chart%20svg'
Choose the condition based on how the target works:
- Static or server-rendered page: use an appropriate navigation milestone. If the required content is already in the returned HTML, consider disabling JavaScript as described below.
- Client-rendered page: wait for a selector that indicates the relevant content has appeared, rather than assuming the navigation event means the app is ready.
- Content behind an interaction: click the relevant control or scroll to the lazy section, then wait for the resulting content selector.
- Page with persistent or long-polling requests: avoid relying on network idle. Open connections can prevent network silence even after the screenshot content is ready.
- No usable readiness signal: use a fixed delay as a fallback, sized to the observed rendering delay and within the overall request budget.
Microlink’s guide says, “Waiting for a condition is both faster and more reliable than waiting for a duration.” That is vendor guidance: a selector can let a fast page proceed promptly while still waiting for the content on slower runs.
A fixed waitForTimeout is not a way to exceed the endpoint’s request limit. Microlink says the wait must fit within the plan’s request timeout, and a wait larger than the timeout is ignored. For element screenshots, the documented screenshot.element option already waits for its selector to be visible, so an additional selector wait may be unnecessary.
4. Reduce work that the screenshot does not need
For screenshot-only requests, set meta=false to skip metadata extraction. Microlink describes this as its biggest speed improvement when metadata is not needed. This reduces avoidable work; it does not fix a blocked target or content that never renders.
- Disable JavaScript only when safe:
javascript=falsecan help when the page is complete without scripts. Do not use it for an app whose screenshot depends on client-side rendering. - Capture fewer pixels if acceptable: reduce the device scale factor or choose a smaller capture where the desired image permits it. Lower pixel count trades image detail for less output work.
- Choose output format deliberately: JPEG can reduce output size when transparency is not required. JPEG quality applies to JPEG, not PNG.
- Capture only what is needed: a viewport or selected element can avoid unnecessary full-page capture work when the use case does not require the whole page.
Check the response’s screenshot data, including its URL, dimensions, type, and size, then inspect the image itself. A successful API response alone does not prove the desired page state was captured.
5. Separate quota and access errors from timeouts
Microlink’s API overview documents 25 requests per day on the free plan. It provides x-rate-limit-limit, x-rate-limit-remaining, and x-rate-limit-reset headers. When the limit is reached, the API returns HTTP 429 with ERATE. Check the reset time or use an appropriate key and plan; retrying immediately or increasing a wait does not restore quota.
The free endpoint can return EPROXYNEEDED when the target is behind antibot protection. Microlink documents proxy capability for Pro, including automatic residential proxy use for recognized antibot or CAPTCHA blocking. That is an access issue, not evidence that the browser simply needs more time.
Microlink says Pro tokens should be sent in the x-api-key header to pro.microlink.io. Keep the token on your server; do not expose it in frontend code.
6. Choose the right wait strategy
| Strategy | Good fit | Watch for |
|---|---|---|
waitForSelector |
A stable element signals that the content you need has rendered. | The selector must match the page and become visible; a selector that never appears can consume the request budget. |
domcontentloaded or another lifecycle event |
You need a navigation milestone before checking or capturing content. | A navigation milestone does not necessarily mean a client-rendered app has finished loading its data. |
networkidle0 or networkidle2 |
The page settles its requests and network silence is a meaningful readiness signal. | Persistent connections and long polling can keep the page from becoming idle. |
waitForTimeout |
No reliable page signal is available and you have measured a reasonable delay. | It waits even on fast runs and must fit within the endpoint’s total request budget. |
| Scroll or click, then wait for a selector | The desired content is lazy-loaded or hidden behind an interaction. | Wait for the resulting content, not merely for the action to complete. |
Use the narrowest condition that proves the screenshot is ready. The right choice depends on whether the page is static or client-rendered, whether it keeps background requests open, and whether you need the viewport, a full page, or an element.
7. Troubleshooting checklist
- Record the target URL, elapsed time, caller exception, HTTP status, JSON status, error code, message, and response headers.
- Determine whether the caller ended the request without a response or Microlink returned an error.
- Check for
ERATEand rate-limit headers before retrying. - Check for
EPROXYNEEDEDif the target uses antibot protection or a CAPTCHA. - For dynamic content, replace a guessed long delay or network-idle wait with a selector tied to the required content.
- Confirm the selector is present and visible in the target page, and include any required click or scroll action.
- Set the caller timeout to cover the plan’s documented request duration, without exceeding your application’s own deadline.
- Remove unneeded metadata, scripts, pixels, or page area only when doing so preserves the desired screenshot.
- Inspect the returned screenshot and its dimensions, type, and size; distinguish an API success from a correct visual result.
Common errors and fixes
| Error or symptom | Cause to investigate | Fix |
|---|---|---|
| Caller timeout with no response | The HTTP library’s deadline is shorter than the API operation. | Increase the client timeout within the request and application limits; capture the exception and elapsed time. |
EBRWSRTIMEOUT or ETIMEOUT |
Browser navigation, rendering, or configured wait did not finish in time. | Use a more precise readiness condition, remove unneeded work, and keep waits within the plan’s cap. |
| Blank screenshot or loading spinner | The page was captured before the relevant client-rendered content appeared. | Wait for a stable content selector; interact or scroll first if the content requires it. |
| Network-idle wait never finishes | The page holds open a long-polling or other persistent request. | Wait for the content selector instead of network silence. |
HTTP 429 with ERATE |
Free-plan daily quota is exhausted. | Use the reset header to determine when to retry, or use an appropriate plan and key. |
EPROXYNEEDED |
Target access is blocked from the free endpoint. | Check the target’s access requirements and the documented Pro proxy option; a longer wait does not remove the block. |
| Wait setting appears ineffective | The fixed wait is larger than the request timeout or consumes most of the available budget. | Keep the wait within the plan limit and prefer a content-based condition. |
| Screenshot returned but expected field or image is missing | The response may be a failure payload, or the screenshot data may describe an unexpected capture. | Check JSON status, error code, screenshot URL and metadata, then inspect the captured image. |
8. Consider a different tool when the job changes
A hosted screenshot API is not a universal fit. Microlink says its service is not the right choice for crawling thousands of pages by following links, driving a live interactive browser session, or retrieving static HTML that needs no rendering. Its overview points to a crawler, local Puppeteer or Playwright, or a plain HTTP client for those distinct jobs. Choose based on the work required; the dossier does not establish that one option is universally faster.
For one-call screenshots with cleanup of consent banners, popups, and chat widgets, ScreenshotNeo is an alternative to try first. It is a website screenshot API and MCP server for developers. The same API parameter names other screenshot APIs use also work, which can make switching easier.
Or skip the browser setup
Send one GET request to capture a page. The examples below use Stripe as the target; replace it with the URL you need. See the ScreenshotNeo API documentation for request options.
cURL
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
Node.js
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`ScreenshotNeo returned HTTP ${res.status}`);
const image = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', image));
ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before the shot; each cleanup step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are never billed, and the response reports page verdict and billing status in headers. Its MCP server gives AI agents tools for screenshots, page information, and PDF capture. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Every feature is on every plan.
Sign up free for 1,000 screenshots a month, with no card required.
Performance, reliability, and cost notes
- Performance: A selector wait avoids spending the same fixed delay on every request. Skipping metadata and reducing capture pixels can reduce work when those outputs are unnecessary, but neither fixes a target that blocks the request.
- Reliability: Classify failures by response and error code. Retrying a quota error before reset, a blocked target, or a selector that never appears is unlikely to address the cause. For transient caller-side connection problems, capture enough context to distinguish them from browser errors before deciding whether to retry.
- Cost: Microlink documents 25 free-plan requests per day and a 30-second free-endpoint request timeout; Pro has a 60-second timeout and proxy capability. Check the current plan terms for your account before relying on a limit. For ScreenshotNeo, the supplied pricing is 1,000 free shots monthly, then Starter at $5 for 3,000, Growth $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000, and Business $249 for 1,000,000; yearly billing gives two months free.
FAQ
How do I increase the Microlink screenshot timeout?
First distinguish the HTTP client timeout from Microlink’s request limit. Configure the client to wait long enough, then use only a Microlink timeout supported by your plan: the dossier documents 30 seconds for the free endpoint and 60 seconds for Pro.
Why is my screenshot blank even though the API returned?
The API can return before a client-rendered page has displayed the content you expect. Wait for a selector that proves the content is present, then inspect the actual screenshot rather than relying only on a success status.
Should I always use networkidle0?
No. It can be unsuitable for sites with long polling or persistent requests. Use it only when network silence is a useful signal for the page; otherwise wait for the specific content element.
Does a longer fixed wait solve a blocked target?
No. Errors such as EPROXYNEEDED indicate an access restriction in the documented scenario. Diagnose access and plan capability separately from render timing.
Can I turn off JavaScript to make screenshots faster?
Only if the target’s needed content is complete without scripts. A client-rendered application may produce an empty or incomplete screenshot with JavaScript disabled.


