Skip to content

Troubleshooting

When custom extraction looks wrong, the cause is usually one of five things: the rule is targeting the wrong element, the page was not ready yet, the wrong page variant was rendered, the request timed out, or the site blocked the request.
For timeouts, blocked sites, auth/plan errors, and debug headers that apply to all workflows, see common troubleshooting.

A field is empty or null

Start by tightening the rule and adding fallbacks:

The following examples show how to use the Microlink API with CLI, cURL, JavaScript, Python, Ruby, PHP & Golang, targeting 'https://example.com' URL with 'data' & 'meta' API parameters:

CLI Microlink API example

microlink https://example.com&data.title='[object Object],[object Object],[object Object]'

cURL Microlink API example

curl -G "https://api.microlink.io" \
  -d "url=https://example.com" \
  -d "data.title=%5Bobject%20Object%5D%2C%5Bobject%20Object%5D%2C%5Bobject%20Object%5D" \
  -d "meta=false"

JavaScript Microlink API example

import mql from '@microlink/mql'

const { data } = await mql('https://example.com', {
  data: {
    title: [
      {
        selector: 'meta[property="og:title"]',
        attr: "content"
      },
      {
        selector: "title",
        attr: "text"
      },
      {
        selector: "h1",
        attr: "text"
      }
    ]
  },
  meta: false
})

Python Microlink API example

import requests

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

querystring = {
    "url": "https://example.com",
    "data.title": "[object Object],[object Object],[object Object]",
    "meta": "false"
}

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",
  data.title: "[object Object],[object Object],[object Object]",
  meta: "false"
}

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

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

$params = [
    "url" => "https://example.com",
    "data.title" => "[object Object],[object Object],[object Object]",
    "meta" => "false"
];

$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("data.title", "[object Object],[object Object],[object Object]")
    q.Set("meta", "false")
    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))
}
Try the most specific selector first, then fall back to broader rules only when needed.
If the field is still empty:
  • Check whether the selector exists in the rendered DOM.
  • Remove type temporarily to see whether validation is discarding the value.
  • Confirm you are extracting the right page variant for that device, locale, or auth state.

A collection or object has the wrong shape

The most common rule-shape mistakes are:
  • Using selector when you really need selectorAll.
  • Returning a single string when you meant to build an object with nested attr rules.
  • Building a nested object too early before the individual child selectors work.
Fix the smallest piece first, then rebuild the larger structure around it.

The page is not ready yet

Dynamic pages often need a selector-based wait:

The following examples show how to use the Microlink API with CLI, cURL, JavaScript, Python, Ruby, PHP & Golang, targeting 'https://dev.to' URL with 'data', 'meta', 'waitUntil' & 'waitForSelector' API parameters:

CLI Microlink API example

microlink https://dev.to&data.title.selector='main h1'&data.title.attr=text&waitUntil=domcontentloaded&waitForSelector='main h1'

cURL Microlink API example

curl -G "https://api.microlink.io" \
  -d "url=https://dev.to" \
  -d "data.title.selector=main%20h1" \
  -d "data.title.attr=text" \
  -d "meta=false" \
  -d "waitUntil=domcontentloaded" \
  -d "waitForSelector=main%20h1"

JavaScript Microlink API example

import mql from '@microlink/mql'

const { data } = await mql('https://dev.to', {
  data: {
    title: {
      selector: "main h1",
      attr: "text"
    }
  },
  meta: false,
  waitUntil: "domcontentloaded",
  waitForSelector: "main h1"
})

Python Microlink API example

import requests

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

querystring = {
    "url": "https://dev.to",
    "data.title.selector": "main h1",
    "data.title.attr": "text",
    "meta": "false",
    "waitUntil": "domcontentloaded",
    "waitForSelector": "main h1"
}

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://dev.to",
  data.title.selector: "main h1",
  data.title.attr: "text",
  meta: "false",
  waitUntil: "domcontentloaded",
  waitForSelector: "main h1"
}

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

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

$params = [
    "url" => "https://dev.to",
    "data.title.selector" => "main h1",
    "data.title.attr" => "text",
    "meta" => "false",
    "waitUntil" => "domcontentloaded",
    "waitForSelector" => "main h1"
];

$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://dev.to")
    q.Set("data.title.selector", "main h1")
    q.Set("data.title.attr", "text")
    q.Set("meta", "false")
    q.Set("waitUntil", "domcontentloaded")
    q.Set("waitForSelector", "main h1")
    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))
}
This is usually more reliable than waiting a fixed number of seconds.
If the field still comes back empty, force browser rendering with prerender: true.

Function errors

  • EINVALFUNCTION — the function parameter has invalid JavaScript syntax.
  • EINVALEVAL — the custom extraction logic failed during evaluation.

Still stuck

Check the full error codes reference or see common troubleshooting for timeout, auth, and plan errors. If the issue is specific to authenticated targets, return to private pages.

Back to guides

See the guides overview for more Microlink guides.