Common patterns: Troubleshooting
These troubleshooting patterns apply to every Microlink workflow. Each guide's own troubleshooting page covers workflow-specific issues (wrong screenshots, bad PDF layout, empty extraction fields, etc.); this page covers the problems that appear across all workflows.
The request times out
If you hit
ETIMEOUT or EBRWSRTIMEOUT, reduce the amount of work before raising timeout:- Replace
waitForTimeoutwithwaitForSelector— selector-based waits finish as soon as content appears. - Set
meta: falsewhen you do not need normalized metadata. - Use
prerender: falsewhen the page already ships the content in HTML. - Disable
javascriptwhen the page does not need client-side execution. - Remove unnecessary
scripts,modules, orfunctionwork. - Only then raise
timeoutand increaseretry:
The following examples show how to use the Microlink API with CLI, cURL, JavaScript, Python, Ruby, PHP & Golang, targeting 'https://example.com' URL with 'meta', 'retry' & 'timeout' API parameters:
CLI Microlink API example
microlink https://example.com&retry=3&timeout=20scURL Microlink API example
curl -G "https://api.microlink.io" \
-d "url=https://example.com" \
-d "meta=false" \
-d "retry=3" \
-d "timeout=20s"JavaScript Microlink API example
import mql from '@microlink/mql'
const { data } = await mql('https://example.com', {
meta: false,
retry: 3,
timeout: "20s"
})Python Microlink API example
import requests
url = "https://api.microlink.io/"
querystring = {
"url": "https://example.com",
"meta": "false",
"retry": "3",
"timeout": "20s"
}
response = requests.get(url, params=querystring)
print(response.json())Ruby Microlink API example
require 'uri'
require 'net/http'
base_url = "https://api.microlink.io/"
params = {
url: "https://example.com",
meta: "false",
retry: "3",
timeout: "20s"
}
uri = URI(base_url)
uri.query = URI.encode_www_form(params)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri)
response = http.request(request)
puts response.bodyPHP Microlink API example
<?php
$baseUrl = "https://api.microlink.io/";
$params = [
"url" => "https://example.com",
"meta" => "false",
"retry" => "3",
"timeout" => "20s"
];
$query = http_build_query($params);
$url = $baseUrl . '?' . $query;
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET"
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #: " . $err;
} else {
echo $response;
}Golang Microlink API example
package main
import (
"fmt"
"net/http"
"net/url"
"io"
)
func main() {
baseURL := "https://api.microlink.io"
u, err := url.Parse(baseURL)
if err != nil {
panic(err)
}
q := u.Query()
q.Set("url", "https://example.com")
q.Set("meta", "false")
q.Set("retry", "3")
q.Set("timeout", "20s")
u.RawQuery = q.Encode()
req, err := http.NewRequest("GET", u.String(), nil)
if err != nil {
panic(err)
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
panic(err)
}
fmt.Println(string(body))
}import mql from '@microlink/mql'
const { data } = await mql('https://example.com', {
meta: false,
retry: 3,
timeout: "20s"
})Increase timeout only after removing unnecessary work. The maximum allowed timeout is 30 seconds on the free plan and 60 seconds on pro.
The site blocks the browser PRO
Some sites block headless browsers, require a region-specific IP, or trigger antibot protection. In those cases, use
proxy:The following examples show how to use the Microlink API with CLI, cURL, JavaScript, Python, Ruby, PHP & Golang, targeting 'https://example.com' URL with 'meta', 'proxy' & 'apiKey' API parameters:
CLI Microlink API example
microlink https://example.com&proxy=https://myproxy:[email protected]:8001 --api-key YOUR_API_TOKENcURL Microlink API example
curl -G "https://pro.microlink.io" \
-H "x-api-key: YOUR_API_TOKEN" \
-d "url=https://example.com" \
-d "meta=false" \
-d "proxy=https://myproxy:[email protected]:8001"JavaScript Microlink API example
import mql from '@microlink/mql'
const { data } = await mql('https://example.com', {
meta: false,
proxy: "https://myproxy:[email protected]:8001",
apiKey: "YOUR_API_TOKEN"
})Python Microlink API example
import requests
url = "https://pro.microlink.io/"
querystring = {
"url": "https://example.com",
"meta": "false",
"proxy": "https://myproxy:[email protected]:8001"
}
headers = {
"x-api-key": "YOUR_API_TOKEN"
}
response = requests.get(url, params=querystring, headers=headers)
print(response.json())Ruby Microlink API example
require 'uri'
require 'net/http'
base_url = "https://pro.microlink.io/"
params = {
url: "https://example.com",
meta: "false",
proxy: "https://myproxy:[email protected]:8001"
}
uri = URI(base_url)
uri.query = URI.encode_www_form(params)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri)
request['x-api-key'] = "YOUR_API_TOKEN"
response = http.request(request)
puts response.bodyPHP Microlink API example
<?php
$baseUrl = "https://pro.microlink.io/";
$params = [
"url" => "https://example.com",
"meta" => "false",
"proxy" => "https://myproxy:[email protected]:8001"
];
$query = http_build_query($params);
$url = $baseUrl . '?' . $query;
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"x-api-key: YOUR_API_TOKEN"
]
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #: " . $err;
} else {
echo $response;
}Golang Microlink API example
package main
import (
"fmt"
"net/http"
"net/url"
"io"
)
func main() {
baseURL := "https://pro.microlink.io"
u, err := url.Parse(baseURL)
if err != nil {
panic(err)
}
q := u.Query()
q.Set("url", "https://example.com")
q.Set("meta", "false")
q.Set("proxy", "https://myproxy:[email protected]:8001")
u.RawQuery = q.Encode()
req, err := http.NewRequest("GET", u.String(), nil)
if err != nil {
panic(err)
}
req.Header.Set("x-api-key", "YOUR_API_TOKEN")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
panic(err)
}
fmt.Println(string(body))
}import mql from '@microlink/mql'
const { data } = await mql('https://example.com', {
meta: false,
proxy: "https://myproxy:[email protected]:8001",
apiKey: "YOUR_API_TOKEN"
})Use a proxy URL when the target site blocks headless traffic, geofences content, or rate-limits your origin.
If the API returns
EPROXYNEEDED, that is the clearest signal that the target needs a proxy-backed request.Auth and plan errors
These errors point directly to setup issues and apply to all workflows:
| Error code | Cause | Fix |
|---|---|---|
EAUTH | API key missing or invalid | Check your x-api-key header |
EPRO | Sent x-api-key to api.microlink.io | Use pro.microlink.io instead |
EHEADERS | headers used without Pro plan | Upgrade to a PRO plan |
EPROXY | proxy used without Pro plan | Upgrade to a PRO plan |
EFILENAME | filename used without Pro plan | Upgrade to a PRO plan |
ETTL | ttl used without Pro plan | Upgrade to a PRO plan |
ESTTL | staleTtl used without Pro plan | Upgrade to a PRO plan |
ERATE | Rate limit reached | Wait for reset or upgrade |
EINVALURL | URL format is invalid | Check protocol and hostname |
EFORBIDDENURL | URL resolves to a forbidden IP | Use a public URL |
EMAXREDIRECTS | More than 10 redirects | Provide the final destination URL |
See the full error codes reference for every error.
Useful headers while debugging
Open the response headers view in the interactive editor and look for:
| Header | What it tells you |
|---|---|
x-cache-status | MISS (fresh), HIT (cached), or BYPASS (forced) |
x-cache-ttl | Effective cache lifetime in milliseconds |
x-fetch-mode | fetch, prerender, proxy-*, or skipped |
x-fetch-time | Time spent fetching and rendering |
x-pricing-plan | Whether the request ran on free or pro |
x-response-time | Total request duration |
These headers usually tell you whether the problem is timing, auth, caching, or target-site protection.