Add the preview component to React or fetch metadata for a custom React card.
Use the hosted web component when you want a ready-made card. Use the metadata API when you want to render your own React UI.
Load the component once in index.html or your app shell:
<script type="module" src="https://api.linkmetadata.com/component.js" async></script>
Then render the custom element from React:
export function LinkPreview({ url }) {
return (
<link-metadata-preview
data-url={url}
data-theme="card"
data-show-branding="false"
/>
);
}
If TypeScript does not recognize the custom element, add a small declaration file:
// src/linkmetadata.d.ts
declare namespace JSX {
interface IntrinsicElements {
"link-metadata-preview": {
"data-url"?: string;
"data-theme"?: "light" | "dark" | "card";
"data-meta"?: string;
"data-show-branding"?: "true" | "false";
};
}
}
Use the Fetch API when you want full control over markup, loading states, and errors.
import { useEffect, useState } from "react";
export function CustomLinkPreview({ url }) {
const [metadata, setMetadata] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
const controller = new AbortController();
const params = new URLSearchParams({ url });
async function loadMetadata() {
try {
const response = await fetch(
`https://api.linkmetadata.com/v1/metadata?${params}`,
{ signal: controller.signal }
);
if (!response.ok) {
throw new Error(`Metadata request failed with ${response.status}`);
}
setMetadata(await response.json());
} catch (err) {
if (err.name !== "AbortError") setError(err);
}
}
loadMetadata();
return () => controller.abort();
}, [url]);
if (error) return <a href={url}>{url}</a>;
if (!metadata) return <span>Loading preview...</span>;
return (
<a href={metadata.url} target="_blank" rel="noreferrer">
<strong>{metadata.title || metadata.url}</strong>
{metadata.description && <p>{metadata.description}</p>}
</a>
);
}
The API is free to use and rate limited per IP address. For the full response contract, see Metadata API reference.