Skip to content

Browser Function
as a Service

Write a JavaScript function. Send a URL. Microlink runs the function remotely and returns whatever it returned — no Lambda, no browser fleet, no server to operate.

A function is just JavaScript. These examples run remotely and return a value.
const { value } = await microlink.function(
'https://microlink.io',
({ page }) => page.extract({
title: { selector: 'h1', attr: 'text' },
description: {
selector: 'meta[name="description"]',
attr: 'content'
}
})
)
Extract with CSS rulesExplore →
const { value } = await microlink.function(
'https://microlink.io',
({ page }) => page.evaluate(() => ({
title: document.title,
links: document.links.length,
resources: performance.getEntriesByType('resource').length
}))
)
Read the pageExplore →
const { value } = await microlink.function(
'https://news.ycombinator.com',
async ({ page }) => {
await Promise.all([
page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
page.click('a.morelink')
])
return page.$$eval('.titleline a', els =>
els.map(el => el.textContent)
)
}
)
Click, then scrapeExplore →
const { value } = await microlink.function(
'https://github.com/microlinkhq/mql',
async ({ page }) => {
await page.waitForSelector('#repo-stars-counter-star')
return page.$eval('#repo-stars-counter-star', el => el.title)
},
{ proxy: { location: 'us' } }
)
Run through a proxyExplore →
const { value } = await microlink.function(
'https://microlink.io',
({ page }) => page.evaluate(() =>
$('a[href^="/docs"]').map((i, el) => el.href).get()
),
{ scripts: 'https://code.jquery.com/jquery-3.5.0.min.js' }
)
Inject a scriptExplore →
const { value } = await microlink.function(
'https://microlink.io/blog',
async ({ page }) => {
const cheerio = require('cheerio')
const $ = cheerio.load(await page.content())
return $('article').map((i, el) => ({
title: $(el).find('h2, h3').first().text(),
href: $(el).find('a').attr('href')
})).get()
}
)
require() a packageExplore →
const { value } = await microlink.function(
'https://microlink.io',
async ({ url }) => {
// Discover sitemap URLs from this origin's robots.txt
const { href: robotsUrl } = new URL('/robots.txt', url)
const res = await fetch(robotsUrl)
const body = res.ok ? await res.text() : ''
const robotsParser = require('robots-parser')
const sitemaps = robotsParser(robotsUrl, body).getSitemaps()
// Walk nested sitemap indexes. `fetcher` is how each document is loaded.
return require('xml-urls')(sitemaps, { fetcher: fetch })
}
)
List sitemap URLsExplore →

Send a function
Get the result

You write a normal JavaScript function. Microlink serializes it, runs it in a sandbox, and sends back the return value. A browser starts only if the function uses page.

  • Write a function

    Any JavaScript. Return a number, a string, an array, or an object. No Lambda bundle and no special format — the same function you would run locally.
  • Send it with a URL

    The function runs against that page. Mention page and Microlink starts a headless browser and gives you the full Puppeteer page object. Skip page and no browser starts.
  • Read the return value

    value is what the function returned. isFulfilled is false if it threw, and value then holds the error. profiling.phases shows install, build, spawn, and run.

How a function runs

Start with a function that returns a value. Add a browser, a click, or a package only when you need them.

Your first function

Pass a JavaScript function and a target URL. The function runs remotely. The return value is at value — the same way a local function returns.

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

CLI Microlink API example

microlink https://example.com&function='({ page }) => page.title()'

cURL Microlink API example

curl -G "https://api.microlink.io" \
  -d "url=https://example.com" \
  -d "function=(%7B%20page%20%7D)%20%3D%3E%20page.title()"

JavaScript Microlink API example

import createClient from 'microlink.io'

const microlink = createClient()

const { value } = await microlink.function(
  'https://example.com',
  ({ page }) => page.title()
)

Python Microlink API example

import requests

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

querystring = {
    "url": "https://example.com",
    "function": "({ page }) => page.title()"
}

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",
  function: "({ page }) => page.title()"
}

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",
    "function" => "({ page }) => page.title()"
];

$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("function", "({ page }) => page.title()")
    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))
}

Skip the browser when you can

When the function does not mention page, no Chrome starts. That is faster and cheaper. Extra parameters on the request are forwarded to the function, so one function can be reused.

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

CLI Microlink API example

