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 library organizes the Microlink API into products — the way Stripe organizes a powerful API into stripe.customers.create():
const microlink = require('microlink.io')()
microlink.markdown('https://example.com').then(markdown => {
console.log(markdown) // → the page content as a Markdown string
})It's a thin layer over @microlink/mql: HTTP, auth, retries, errors and binary handling are already solved there. Each product just sets the right API parameters and unwraps the result.
npm install microlink.ioThe export is a single factory. Call it once to get a client; the optional argument carries apiKey and any other client-wide defaults:
const createClient = require('microlink.io')
const microlink = createClient() // free client
const microlinkPro = createClient({ apiKey: process.env.MICROLINK_API_KEY }) // pro clientESM works the same way:
import createClient from 'microlink.io'
const microlink = createClient()Whatever 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, ...).
const microlink = require('microlink.io')()
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, ...):
microlink.metadata('https://vercel.com').then(({ title, description }) => {
console.log(title, description)
})The page content as Markdown, HTML or plain text. Use selector to scope it:
microlink.markdown('https://example.com', { selector: 'article' }).then(markdown => {
console.log(markdown)
})Takes a screenshot and returns the asset object (url, type, width, height, size, ...):
microlink.screenshot('https://example.com', { fullPage: true }).then(({ url }) => {
console.log(url)
})Generates a PDF and returns the asset object:
microlink.pdf('https://example.com', { format: 'A4' }).then(({ url }) => {
console.log(url)
})The brand logo of the site. Pass square: true to prefer the square variant:
microlink.logo('https://github.com', { square: true }).then(({ url }) => {
console.log(url)
})The oEmbed-style embeddable iframe ({ html, scripts }), e.g. for a YouTube video or a Tweet. Constrain with maxWidth/maxHeight:
microlink.embed('https://www.youtube.com/watch?v=dQw4w9WgXcQ').then(({ html }) => {
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:
microlink.video('https://vimeo.com/76979871').then(({ url, type }) => {
console.log(url) // → direct .mp4 URL
})Every media URL on the page as a clean string[] — absolute, junk-filtered and deduped. Scope with selectorAll:
microlink.links('https://example.com', { selectorAll: 'nav a' }).then(links => {
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:
microlink.emails('https://microlink.io').then(emails => {
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:
microlink.extract('https://microlink.io', {
image: { selector: 'meta[property="og:image"]', attr: 'content', type: 'image' }
}).then(({ 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:
microlink.technologies('https://microlink.io').then(technologies => {
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:
microlink.search('Lotus Elise S2').then(page => {
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 ideas
})type 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 |
microlink.search('open source llm', { type: 'news', period: 'week' }).then(({ results }) => {
console.log(results[0])
// → { title: 'DeepSeek open sources DSpark...', publisher: 'VentureBeat', date: '2026-06-30T...' }
})
microlink.search('macbook pro', { type: 'shopping' }).then(({ results }) => {
console.log(results[0].price) // → { symbol: '$', amount: 1999 }
})
microlink.search('how to fine tune', { type: 'autocomplete' }).then(({ results }) => {
console.log(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:
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:
microlink.search('site:openai.com function calling guide').then(page =>
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:
microlink.search('Lotus Elise S2').then(async page => {
const markdown = await page.markdown() // the SERP as Markdown
const html = await page.html() // the SERP as HTML
})Pages chain with .next():
microlink.search('node.js frameworks').then(async page => {
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:
microlink.run('https://example.com', () => 40 + 2).then(({ value }) => {
console.log(value) // → 42
})When 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):
microlink.run('https://example.com', async ({ page }) => {
await page.waitForSelector('h1')
return page.$eval('h1', el => el.textContent)
}).then(({ value }) => {
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):
microlink.run(
'https://example.com',
({ page, selector }) => page.$eval(selector, el => el.textContent),
{ selector: 'h1' }
).then(({ value }) => 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'):
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()
}).then(({ value }) => {
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):
microlink.run('https://example.com', ({ page }) => {
console.log('visiting page')
return page.title()
}).then(({ isFulfilled, value, logging, profiling }) => {
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: 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:
const microlink = require('microlink.io')({ apiKey: process.env.MICROLINK_API_KEY })
microlink.markdown('https://x.com/some/article', {
headers: { 'x-api-header-cookie': 'auth_token=...' } // forwarded to the target as `cookie`
}).then(console.log)Any API error rejects with a MicrolinkError carrying code, statusCode and a human-readable description:
const { MicrolinkError } = require('microlink.io')
microlink.screenshot('https://example.com').catch(error => {
if (error instanceof MicrolinkError) console.error(error.code, error.description)
})The package ships a microlink binary where every product is a subcommand:
microlink markdown https://example.com
microlink screenshot https://example.com --fullPage
microlink logo https://github.com --square
microlink links https://example.com
microlink search "best coffee" --limit 10 --location es
microlink extract https://microlink.io --data '{"image":{"selector":"meta[property=og:image]","attr":"content","type":"image"}}'
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