Skip to content

Page preparation

Metadata extraction is only as good as the page Microlink sees. On static sites, the default behavior is usually enough. On dynamic or hydration-heavy sites, you may need to control how the page is fetched and when extraction happens.

Choose fetch mode first

The biggest rendering decision is prerender:

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

CLI Microlink API example

microlink https://vercel.com&meta.title&meta.description

cURL Microlink API example

curl -G "https://api.microlink.io" \
  -d "url=https://vercel.com" \
  -d "meta.title=true" \
  -d "meta.description=true" \
  -d "prerender=false"

JavaScript Microlink API example

import mql from '@microlink/mql'

const { data } = await mql('https://vercel.com', {
  meta: {
    title: true,
    description: true
  },
  prerender: false
})

Python Microlink API example

import requests

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

querystring = {
    "url": "https://vercel.com",
    "meta.title": "true",
    "meta.description": "true",
    "prerender": "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://vercel.com",
  meta.title: "true",
  meta.description: "true",
  prerender: "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://vercel.com",
    "meta.title" => "true",
    "meta.description" => "true",
    "prerender" => "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://vercel.com")
    q.Set("meta.title", "true")
    q.Set("meta.description", "true")
    q.Set("prerender", "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))
}
Use prerender: false when the metadata is already present in the initial HTML and you do not need a browser render.
If the pageUse
Is static HTML or simple server-rendered markupprerender: false
Might need a browser, but you are not sureprerender: 'auto' (default)
Is client-rendered and comes back incomplete without browser executionprerender: true
prerender is often the difference between getting real metadata and getting a generic shell.

Wait for dynamic pages to settle

If the page needs browser rendering, you can control when Microlink considers it ready:

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

CLI Microlink API example

microlink https://dev.to&meta.title&meta.description&waitUntil=domcontentloaded&waitForSelector=main

cURL Microlink API example

curl -G "https://api.microlink.io" \
  -d "url=https://dev.to" \
  -d "meta.title=true" \
  -d "meta.description=true" \
  -d "waitUntil=domcontentloaded" \
  -d "waitForSelector=main"

JavaScript Microlink API example

import mql from '@microlink/mql'

const { data } = await mql('https://dev.to', {
  meta: {
    title: true,
    description: true
  },
  waitUntil: "domcontentloaded",
  waitForSelector: "main"
})

Python Microlink API example

import requests

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

querystring = {
    "url": "https://dev.to",
    "meta.title": "true",
    "meta.description": "true",
    "waitUntil": "domcontentloaded",
    "waitForSelector": "main"
}

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",
  meta.title: "true",
  meta.description: "true",
  waitUntil: "domcontentloaded",
  waitForSelector: "main"
}

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",
    "meta.title" => "true",
    "meta.description" => "true",
    "waitUntil" => "domcontentloaded",
    "waitForSelector" => "main"
];

$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("meta.title", "true")
    q.Set("meta.description", "true")
    q.Set("waitUntil", "domcontentloaded")
    q.Set("waitForSelector", "main")
    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))
}
Start with a fast lifecycle event, then wait for a stable selector that signals the page is really ready.
Use the wait controls in this order:
NeedBest option
A good default navigation signalwaitUntil: 'auto'
Faster navigation before a selector waitwaitUntil: 'domcontentloaded'
A stable signal that the page has renderedwaitForSelector
A last-resort fixed waitwaitForTimeout
You can also pass an array to waitUntil when one event alone is not enough.

Disable JavaScript when it is not helping

If the site already exposes the metadata you need in the HTML, JavaScript can be unnecessary:

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

CLI Microlink API example

microlink https://news.ycombinator.com&meta.title&meta.description

cURL Microlink API example

curl -G "https://api.microlink.io" \
  -d "url=https://news.ycombinator.com" \
  -d "meta.title=true" \
  -d "meta.description=true" \
  -d "javascript=false"

JavaScript Microlink API example

import mql from '@microlink/mql'

const { data } = await mql('https://news.ycombinator.com', {
  meta: {
    title: true,
    description: true
  },
  javascript: false
})

Python Microlink API example

import requests

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

querystring = {
    "url": "https://news.ycombinator.com",
    "meta.title": "true",
    "meta.description": "true",
    "javascript": "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://news.ycombinator.com",
  meta.title: "true",
  meta.description: "true",
  javascript: "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://news.ycombinator.com",
    "meta.title" => "true",
    "meta.description" => "true",
    "javascript" => "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://news.ycombinator.com")
    q.Set("meta.title", "true")
    q.Set("meta.description", "true")
    q.Set("javascript", "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))
}
Disabling JavaScript can reduce rendering work when the target site already exposes the right metadata in the initial document.
This is most useful for static sites, classic server-rendered pages, and pages where JavaScript adds noise rather than value.

Use fixed waits sparingly

If there is no stable selector to wait for, use waitForTimeout as a last resort:

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

CLI Microlink API example

microlink https://dev.to&meta.title&meta.description&waitForTimeout=3s

cURL Microlink API example

curl -G "https://api.microlink.io" \
  -d "url=https://dev.to" \
  -d "meta.title=true" \
  -d "meta.description=true" \
  -d "waitForTimeout=3s"

JavaScript Microlink API example

import mql from '@microlink/mql'

const { data } = await mql('https://dev.to', {
  meta: {
    title: true,
    description: true
  },
  waitForTimeout: "3s"
})

Python Microlink API example

import requests

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

querystring = {
    "url": "https://dev.to",
    "meta.title": "true",
    "meta.description": "true",
    "waitForTimeout": "3s"
}

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",
  meta.title: "true",
  meta.description: "true",
  waitForTimeout: "3s"
}

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",
    "meta.title" => "true",
    "meta.description" => "true",
    "waitForTimeout" => "3s"
];

$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("meta.title", "true")
    q.Set("meta.description", "true")
    q.Set("waitForTimeout", "3s")
    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))
}
Fixed waits work, but selector-based waits are usually faster and more reliable.
If you still cannot get the right result, continue with troubleshooting.

Next step

Learn how to keep metadata requests fast and fresh in caching and performance.