Skip to content

Caching patterns

These caching patterns apply to every Microlink workflow: screenshots, PDFs, data extraction, metadata, and insights. Each guide's own caching page covers the workflow-specific speedups; this page covers the shared cache controls.

How caching works

Every Microlink response is cached for 24 hours by default. The cache is two-layered:
  1. Unified cache — the first request creates a shared copy (x-cache-status: MISS). Subsequent requests serve that copy (HIT).
  2. Edge node cache — after the unified cache is warm, responses are also served from the nearest CloudFlare edge node.
See the cache docs for the full architecture.

Cache TTL
PRO

Use ttl to control how long a response stays valid before expiring:

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

CLI Microlink API example

microlink https://microlink.io&ttl=1d

cURL Microlink API example

curl -G "https://api.microlink.io" \
  -d "url=https://microlink.io" \
  -d "ttl=1d"

JavaScript Microlink API example

import mql from '@microlink/mql'

const { data } = await mql('https://microlink.io', {
  ttl: "1d"
})

Python Microlink API example

import requests

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

querystring = {
    "url": "https://microlink.io",
    "ttl": "1d"
}

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",
  ttl: "1d"
}

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",
    "ttl" => "1d"
];

$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://microlink.io")
    q.Set("ttl", "1d")
    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))
}
After the TTL expires, the next request generates a fresh response.
The value must be between 1 minute and 31 days. It accepts milliseconds or humanized strings:
ttl=90s        # 90 seconds
ttl=1h         # 1 hour
ttl=1d         # 1 day (24 hours)
ttl=7d         # 7 days
ttl=min        # alias for 1 minute
ttl=max        # alias for 31 days
Choose your TTL based on how often the target content changes:
Content typeRecommended TTL
Rapidly changing (dashboards, feeds)'1h' or less
Moderate changes (blogs, docs, marketing pages)'1d' to '7d'
Rarely changing (static docs, stable references)'max' (31 days)
The TTL is reflected in the x-cache-ttl response header. See the ttl reference for all supported formats.

Stale-while-revalidate
PRO

The staleTtl parameter serves the cached response immediately while refreshing it in the background:

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

CLI Microlink API example

microlink https://microlink.io&ttl=1d&staleTtl=0

cURL Microlink API example

curl -G "https://api.microlink.io" \
  -d "url=https://microlink.io" \
  -d "ttl=1d" \
  -d "staleTtl=0"

JavaScript Microlink API example

import mql from '@microlink/mql'

const { data } = await mql('https://microlink.io', {
  ttl: "1d",
  staleTtl: 0
})

Python Microlink API example

import requests

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

querystring = {
    "url": "https://microlink.io",
    "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://microlink.io",
  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.body

PHP Microlink API example

<?php

$baseUrl = "https://api.microlink.io/";

$params = [
    "url" => "https://microlink.io",
    "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://microlink.io")
    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))
}
With staleTtl: 0, every request serves the cached copy instantly and triggers a background refresh.
This is the recommended production pattern. Your users always get an instant response, and the content stays reasonably fresh. The staleTtl value cannot exceed the ttl value.
PatternBehavior
staleTtl: 0Always serve cache, always revalidate in background
staleTtl: '12h'Serve cache for 12 hours, then revalidate
staleTtl: falseDisabled (default) — no stale serving
See the staleTtl reference for all supported formats.

Bypassing the cache

Use force: true to skip the cache entirely and get a fresh response:

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

CLI Microlink API example

microlink https://microlink.io&force

cURL Microlink API example

curl -G "https://api.microlink.io" \
  -d "url=https://microlink.io" \
  -d "force=true"

JavaScript Microlink API example

import mql from '@microlink/mql'

const { data } = await mql('https://microlink.io', {
  force: true
})

Python Microlink API example

import requests

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

querystring = {
    "url": "https://microlink.io",
    "force": "true"
}

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",
  force: "true"
}

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",
    "force" => "true"
];

$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://microlink.io")
    q.Set("force", "true")
    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))
}
The response header x-cache-status will be BYPASS. Use sparingly — this always triggers a fresh request.

Verify caching behavior

Check these response headers to confirm the request behaved as expected:
HeaderWhat it tells you
x-cache-statusHIT (served from cache), MISS (fresh), or BYPASS (forced)
x-cache-ttlThe effective cache lifetime in milliseconds
cf-cache-statusCloudFlare edge cache status
x-response-timeTotal request duration — fast times usually indicate a cache hit