microlink https://example.com&function='() => 40 + 2'

cURL Microlink API example

curl -G "https://api.microlink.io" \
  -d "url=https://example.com" \
  -d "function=()%20%3D%3E%2040%20%2B%202"

JavaScript Microlink API example

import createClient from 'microlink.io'

const microlink = createClient()

const { value } = await microlink.function('https://example.com', () => 40 + 2)

Python Microlink API example

import requests

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

querystring = {
    "url": "https://example.com",
    "function": "() => 40 + 2"
}

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",
  function: "() => 40 + 2"
}

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",
    "function" => "() => 40 + 2"
];

$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("function", "() => 40 + 2")
    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))
}

Read the result

A throw does not fail the HTTP request. isFulfilled tells you if the function finished. value is the return, or the error. profiling.phases shows where time went.

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

CLI Microlink API example

microlink https://example.com&function='() => { throw new Error("boom") }'

cURL Microlink API example

curl -G "https://api.microlink.io" \
  -d "url=https://example.com" \
  -d "function=()%20%3D%3E%20%7B%20throw%20new%20Error(%22boom%22)%20%7D"

JavaScript Microlink API example

import createClient from 'microlink.io'

const microlink = createClient()

const { value } = await microlink.function(
  'https://example.com',
  () => { throw new Error("boom") }
)

Python Microlink API example

import requests

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

querystring = {
    "url": "https://example.com",
    "function": '''() => { throw new Error("boom") }'''
}

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",
  function: '() => { throw new Error("boom") }'
}

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",
    "function" => '() => { throw new Error("boom") }'
];

$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)
    }
    fn := `() => { throw new Error("boom") }`

    q := u.Query()
    q.Set("url", "https://example.com")
    q.Set("function", fn)
    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))
}

Prefer extract() first

If a CSS selector is enough, do not write a function. data is shorter, cheaper, and easier to reuse. Reach for Function when the first HTML is not the data.

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

CLI Microlink API example

microlink https://microlink.io&data.title.selector=title&data.description.selector='meta[name="description"]'&data.description.attr=content

cURL Microlink API example

curl -G "https://api.microlink.io" \
  -d "url=https://microlink.io" \
  -d "data.title.selector=title" \
  -d "data.description.selector=meta[name="description"]" \
  -d "data.description.attr=content"

JavaScript Microlink API example

import createClient from 'microlink.io'

const microlink = createClient()

const { title, description } = await microlink.extract('https://microlink.io', {
  title: {
    selector: "title"
  },
  description: {
    selector: 'meta[name="description"]',
    attr: "content"
  }
})

Python Microlink API example

import requests

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

querystring = {
    "url": "https://microlink.io",
    "data.title.selector": "title",
    "data.description.selector": '''meta[name="description"]''',
    "data.description.attr": "content"
}

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://microlink.io",
  data.title.selector: "title",
  data.description.selector: 'meta[name="description"]',
  data.description.attr: "content"
}

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://microlink.io",
    "data.title.selector" => "title",
    "data.description.selector" => 'meta[name="description"]',
    "data.description.attr" => "content"
];

$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)
    }
    data.description.selectorParam := `meta[name="description"]`

    q := u.Query()
    q.Set("url", "https://microlink.io")
    q.Set("data.title.selector", "title")
    q.Set("data.description.selector", data.description.selectorParam)
    q.Set("data.description.attr", "content")
    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))
}

page is a remote Chrome

Name page and Microlink navigates first, then hands you the Puppeteer page object. title, $eval, $$eval, click, wait — the same API you use locally.

The following examples show how to use the Microlink API with CLI, cURL, JavaScript, Python, Ruby, PHP & Golang, targeting 'https://microlink.io' URL with 'function' API parameter:

CLI Microlink API example

microlink https://microlink.io&function='({ page }) => page.evaluate(() => ({
  title: document.title,
  links: document.links.length,
  resources: performance.getEntriesByType('"'"'resource'"'"').length
}))'

cURL Microlink API example

curl -G "https://api.microlink.io" \
  -d "url=https://microlink.io" \
  -d "function=(%7B%20page%20%7D)%20%3D%3E%20page.evaluate(()%20%3D%3E%20(%7B%0A%20%20title%3A%20document.title%2C%0A%20%20links%3A%20document.links.length%2C%0A%20%20resources%3A%20performance.getEntriesByType('resource').length%0A%7D))"

