Skip to content

microlinkhq/microlink

Repository files navigation

microlink.io

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.

Install

npm install microlink.io

Usage

The 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 client

ESM 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.

Passing options

Every product method takes a single options object: product(url, options). The library routes each key to the right destination automatically:

  • headers travels as real HTTP request headers (never in the URL). The API forwards any x-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 fullPage for screenshot, format for pdf, selector for markdown).
  • 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
})

Products

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 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.

metadata(url, options)

The unified metadata object (title, description, image, publisher, ...):

microlink.metadata('https://vercel.com').then(({ title, description }) => {
  console.log(title, description)
})

markdown(url, options) / html(url, options) / text(url, options)

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)
})

screenshot(url, options)

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)
})

pdf(url, options)

Generates a PDF and returns the asset object:

microlink.pdf('https://example.com', { format: 'A4' }).then(({ url }) => {
  console.log(url)
})

logo(url, options)

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)
})

embed(url, options)

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)
})

video(url, options) / audio(url, options)

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
})

links / images / videos / audios — (url, options)

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', ...]
})

emails(url, options)

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']
})

extract(url, rules, options)

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.

technologies(url, options) / lighthouse(url, options)

The tech stack behind a site, or a full Lighthouse report:

microlink.technologies('https://microlink.io').then(technologies => {
  console.log(technologies) // → [{ name: 'Cloudflare', ... }]
})

search(query, options)

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(url, code, options)

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.

Authenticated requests

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)

Error handling

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)
})

CLI

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.js

Flags 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.

Related

License

microlink.io © microlink.io, released under the MIT License.

microlink.io · GitHub microlinkhq · X @microlinkhq

About

The Microlink API organized into products, each returning a direct result

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors