## Table of Contents

- [Troubleshooting](#troubleshooting)
- [The request times out](#the-request-times-out)
  - [CLI Microlink API example](#cli-microlink-api-example)
  - [cURL Microlink API example](#curl-microlink-api-example)
  - [JavaScript Microlink API example](#javascript-microlink-api-example)
  - [Python Microlink API example](#python-microlink-api-example)
  - [Ruby Microlink API example](#ruby-microlink-api-example)
  - [PHP Microlink API example](#php-microlink-api-example)
  - [Golang Microlink API example](#golang-microlink-api-example)
- [The site blocks the browser PRO](#the-site-blocks-the-browser-pro)
  - [CLI Microlink API example](#cli-microlink-api-example-1)
  - [cURL Microlink API example](#curl-microlink-api-example-1)
  - [JavaScript Microlink API example](#javascript-microlink-api-example-1)
  - [Python Microlink API example](#python-microlink-api-example-1)
  - [Ruby Microlink API example](#ruby-microlink-api-example-1)
  - [PHP Microlink API example](#php-microlink-api-example-1)
  - [Golang Microlink API example](#golang-microlink-api-example-1)
- [Useful headers while debugging](#useful-headers-while-debugging)

---

[](https://microlink.io/docs/api/getting-started/overview)

[API](https://microlink.io/docs/api/getting-started/overview)

[](https://microlink.io/docs/guides)

GUIDES

[](https://microlink.io/docs/mql/getting-started/overview)

MQL

[](https://microlink.io/docs/sdk/getting-started/overview)

SDK

[](https://microlink.io/docs/cards/getting-started/overview)

CARDS

## 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`:

1.  **Replace `waitForTimeout` with `waitForSelector`** — selector-based waits finish as soon as content appears.
2.  **Set `meta: false`** when you do not need normalized metadata.
3.  **Use `prerender: false`** when the page already ships the content in HTML.
4.  **Disable `javascript`** when the page does not need client-side execution.
5.  **Remove unnecessary `scripts`, `modules`, or `function` work**.
6.  **Only then raise `timeout`** and increase `retry`:

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

``` bash
microlink https://example.com&retry=3&timeout=20s
```

### cURL Microlink API example

``` bash
curl -G "https://api.microlink.io" \
  -d "url=https://example.com" \
  -d "meta=false" \
  -d "retry=3" \
  -d "timeout=20s"
```

### JavaScript Microlink API example

``` javascript
import mql from '@microlink/mql'

const { data } = await mql('https://example.com', {
  meta: false,
  retry: 3,
  timeout: "20s"
})
```

### Python Microlink API example

``` python
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

``` ruby
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.body
```

### PHP Microlink API example

``` php
<?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

``` bash
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))
}
```

``` javascript
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

``` bash
microlink https://example.com&proxy=https://myproxy:603f60f5@superproxy.cool:8001
```

### cURL Microlink API example

``` bash
curl -G "https://api.microlink.io" \
  -d "url=https://example.com" \
  -d "meta=false" \
  -d "proxy=https://myproxy:603f60f5@superproxy.cool:8001"
```

### JavaScript Microlink API example

``` javascript
import mql from '@microlink/mql'

const { data } = await mql('https://example.com', {
  meta: false,
  proxy: "https://myproxy:603f60f5@superproxy.cool:8001"
})
```

### Python Microlink API example

``` python
import requests

url = "https://api.microlink.io/"

querystring = {
    "url": "https://example.com",
    "meta": "false",
    "proxy": "https://myproxy:603f60f5@superproxy.cool:8001"
}

response = requests.get(url, params=querystring)

print(response.json())
```

### Ruby Microlink API example

``` ruby
require 'uri'
require 'net/http'

base_url = "https://api.microlink.io/"

params = {
  url: "https://example.com",
  meta: "false",
  proxy: "https://myproxy:603f60f5@superproxy.cool: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.body
```

### PHP Microlink API example

``` php
<?php

$baseUrl = "https://api.microlink.io/";

$params = [
    "url" => "https://example.com",
    "meta" => "false",
    "proxy" => "https://myproxy:603f60f5@superproxy.cool: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

``` bash
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:603f60f5@superproxy.cool: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))
}
```

``` javascript
import mql from '@microlink/mql'

const { data } = await mql('https://example.com', {

  meta: false,

  proxy: "https://myproxy:603f60f5@superproxy.cool: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.

These errors point directly to setup issues and apply to all workflows:

<table>
<colgroup>
<col style="width: 33%" />
<col style="width: 33%" />
<col style="width: 33%" />
</colgroup>
<thead>
<tr>
<th>Error code</th>
<th>Cause</th>
<th>Fix</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>EAUTH</code></td>
<td>API key missing or invalid</td>
<td>Check your <code>x-api-key</code> header</td>
</tr>
<tr>
<td><code>EPRO</code></td>
<td>Sent <code>x-api-key</code> to <code>api.microlink.io</code></td>
<td>Use <code>pro.microlink.io</code> instead</td>
</tr>
<tr>
<td><code>EHEADERS</code></td>
<td><code>headers</code> used without Pro plan</td>
<td>Upgrade to a
<p>PRO</p>
plan</td>
</tr>
<tr>
<td><code>EPROXY</code></td>
<td><code>proxy</code> used without Pro plan</td>
<td>Upgrade to a
<p>PRO</p>
plan</td>
</tr>
<tr>
<td><code>EFILENAME</code></td>
<td><code>filename</code> used without Pro plan</td>
<td>Upgrade to a
<p>PRO</p>
plan</td>
</tr>
<tr>
<td><code>ETTL</code></td>
<td><code>ttl</code> used without Pro plan</td>
<td>Upgrade to a
<p>PRO</p>
plan</td>
</tr>
<tr>
<td><code>ESTTL</code></td>
<td><code>staleTtl</code> used without Pro plan</td>
<td>Upgrade to a
<p>PRO</p>
plan</td>
</tr>
<tr>
<td><code>ERATE</code></td>
<td>Rate limit reached</td>
<td>Wait for reset or upgrade</td>
</tr>
<tr>
<td><code>EINVALURL</code></td>
<td>URL format is invalid</td>
<td>Check protocol and hostname</td>
</tr>
<tr>
<td><code>EFORBIDDENURL</code></td>
<td>URL resolves to a forbidden IP</td>
<td>Use a public URL</td>
</tr>
<tr>
<td><code>EMAXREDIRECTS</code></td>
<td>More than 10 redirects</td>
<td>Provide the final destination URL</td>
</tr>
</tbody>
</table>

See the full [error codes reference](https://microlink.io/docs/api/basics/error-codes) 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.