JavaScript Microlink API example

import createClient from 'microlink.io'

const microlink = createClient()

const { value } = await microlink.function(
  'https://microlink.io',
  ({ page }) => page.evaluate(() => ({
    title: document.title,
    links: document.links.length,
    resources: performance.getEntriesByType('resource').length
  }))
)

Python Microlink API example

import requests

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

querystring = {
    "url": "https://microlink.io",
    "function": '''({ page }) => page.evaluate(() => ({
  title: document.title,
  links: document.links.length,
  resources: performance.getEntriesByType('resource').length
}))'''
}

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://microlink.io",
  function: "({ page }) => page.evaluate(() => ({
  title: document.title,
  links: document.links.length,
  resources: performance.getEntriesByType('resource').length
}))"
}

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://microlink.io",
    "function" => "({ page }) => page.evaluate(() => ({
  title: document.title,
  links: document.links.length,
  resources: performance.getEntriesByType('resource').length
}))"
];

$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)
    }
    fn := `({ page }) => page.evaluate(() => ({
  title: document.title,
  links: document.links.length,
  resources: performance.getEntriesByType('resource').length
}))`

    q := u.Query()
    q.Set("url", "https://microlink.io")
    q.Set("function", fn)
    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))
}

Click, wait, then scrape

Pagination, “Load more”, and client-rendered lists are missing from the first HTML. Click, wait for the new nodes, then return the text or hrefs.

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 'function' API parameter:

CLI Microlink API example

microlink https://news.ycombinator.com&function='async ({ page }) => {
  await page.click('"'"'a.morelink'"'"')
  await page.waitForSelector('"'"'.athing'"'"')
  return page.$$eval('"'"'.titleline a'"'"', els =>
    els.map(el => el.textContent)
  )
}'

cURL Microlink API example

curl -G "https://api.microlink.io" \
  -d "url=https://news.ycombinator.com" \
  -d "function=async%20(%7B%20page%20%7D)%20%3D%3E%20%7B%0A%20%20await%20page.click('a.morelink')%0A%20%20await%20page.waitForSelector('.athing')%0A%20%20return%20page.%24%24eval('.titleline%20a'%2C%20els%20%3D%3E%0A%20%20%20%20els.map(el%20%3D%3E%20el.textContent)%0A%20%20)%0A%7D"

JavaScript Microlink API example

import createClient from 'microlink.io'

const microlink = createClient()

const { value } = await microlink.function(
  'https://news.ycombinator.com',
  async ({ page }) => {
    await page.click('a.morelink')
    await page.waitForSelector('.athing')
    return page.$$eval('.titleline a', els =>
      els.map(el => el.textContent)
    )
  }
)

Python Microlink API example

import requests

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

querystring = {
    "url": "https://news.ycombinator.com",
    "function": '''async ({ page }) => {
  await page.click('a.morelink')
  await page.waitForSelector('.athing')
  return page.$$eval('.titleline a', els =>
    els.map(el => el.textContent)
  )
}'''
}

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",
  function: "async ({ page }) => {
  await page.click('a.morelink')
  await page.waitForSelector('.athing')
  return page.$$eval('.titleline a', els =>
    els.map(el => el.textContent)
  )
}"
}

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",
    "function" => "async ({ page }) => {
  await page.click('a.morelink')
  await page.waitForSelector('.athing')
  return page.$$eval('.titleline a', els =>
    els.map(el => el.textContent)
  )
}"
];

$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)
    }
    fn := `async ({ page }) => {
  await page.click('a.morelink')
  await page.waitForSelector('.athing')
  return page.$$eval('.titleline a', els =>
    els.map(el => el.textContent)
  )
}`

    q := u.Query()
    q.Set("url", "https://news.ycombinator.com")
    q.Set("function", fn)
    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))
}

require() a package

Need cheerio or lodash? require it. The runtime detects the import, installs it in the sandbox, and caches it. No Lambda zip. Pin a version with require('[email protected]').

The following examples show how to use the Microlink API with CLI, cURL, JavaScript, Python, Ruby, PHP & Golang, targeting 'https://microlink.io/blog' URL with 'function' API parameter:

CLI Microlink API example

microlink https://microlink.io/blog&function='async ({ page }) => {
  const cheerio = require('"'"'cheerio'"'"')
  const $ = cheerio.load(await page.content())
  return $('"'"'article'"'"').map((i, el) => ({
    title: $(el).find('"'"'h2, h3'"'"').first().text(),
    href: $(el).find('"'"'a'"'"').attr('"'"'href'"'"')
  })).get()
}'

cURL Microlink API example

curl -G "https://api.microlink.io" \
  -d "url=https://microlink.io/blog" \
  -d "function=async%20(%7B%20page%20%7D)%20%3D%3E%20%7B%0A%20%20const%20cheerio%20%3D%20require('cheerio')%0A%20%20const%20%24%20%3D%20cheerio.load(await%20page.content())%0A%20%20return%20%24('article').map((i%2C%20el)%20%3D%3E%20(%7B%0A%20%20%20%20title%3A%20%24(el).find('h2%2C%20h3').first().text()%2C%0A%20%20%20%20href%3A%20%24(el).find('a').attr('href')%0A%20%20%7D)).get()%0A%7D"

JavaScript Microlink API example

import createClient from 'microlink.io'

const microlink = createClient()

const { value } = await microlink.function(
  'https://microlink.io/blog',
  async ({ page }) => {
    const cheerio = require('cheerio')
    const $ = cheerio.load(await page.content())
    return $('article').map((i, el) => ({
      title: $(el).find('h2, h3').first().text(),
      href: $(el).find('a').attr('href')
    })).get()
  }
)

Python Microlink API example

import requests

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

querystring = {
    "url": "https://microlink.io/blog",
    "function": '''async ({ page }) => {
  const cheerio = require('cheerio')
  const $ = cheerio.load(await page.content())
  return $('article').map((i, el) => ({
    title: $(el).find('h2, h3').first().text(),
    href: $(el).find('a').attr('href')
  })).get()
}'''
}

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://microlink.io/blog",
  function: "async ({ page }) => {
  const cheerio = require('cheerio')
  const $ = cheerio.load(await page.content())
  return $('article').map((i, el) => ({
    title: $(el).find('h2, h3').first().text(),
    href: $(el).find('a').attr('href')
  })).get()
}"
}

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://microlink.io/blog",
    "function" => "async ({ page }) => {
  const cheerio = require('cheerio')
  const $ = cheerio.load(await page.content())
  return $('article').map((i, el) => ({
    title: $(el).find('h2, h3').first().text(),
    href: $(el).find('a').attr('href')
  })).get()
}"
];

$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)
    }
    fn := `async ({ page }) => {
  const cheerio = require('cheerio')
  const $ = cheerio.load(await page.content())
  return $('article').map((i, el) => ({
    title: $(el).find('h2, h3').first().text(),
    href: $(el).find('a').attr('href')
  })).get()
}`

    q := u.Query()
    q.Set("url", "https://microlink.io/blog")
    q.Set("function", fn)
    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))
}

Inject a script

Function is another Microlink parameter, so you can prepare the page first. Pass scripts and the helper lands before the function runs.

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

CLI Microlink API example

microlink https://microlink.io&function='({ page }) => page.evaluate(() =>
  $('"'"'a[href^="/docs"]'"'"').map((i, el) => el.href).get()
)'&scripts=https://code.jquery.com/jquery-3.5.0.min.js

cURL Microlink API example

curl -G "https://api.microlink.io" \
  -d "url=https://microlink.io" \
  -d "function=(%7B%20page%20%7D)%20%3D%3E%20page.evaluate(()%20%3D%3E%0A%20%20%24('a%5Bhref%5E%3D%22%2Fdocs%22%5D').map((i%2C%20el)%20%3D%3E%20el.href).get()%0A)" \
  -d "scripts=https://code.jquery.com/jquery-3.5.0.min.js"

JavaScript Microlink API example

import createClient from 'microlink.io'

const microlink = createClient()

const { value } = await microlink.function(
  'https://microlink.io',
  ({ page }) => page.evaluate(() =>
    $('a[href^="/docs"]').map((i, el) => el.href).get()
  ),
  {
    scripts: "https://code.jquery.com/jquery-3.5.0.min.js"
  }
)

Python Microlink API example

import requests

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

