Embed: Generate custom previews with AI
This guide builds on the metadata API approach — fetch the JSON, then let your AI coding assistant write the markup that matches your design system. No new dependency, no
<Microlink> wrapper to override, no CSS reset to fight — just a card built from your own components and tokens.This page covers the prompts to paste into Cursor, Claude Code, ChatGPT, or any agent embedded in your IDE — and the style recipes you can ask it to adapt.
The payload your assistant will work with
The same metadata response powers every recipe below. Show it to your assistant once:
The following examples show how to use the Microlink API with CLI, cURL, JavaScript, Python, Ruby, PHP & Golang, targeting 'https://stripe.com' URL:
CLI Microlink API example
microlink https://stripe.comcURL Microlink API example
curl -G "https://api.microlink.io" \
-d "url=https://stripe.com"JavaScript Microlink API example
import mql from '@microlink/mql'
const { data } = await mql('https://stripe.com')Python Microlink API example
import requests
url = "https://api.microlink.io/"
querystring = {
"url": "https://stripe.com"
}
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"
}
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"
];
$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")
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')For the full field list,
palette, screenshot, filter, and the security model, see metadata API with custom HTML/CSS.Why prompt your assistant instead of using the SDK
- No bundle cost. No SDK install, no peer dependencies (
react,react-dom,styled-components). - Matches your design system exactly. Your assistant already knows your tokens, components, and conventions — let it use them.
- Server-renderable. The result is plain HTML/JSX, so it works in SSR, RSC, static sites, emails, and Markdown.
- Easy to evolve. When the design system changes, regenerate the card with the same prompt — no SDK upgrade dance.
The base prompt
Paste this into Cursor, Claude Code, or your IDE's AI assistant before asking for a specific style. It establishes the contract once.
I want to add link previews to this project without installing the
Microlink SDK. Instead, fetch the metadata directly from the API:
GET https://api.microlink.io?url=<TARGET_URL>
The response is JSON with `data` containing at least:
- data.title (string)
- data.description (string)
- data.publisher (string)
- data.url (string, canonical)
- data.image.url (string, og:image)
- data.logo.url (string, favicon / brand mark)
- data.author (string | null)
Generate a preview component that:
1. Reads those fields from `data`.
2. Uses *this project's* design system — same components, tokens,
spacing, typography, and theming primitives I already use here.
Do not invent new design tokens. Do not use inline styles when
the project already has CSS modules / Tailwind / styled-components.
3. Handles the case where image, logo, description, or publisher
are missing — render a graceful fallback, never a broken `<img>`.
4. Stays accessible: anchor wraps the whole card with `rel="noopener
noreferrer"`, decorative images use empty alt, the title is a
real heading.
When I ask for a specific style (hero card, one-line, chat bubble,
tweet-style, notification, telegram-style), apply that layout while
keeping the rules above.The prompt is intentionally framework-agnostic. Your assistant adapts it to React + Tailwind, Vue + CSS modules, Astro, Svelte, plain HTML — whatever the open project is using.
Pick a style and ask for it
Each section below describes the layout, when it fits, the prompt to send, and a reference output. The reference is a starting point — your assistant should rewrite it in your project's idioms.
Hero card
A full-bleed image with publisher, title, and description below. Best when the link is the focus of the section.
Prompt to send: "Generate a hero-style preview using the contract above. Image fills the top with a 16:9 ratio, then publisher (with logo), title, and a 3-line clamped description below. Match the card chrome and elevation we already use for other content cards in this project."
Rendered with
stripe.com as the source:The shape your assistant should produce — image at the top, publisher + title + clamped description below.
One-line
Compact, scannable, and fits inside dense layouts. Good for search results, footnotes, and sidebars.
Prompt to send: "Generate a one-line preview using the contract above. Logo, publisher (bold), title (truncated), and the bare hostname on the right, all on a single row. Reuse the row primitives we already have for list items in this project."
Rendered with
stripe.com as the source:Logo, publisher, title, and hostname collapsed to a single dense row.
Tweet-style
Vertical card with image-on-top, big title, big description — fits social-feed clones, comment threads, and replies.
Prompt to send: "Generate a tweet-style preview using the contract above. Round avatar from logo at the top with publisher and a fake @handle from the hostname, then the title as the post body, then a rounded media image. Use the radii and avatar utilities we already have."
Rendered with
stripe.com as the source:m
Microlink@microlinkhq · 2h
Embed any URL with rich previews — try it with stripe.com
24 188 1.2k
Avatar + @handle header, post body, embedded link card, action bar — the full embedded-tweet shape.
Telegram-style
A quoted reply with a colored accent bar pulled from the source's brand palette. Each card adapts to the link.
Prompt to send: "Generate a telegram-style preview using the contract above. Addpalette: trueto the metadata request so I get brand colors. Use a vertical accent bar on the left, colored withdata.image.palette[0], and tint the publisher line with the same color. Make sure the contrast pair (background_color+color) is respected for readability."
Rendered with
stripe.com as the source:Stripe
Financial Infrastructure to Grow Your Revenue
Accent bar pulled from
data.image.palette[0] — every link automatically tints itself to the source brand.This recipe needs
palette: true. See palette reference.Notification
Short, glanceable item designed for activity feeds, toasts, and push-style components.
Prompt to send: "Generate a notification-style preview using the contract above. A small logo on the left, title and publisher in the middle, and a primary-colored 'Open' link on the right. Reuse the toast / activity-row component we already have."
Rendered with
stripe.com as the source:Stripenow
Financial Infrastructure to Grow Your Revenue
iOS-style notification — logo, publisher + timestamp, then the link title and a short description.
Chat bubble
Inline, conversational citation — the right pattern for AI chat products and comment threads.
Prompt to send: "Generate a chat-bubble citation using the contract above. A short text line referencing the publisher, then a pill-shaped link with a tiny logo and the title (truncated). Match the chat bubble we already render for AI responses in this project."
Rendered with
stripe.com as the source:Check this webpage! stripe.com
12:34✓✓
WhatsApp-style bubble with an embedded link card and a clickable URL line — drop it into a chat thread as-is.
Wire it up
Once your assistant has generated the markup, you only need a minimal data-fetching helper. Drop one of these into the project and the preview is ready to render.
Server / RSC / build-time
import mql from '@microlink/mql'
export async function getPreview (url, options = {}) {
const { data } = await mql(url, { palette: true, ...options })
return data
}// app/components/LinkPreview.tsx (Next.js RSC example)
import { getPreview } from '@/lib/preview'
export async function LinkPreview ({ url }) {
const data = await getPreview(url)
return /* the JSX your assistant generated, reading from `data` */
}Client-side
import { useEffect, useState } from 'react'
export function useLinkPreview (url) {
const [data, setData] = useState(null)
useEffect(() => {
let cancelled = false
fetch(`https://api.microlink.io?url=${encodeURIComponent(url)}&palette=true`)
.then(r => r.json())
.then(json => { if (!cancelled && json.status === 'success') setData(json.data) })
return () => { cancelled = true }
}, [url])
return data
}Direct from HTML
For static sites, README files, or markdown — skip the JSON entirely and use direct embed:
<img src="https://api.microlink.io?url=https://stripe.com&embed=image.url" alt="Stripe" />See the embed reference for the full field list.
Theming with palette
Ask your assistant to make any recipe brand-aware once
palette: true is on. The pattern:const { data } = await mql(url, { palette: true })
card.style.setProperty('--brand', data.image.background_color)
card.style.setProperty('--brand-text', data.image.color)
card.style.setProperty('--brand-accent', data.image.palette[0])The contrast pair (
background_color + color) is WCAG-checked, so foreground text stays readable. See palette reference.When og:image is missing
Some pages don't expose a usable image. Tell your assistant to fall back to a real screenshot:
const { data } = await mql(url, { screenshot: true, palette: true })
const heroImage = data.image?.url ?? data.screenshot.urlIterate with your assistant
The recipes above are starting points. Once the first card is in your codebase, ask your assistant for variations without repeating the contract:
- "Make the hero card horizontal, image on the left, content on the right."
- "Tighten the one-line variant for our sidebar — drop the description and switch to our
--text-xstoken." - "Add a hover state matching how our other clickable cards lift on hover."
- "Animate the entry with the same enter transition we use on toasts."
Because the AI is editing files in your repo, it can reuse hooks, mixins, utility classes, and component composition you already have — so the previews stay coherent as the codebase evolves.
Next step
For optimizing repeat embed calls (especially when an AI agent fans out across many URLs), see caching and performance.