The Microlink API organized into products, each returning a direct result.
Turning a page into markdown, taking a screenshot, or getting every link on a page shouldn't require hand-writing query parameters. This package organizes the Microlink API into products — from Node or the CLI:
import createClient from 'microlink.io'
const microlink = createClient()
const markdown = await microlink.markdown('https://example.com')
console.log(markdown) // → the page content as a Markdown stringnpx microlink markdown https://example.comnpm install microlink.ioThat also installs the microlink binary. Use it via npx, or install globally with npm install -g microlink.io. See CLI for every product as a subcommand.
The export is a single factory. Call it once to get a client; the optional argument carries apiKey and any other client-wide defaults:
import createClient from 'microlink.io'
const microlink = createClient() // free client
const microlinkPro = createClient({ apiKey: process.env.MICROLINK_API_KEY }) // pro clientWhatever you pass to the factory is merged into every call, and per-call options can override it.
Every product method takes a single options object: product(url, options). The library routes each key to the right destination automatically:
headerstravels as real HTTP request headers (never in the URL). The API forwards anyx-api-header-<name>header to the target fetch as<name>— the right way to pass secrets like cookies.- Well-known capability keys nest under the product (for example
fullPageforscreenshot,formatforpdf,selectorformarkdown). - Everything else goes as a top-level API query parameter (
device,waitUntil,prerender,ttl,proxy, ...).
await microlink.screenshot('https://example.com', {
fullPage: true, // nests under `screenshot`
device: 'iPhone 11' // top-level query param
})Every microlink.io product maps to a client method:
| Product | Method |
|---|---|
| Link preview / Metadata | metadata(url) |
| Markdown / HTML / Text | markdown(url) / html(url) / text(url) |
| Screenshot | screenshot(url) |
| Animated Screenshot | screenshot(url, { animated: true }) |
pdf(url) |
|
| Logo | logo(url) |
| Embed | embed(url) |
| Video / Audio | video(url) / audio(url) |
| Lighthouse | lighthouse(url) |
| Technologies | technologies(url) |
| Search | search(query) |
| Function | run(url, code) (alias function) |
Plus library extras: links / images / videos / audios / emails collections and extract for custom data rules.
The unified metadata object (title, description, image, publisher, ...):
const { title, description } = await microlink.metadata('https://vercel.com')
console.log(title, description)The page content as Markdown, HTML or plain text. Use selector to scope it:
const markdown = await microlink.markdown('https://example.com', { selector: 'article' })
console.log(markdown)Takes a screenshot and returns the asset object (url, type, width, height, size, ...):
const { url } = await microlink.screenshot('https://example.com', { fullPage: true })
console.log(url)Generates a PDF and returns the asset object:
const { url } = await microlink.pdf('https://example.com', { format: 'A4' })
console.log(url)The brand logo of the site. Pass square: true to prefer the square variant:
const { url } = await microlink.logo('https://github.com', { square: true })
console.log(url)The oEmbed-style embeddable iframe ({ html, scripts }), e.g. for a YouTube video or a Tweet. Constrain with maxWidth/maxHeight:
const { html } = await microlink.embed('https://www.youtube.com/watch?v=dQw4w9WgXcQ')
console.log(html)The primary video or audio of the page (e.g. the video of a Vimeo page or a Tweet), detected by the API and returned as the asset object:
const { url } = await microlink.video('https://vimeo.com/76979871')
console.log(url) // → direct .mp4 URLEvery media URL on the page as a clean string[] — absolute, junk-filtered and deduped. Scope with selectorAll:
const links = await microlink.links('https://example.com', { selectorAll: 'nav a' })
console.log(links) // → ['https://example.com/docs', ...]Every email address present on the page — from mailto: links and plain text alike. It's a preset over the API's email rule type, which extracts and validates addresses server-side:
const emails = await microlink.emails('https://microlink.io')
console.log(emails) // → ['hello@microlink.io']Custom data rules with full MQL rule grammar parity — the same data rules object you'd write for raw MQL, with the result unwrapped:
const { image } = await microlink.extract('https://microlink.io', {
image: { selector: 'meta[property="og:image"]', attr: 'content', type: 'image' }
})
console.log(image) // → { url, type, size, size_pretty, width, height }Nested and array rules work the same way — every named product above is just a preset over this engine.
The tech stack behind a site, or a full Lighthouse report:
const technologies = await microlink.technologies('https://microlink.io')
console.log(technologies) // → [{ name: 'Cloudflare', ... }]Google as structured data (via @microlink/google) — built for agents, RAG pipelines, and anything that needs fresh Google results without parsing SERP HTML. Requires an apiKey. Google search operators (site:, filetype:, quotes, ...) work as-is:
const page = await microlink.search('Lotus Elise S2')
console.log(page.results)
// → [{ title: 'Lotus Elise - Wikipedia', url, description }, ...]
console.log(page.knowledgeGraph) // entity card, when Google shows one
console.log(page.peopleAlsoAsk) // related questions
console.log(page.relatedSearches) // query expansion ideastype routes the query to any of the 10 Google verticals, each returning fields normalized for that surface:
type |
Returns |
|---|---|
search (default) |
web results + knowledge graph, related questions/searches |
news |
articles with publisher, date, thumbnail |
images |
full-resolution image URLs with dimensions |
videos |
video metadata with duration |
places / maps |
local entities with address, phone, coordinates, ratings, hours |
shopping |
products with parsed price and ratings |
scholar |
papers with citation counts and PDF links |
patents |
filings with ISO 8601 dates |
autocomplete |
query suggestions |
const news = await microlink.search('open source llm', { type: 'news', period: 'week' })
console.log(news.results[0])
// → { title: 'DeepSeek open sources DSpark...', publisher: 'VentureBeat', date: '2026-06-30T...' }
const shopping = await microlink.search('macbook pro', { type: 'shopping' })
console.log(shopping.results[0].price) // → { symbol: '$', amount: 1999 }
const autocomplete = await microlink.search('how to fine tune', { type: 'autocomplete' })
console.log(autocomplete.results.map(r => r.value)) // → ['how to fine tune llm', ...]location (ISO 3166-1 country code) localizes ranking and language; period (hour/day/week/month/year) constrains freshness; limit caps results per page:
await microlink.search('recetas de pasta', { location: 'es', limit: 10 })Results compose in depth: every result with a url exposes lazy .html() and .markdown() for fetching the full page content only when needed — the source-expansion pattern for RAG:
const page = await microlink.search('site:openai.com function calling guide')
await Promise.all(
page.results.slice(0, 3).map(async result => ({
title: result.title,
url: result.url,
markdown: await result.markdown()
}))
)The page itself serializes too: page.html() and page.markdown() return the whole Google results page as HTML or Markdown — useful for feeding a SERP straight to an LLM or building your own parser on top:
const page = await microlink.search('Lotus Elise S2')
const markdown = await page.markdown() // the SERP as Markdown
const html = await page.html() // the SERP as HTMLPages chain with .next():
let page = await microlink.search('node.js frameworks')
while (page) {
for (const result of page.results) console.log(result.title)
page = await page.next()
}Run any JavaScript remotely in a sandboxed runtime — no Lambda bundle, no browser fleet, no server (guide). Also exposed as function, matching the API parameter name. You write a plain function; the library handles serialization, compression and the API call for you. When the code doesn't reference page, no browser is started, making execution faster and cheaper:
const { value } = await microlink.run('https://example.com', () => 40 + 2)
console.log(value) // → 42When it references page, Microlink starts a headless browser and navigates to the URL first, handing your code the full puppeteer page for clicks, waits, evaluation and navigation (browser interaction):
const { value } = await microlink.run('https://example.com', async ({ page }) => {
await page.waitForSelector('h1')
return page.$eval('h1', el => el.textContent)
})
console.log(value) // → 'Example Domain'Any extra option you pass is forwarded into the function scope — the simplest way to make one function reusable across requests (custom parameters):
const { value } = await microlink.run(
'https://example.com',
({ page, selector }) => page.$eval(selector, el => el.textContent),
{ selector: 'h1' }
)
console.log(value)You can require() any npm package inside the function — dependencies are detected, installed on the fly into the sandbox, and cached for subsequent runs. Pin a version with require('cheerio@1.0.0'):
const { value } = await microlink.run('https://news.ycombinator.com', async ({ page }) => {
const cheerio = require('cheerio')
const $ = cheerio.load(await page.content())
return $('.titleline > a').map((i, el) => $(el).text()).toArray()
})
console.log(value) // → ['Top HN story', ...]The result carries more than the return value — console.log calls are captured in logging, and profiling reports peak cpu/memory plus per-phase timings (install/build/spawn/run) so you can spot the bottleneck (profiling):
const { isFulfilled, value, logging, profiling } = await microlink.run('https://example.com', ({ page }) => {
console.log('visiting page')
return page.title()
})
console.log(isFulfilled) // → true
console.log(value) // → 'Example Domain'
console.log(logging.log) // → [['visiting page']]
console.log(profiling.phases) // → { install: 0, build: 7.8, spawn: 68.5, run: 0.02, total: 73.7 }When the code throws, the promise still resolves: isFulfilled is false and value carries the error as { name, message }. Resource limits surface the same way with plan-aware errors (TimeoutError, MemoryError, CodeSizeError, ...) — see troubleshooting. From the CLI, put the code in a file and pass extra scope variables as flags: npx microlink function https://example.com --file ./fn.js --selector h1.
Secrets stay out of URLs: apiKey is sent as the x-api-key header, and headers travel as real request headers:
import createClient from 'microlink.io'
const microlink = createClient({ apiKey: process.env.MICROLINK_API_KEY })
console.log(await microlink.markdown('https://x.com/some/article', {
headers: { 'x-api-header-cookie': 'auth_token=...' } // forwarded to the target as `cookie`
}))Any API error rejects with a MicrolinkError carrying code, statusCode and a human-readable description:
import createClient, { MicrolinkError } from 'microlink.io'
const microlink = createClient()
try {
await microlink.screenshot('https://example.com')
} catch (error) {
if (error instanceof MicrolinkError) console.error(error.code, error.description)
}Every product is a microlink subcommand — npx microlink works without a global install:
npx microlink markdown https://example.com
npx microlink screenshot https://example.com --fullPage
npx microlink logo https://github.com --square
npx microlink links https://example.com
npx microlink search "best coffee" --limit 10 --location es
npx microlink extract https://microlink.io --data '{"image":{"selector":"meta[property=og:image]","attr":"content","type":"image"}}'
npx microlink function https://example.com --file ./fn.jsFlags map to the same single options bag as the library. Use --api-key (or the MICROLINK_API_KEY environment variable) for authenticated calls and repeatable --header 'Name: value' flags for request headers. Strings print raw to stdout; objects pretty-print as JSON.
- @microlink/mql — the low-level Microlink Query Language client (raw envelopes,
buffer/streamaccess). - @microlink/google — structured Google data, powering
search. - @microlink/function — remote JavaScript functions, powering
function/run(guides).
microlink.io © microlink.io, released under the MIT License.
microlink.io · GitHub microlinkhq · X @microlinkhq