Embed: Caching and performance
Embeds are read-mostly. The same URL renders the same card thousands of times. Lean into that — cache aggressively and serve from the edge.
This page covers embed-specific performance tactics. For the universal caching controls (
ttl, staleTtl, force, and how to read cache headers), see caching patterns.Embed-specific speedups
The single biggest win for embed-only requests is matching the response shape to your renderer. Three patterns:
-
Static markup with direct
embed— for<img>and<meta og:image>, return the asset itself. The CDN serves bytes directly with no JSON parsing in your stack.<img src="https://api.microlink.io?url=https://stripe.com&embed=image.url" /> -
Filter the JSON when you only need a few fields —
filter=title,description,image.urlshrinks the payload and keeps your renderer's hot path tight.The following examples show how to use the Microlink API with CLI, cURL, JavaScript, Python, Ruby, PHP & Golang, targeting 'https://stripe.com' URL with 'filter' API parameter:
CLI Microlink API example
microlink https://stripe.com&filter=title,description,image.url,logo.urlcURL Microlink API example
curl -G "https://api.microlink.io" \ -d "url=https://stripe.com" \ -d "filter=title,description,image.url,logo.url"JavaScript Microlink API example
import mql from '@microlink/mql' const { data } = await mql('https://stripe.com', { filter: "title,description,image.url,logo.url" })Python Microlink API example
import requests url = "https://api.microlink.io/" querystring = { "url": "https://stripe.com", "filter": "title,description,image.url,logo.url" } 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://stripe.com", filter: "title,description,image.url,logo.url" } 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.bodyPHP Microlink API example
<?php $baseUrl = "https://api.microlink.io/"; $params = [ "url" => "https://stripe.com", "filter" => "title,description,image.url,logo.url" ]; $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://stripe.com") q.Set("filter", "title,description,image.url,logo.url") 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)) }import mql from '@microlink/mql' const { data } = await mql('https://stripe.com', { filter: "title,description,image.url,logo.url" }) -
Disable metadata extraction when you only want a screenshot or iframe —
meta=falseskips the metadata stage entirely.The following examples show how to use the Microlink API with CLI, cURL, JavaScript, Python, Ruby, PHP & Golang, targeting 'https://stripe.com' URL with 'screenshot', 'meta' & 'embed' API parameters:
CLI Microlink API example
microlink https://stripe.com&screenshot&embed=screenshot.urlcURL Microlink API example
curl -G "https://api.microlink.io" \ -d "url=https://stripe.com" \ -d "screenshot=true" \ -d "meta=false" \ -d "embed=screenshot.url"JavaScript Microlink API example
import mql from '@microlink/mql' const { data } = await mql('https://stripe.com', { screenshot: true, meta: false, embed: "screenshot.url" })Python Microlink API example
import requests url = "https://api.microlink.io/" querystring = { "url": "https://stripe.com", "screenshot": "true", "meta": "false", "embed": "screenshot.url" } 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://stripe.com", screenshot: "true", meta: "false", embed: "screenshot.url" } 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.bodyPHP Microlink API example
<?php $baseUrl = "https://api.microlink.io/"; $params = [ "url" => "https://stripe.com", "screenshot" => "true", "meta" => "false", "embed" => "screenshot.url" ]; $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://stripe.com") q.Set("screenshot", "true") q.Set("meta", "false") q.Set("embed", "screenshot.url") 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)) }import mql from '@microlink/mql' const { data } = await mql('https://stripe.com', { screenshot: true, meta: false, embed: "screenshot.url" })Useful for OG images and dynamic banners — no metadata work, just the capture.
Cache strategy
For the controls that apply to every workflow —
ttl, staleTtl, force, and how to verify caching through response headers — see caching patterns.A recommended production setup for embeds:
The following examples show how to use the Microlink API with CLI, cURL, JavaScript, Python, Ruby, PHP & Golang, targeting 'https://stripe.com' URL with 'ttl' & 'staleTtl' API parameters:
CLI Microlink API example
microlink https://stripe.com&ttl=1d&staleTtl=0cURL Microlink API example
curl -G "https://api.microlink.io" \
-d "url=https://stripe.com" \
-d "ttl=1d" \
-d "staleTtl=0"JavaScript Microlink API example
import mql from '@microlink/mql'
const { data } = await mql('https://stripe.com', {
ttl: "1d",
staleTtl: 0
})Python Microlink API example
import requests
url = "https://api.microlink.io/"
querystring = {
"url": "https://stripe.com",
"ttl": "1d",
"staleTtl": "0"
}
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://stripe.com",
ttl: "1d",
staleTtl: "0"
}
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.bodyPHP Microlink API example
<?php
$baseUrl = "https://api.microlink.io/";
$params = [
"url" => "https://stripe.com",
"ttl" => "1d",
"staleTtl" => "0"
];
$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://stripe.com")
q.Set("ttl", "1d")
q.Set("staleTtl", "0")
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))
}import mql from '@microlink/mql'
const { data } = await mql('https://stripe.com', {
ttl: "1d",
staleTtl: 0
})Cache for a day, serve stale instantly while refreshing in the background. Requires a
PRO
plan.For high-traffic embed surfaces — comment widgets, RSS readers, AI search results — pair
staleTtl: 0 with a long ttl so users always hit cache and only the background refresh touches the origin.Hot-linking and the embed URL
The
embed=... URL is itself a CDN-cacheable asset. Browsers and downstream proxies (Slack, Discord, email clients) cache it by URL. Two consequences:- Stable URLs cache best. Avoid appending random query parameters or session IDs.
force=truedefeats this. Useforceonly when you intentionally want a regeneration — never as a default.
If you need the URL to change when source content changes (cache busting), append a content hash you control:
<img src="https://api.microlink.io?url=https://your-site.com/post&screenshot&embed=screenshot.url&v=42" />Bumping
v invalidates downstream caches without touching Microlink's behavior.SDK lazy-loading
The SDK uses
IntersectionObserver and only fires its API call when each preview enters the viewport. Pages with hundreds of embedded links still hit a fast first paint. To preload above-the-fold cards, tighten the lazy options:<Microlink url='...' lazy={{ rootMargin: '400px' }} />See lazy reference.
When you don't need fresh data
Static sites and SSR builds often have the metadata at build time. Skip the runtime call:
<Microlink
url='https://example.com/post'
fetchData={false}
setData={prefetchedData}
/>That removes the API call entirely. Combined with build-time crawling, you ship zero-API-call embeds. See setData reference.
Verify caching is working
Check the response headers when you suspect a slow embed:
| Header | What it tells you |
|---|---|
x-cache-status | HIT (cache), MISS (fresh), BYPASS (forced) |
x-cache-ttl | Effective cache lifetime in milliseconds |
x-response-time | A short value (under ~50ms) usually means a cache hit |
For the full pattern, see verify caching behavior.
Next step
Learn how to embed authenticated dashboards and pages protected by antibot systems in private pages and proxy.