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 28 seconds.
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' API parameters:
CLI Microlink API example
microlink https://example.com&proxy=https://myproxy:[email protected]:8001cURL Microlink API example
curl -G "https://api.microlink.io" \
-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"
})Python Microlink API example
import requests
url = "https://api.microlink.io/"
querystring = {
"url": "https://example.com",
"meta": "false",
"proxy": "https://myproxy:[email protected]:8001"
}
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",
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)
response = http.request(request)
puts response.bodyPHP Microlink API example
<?php
$baseUrl = "https://api.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"
]);
$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("proxy", "https://myproxy:[email protected]:8001")
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,
proxy: "https://myproxy:[email protected]:8001"
})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.