querystring = {
    "url": "https://microlink.io",
    "function": '''({ page }) => page.evaluate(() =>
  $('a[href^="/docs"]').map((i, el) => el.href).get()
)''',
    "scripts": "https://code.jquery.com/jquery-3.5.0.min.js"
}

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://microlink.io",
  function: "({ page }) => page.evaluate(() =>
  $('a[href^=\"/docs\"]').map((i, el) => el.href).get()
)",
  scripts: "https://code.jquery.com/jquery-3.5.0.min.js"
}

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://microlink.io",
    "function" => "({ page }) => page.evaluate(() =>
  $('a[href^=\"/docs\"]').map((i, el) => el.href).get()
)",
    "scripts" => "https://code.jquery.com/jquery-3.5.0.min.js"
];

$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)
    }
    fn := `({ page }) => page.evaluate(() =>
  $('a[href^="/docs"]').map((i, el) => el.href).get()
)`

    q := u.Query()
    q.Set("url", "https://microlink.io")
    q.Set("function", fn)
    q.Set("scripts", "https://code.jquery.com/jquery-3.5.0.min.js")
    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))
}

Route through a proxy

Datacenter IPs get blocked. Pin a country with proxy.location and the function runs after a residential navigation. Same value, harder target.

The following examples show how to use the Microlink API with CLI, cURL, JavaScript, Python, Ruby, PHP & Golang, targeting 'https://github.com/microlinkhq/mql' URL with 'function' & 'proxy' API parameters:

CLI Microlink API example

microlink https://github.com/microlinkhq/mql&function='async ({ page }) => {
  await page.waitForSelector('"'"'#repo-stars-counter-star'"'"')
  return page.$eval('"'"'#repo-stars-counter-star'"'"', el => el.title)
}'&proxy.location=us

cURL Microlink API example

curl -G "https://api.microlink.io" \
  -d "url=https://github.com/microlinkhq/mql" \
  -d "function=async%20(%7B%20page%20%7D)%20%3D%3E%20%7B%0A%20%20await%20page.waitForSelector('%23repo-stars-counter-star')%0A%20%20return%20page.%24eval('%23repo-stars-counter-star'%2C%20el%20%3D%3E%20el.title)%0A%7D" \
  -d "proxy.location=us"

JavaScript Microlink API example

import createClient from 'microlink.io'

const microlink = createClient()

const { value } = await microlink.function(
  'https://github.com/microlinkhq/mql',
  async ({ page }) => {
    await page.waitForSelector('#repo-stars-counter-star')
    return page.$eval('#repo-stars-counter-star', el => el.title)
  },
  {
    proxy: {
      location: "us"
    }
  }
)

Python Microlink API example

import requests

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

querystring = {
    "url": "https://github.com/microlinkhq/mql",
    "function": '''async ({ page }) => {
  await page.waitForSelector('#repo-stars-counter-star')
  return page.$eval('#repo-stars-counter-star', el => el.title)
}''',
    "proxy.location": "us"
}

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://github.com/microlinkhq/mql",
  function: "async ({ page }) => {
  await page.waitForSelector('#repo-stars-counter-star')
  return page.$eval('#repo-stars-counter-star', el => el.title)
}",
  proxy.location: "us"
}

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://github.com/microlinkhq/mql",
    "function" => "async ({ page }) => {
  await page.waitForSelector('#repo-stars-counter-star')
  return page.$eval('#repo-stars-counter-star', el => el.title)
}",
    "proxy.location" => "us"
];

$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)
    }
    fn := `async ({ page }) => {
  await page.waitForSelector('#repo-stars-counter-star')
  return page.$eval('#repo-stars-counter-star', el => el.title)
}`

    q := u.Query()
    q.Set("url", "https://github.com/microlinkhq/mql")
    q.Set("function", fn)
    q.Set("proxy.location", "us")
    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))
}

Cache the result

Set ttl and a repeat of the same URL and function is served from the edge. The sandbox does not run again. Cache hits are free.

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

CLI Microlink API example

microlink https://example.com&function='({ page }) => page.$eval('"'"'h1'"'"', el => el.textContent)'&ttl=1h

cURL Microlink API example

curl -G "https://api.microlink.io" \
  -d "url=https://example.com" \
  -d "function=(%7B%20page%20%7D)%20%3D%3E%20page.%24eval('h1'%2C%20el%20%3D%3E%20el.textContent)" \
  -d "ttl=1h"

JavaScript Microlink API example

import createClient from 'microlink.io'

const microlink = createClient()

const { value } = await microlink.function(
  'https://example.com',
  ({ page }) => page.$eval('h1', el => el.textContent),
  {
    ttl: "1h"
  }
)

Python Microlink API example

import requests

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

querystring = {
    "url": "https://example.com",
    "function": '''({ page }) => page.$eval('h1', el => el.textContent)''',
    "ttl": "1h"
}

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",
  function: "({ page }) => page.$eval('h1', el => el.textContent)",
  ttl: "1h"
}

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",
    "function" => "({ page }) => page.$eval('h1', el => el.textContent)",
    "ttl" => "1h"
];

$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)
    }
    fn := `({ page }) => page.$eval('h1', el => el.textContent)`

    q := u.Query()
    q.Set("url", "https://example.com")
    q.Set("function", fn)
    q.Set("ttl", "1h")
    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 free, scale when ready

No signup, no API key, no credit card. Write a function and send it — 25 requests/day on the free plan.

Pro

For production workloads.
$49/month
≈ $1.07 per 1,000 requests
46,000 requests / month
Cancel anytime · No setup fees

Business & Enterprise

Bought the way companies buy.
Enterprise adds

What you can add

A function and a URL are enough to start. These are the options you can add on the same request.
  • Microlink Function

    Send a function and a URL. Read the return value.
  • Browser on demand

    Chrome starts only when the function uses page.
  • require() anything

    require() installs on the fly. No zip, no install step.
  • Click and paginate

    Click, wait, then return the new nodes.
  • Inject scripts

    scripts lands in the page before the function runs.
  • Residential proxy

    proxy.location pins a country for blocked targets.
  • TTL cache

    ttl serves the same call from cache. Hits are free.
  • Compression

    gzip, brotli, or zstd on the wire.
  • Errors as values

    A throw still resolves. Read isFulfilled and value.
  • Profiling

    profiling.phases breaks down install, build, spawn, run.
  • Scope

    Extra arguments become scope on the remote function.
  • TypeScript

    Types ship with the SDK. No extra package.
  • CLI and HTTP

    The same function from the SDK, CLI, or a GET.
  • API token

    Free is 25 requests/day. Pro raises the daily cap.
  • Edge cache

    A warm cache skips the sandbox on the next call.

Browser code, in practice.

Puppeteer without hosting Chrome, npm packages on any URL and Load more buttons. Each use case shows the function to run and the limits to plan for.

Puppeteer without hosting Chrome

Send a Puppeteer function with a URL and get its return value back. The browser, the sandbox and the cleanup run on Microlink.

JavaScript with npm packages

Require any npm package inside a remote function, pin its version, and skip the browser entirely when the code does not need one.

Pagination and Load more buttons

Scrape numbered pages in parallel, one call per page, or click Load more inside a function until the list is complete.

Start now

Write a function in the browser. 25 requests/day, no account, no card.
No login needed
25 reqs/day free
No credit card

Product Information

The questions that come up the first time you send a function.

A way to run your JavaScript remotely. You send a function and a URL. Microlink executes the function in a sandbox — and starts a headless browser only if the function uses page — then returns the value. No Lambda bundle, no browser fleet, no server.

When does the function start a browser?

Only when your code references page. Without it, Microlink skips the headless browser entirely, so plain compute runs faster and cheaper. Reference page to get the full Puppeteer API for clicks, waits, and evaluation.

When should I use Function instead of extract()?

Start with extract() — declarative CSS-selector rules are shorter and easier to maintain.
Escalate to Function when you need to click, wait, compute, or orchestrate custom logic that rules cannot express.

Can I require() npm packages?

Yes. Any require() call is detected, installed on the fly into the sandbox, and cached for later runs. Pin a version with require('[email protected]'). Operations such as spawning child processes or writing outside the sandbox are not permitted.

What happens if my function throws?

The promise still resolves: result.isFulfilled comes back false and result.value carries the error as { name, message } so you handle failures in your own code.

Is Function available on the free plan?

Yes. Free runs get a 5-second timeout, 64 MB of memory, 1024 bytes of code, and one concurrent execution per IP. Pro plans extend the timeout up to 60 seconds, raise memory to 128 MB, and remove code-size and concurrency limits.

Does every call execute the function again?

Only on a cache miss. Set a ttl and any repeat request for the same URL and function inside that window is served from the edge cache instantly, at no cost and without running the sandbox again.