Zum Inhalt springen
Tutorial

URL-Metadaten-API: Erstellen Sie Linkvorschauen wie Slack in einem Aufruf

| 6 min read

Extrahieren Sie Open Graph-Tags, Twitter-Kartendaten, Favoriten und Seitentitel aus jeder URL mit einer POST-Anfrage. Erstellen Sie Link-Vorschaukarten in weniger als 20 Codezeilen.

Social media cards displayed on a phone screen
Photo by Rami Al-zayat on Unsplash

Ein Benutzer fügt eine URL in Ihre Chat-App ein. Sie möchten eine umfangreiche Vorschaukarte mit dem Seitentitel anzeigen. Beschreibung und Miniaturbild; die gleiche Kartenanzeige in Slack, Discord und iMessage. Du könntest Rufen Sie die Seite ab, analysieren Sie den HTML-Code und extrahieren Sie die Open Graph-Tags selbst. Oder Sie könnten eines schicken POST-Anfrage.

Die Botoi /v1/url-metadata Der Endpunkt ruft eine beliebige URL ab und liest sie <meta> Tags und gibt strukturiertes JSON zurück: OG-Titel, OG-Beschreibung, OG-Bild, Twitter-Kartendaten, Favicon, kanonische URL, Sprache und mehr. Ein Aufruf ersetzt den Abruf, den HTML-Parser und die Fallback-Logik.

Der Endpunkt

curl -X POST https://api.botoi.com/v1/url-metadata \\
  -H "Content-Type: application/json" \\
  -d '{ "url": "https://github.com/anthropics/claude-code" }'

Antwort:

{
  "success": true,
  "data": {
    "url": "https://github.com/anthropics/claude-code",
    "status": 200,
    "content_type": "text/html",
    "title": "anthropics/claude-code: Claude Code is an agentic coding tool",
    "description": "Claude Code is an agentic coding tool that lives in your terminal",
    "og": {
      "title": "anthropics/claude-code",
      "description": "Claude Code is an agentic coding tool that lives in your terminal",
      "image": "https://opengraph.githubassets.com/1/anthropics/claude-code",
      "type": "object",
      "url": "https://github.com/anthropics/claude-code",
      "site_name": "GitHub"
    },
    "twitter": {
      "card": "summary_large_image",
      "title": "anthropics/claude-code",
      "description": "Claude Code is an agentic coding tool that lives in your terminal",
      "image": null
    },
    "favicon": "https://github.com/favicon.ico",
    "canonical": "https://github.com/anthropics/claude-code",
    "language": "en",
    "author": null,
    "keywords": [],
    "theme_color": null
  }
}

Die Antwort bietet Ihnen alles, was Sie zum Rendern einer Linkvorschaukarte benötigen. Der og Das Objekt enthält die Open Graph-Tags, die Slack und Discord lesen. Der twitter Das Objekt enthält die Twitter-Karten-Tags. Wenn eine Seite beides festlegt, erhalten Sie beides. Wenn eine Seite keines von beiden festlegt, erhalten Sie trotzdem den HTML-Code title Und description als Fallbacks.

Erstellen Sie eine Link-Vorschaukomponente für die Chat-App

Diese Preact-Komponente nimmt eine URL, ruft die API auf und rendert eine Karte mit dem OG-Bild, dem Titel, Beschreibung und Site-Name. Wenn OG-Tags fehlen, wird auf den HTML-Titel zurückgegriffen.

import { useState, useEffect } from "preact/hooks";

interface LinkPreview {
  title: string | null;
  description: string | null;
  image: string | null;
  favicon: string | null;
  url: string;
  siteName: string | null;
}

function useLinkPreview(url: string) {
  const [preview, setPreview] = useState&lt;LinkPreview | null&gt;(null);
  const [loading, setLoading] = useState(false);

  useEffect(() =&gt; {
    if (!url) return;
    setLoading(true);

    fetch("https://api.botoi.com/v1/url-metadata", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ url }),
    })
      .then((res) =&gt; res.json())
      .then(({ data }) =&gt; {
        setPreview({
          title: data.og?.title || data.title,
          description: data.og?.description || data.description,
          image: data.og?.image || null,
          favicon: data.favicon,
          url: data.canonical || url,
          siteName: data.og?.site_name || null,
        });
      })
      .catch(() =&gt; setPreview(null))
      .finally(() =&gt; setLoading(false));
  }, [url]);

  return { preview, loading };
}

function LinkPreviewCard({ url }: { url: string }) {
  const { preview, loading } = useLinkPreview(url);

  if (loading) {
    return (
      &lt;div class="rounded-lg border border-gray-200 p-4 animate-pulse"&gt;
        &lt;div class="h-4 bg-gray-100 rounded w-3/4 mb-2"&gt;&lt;/div&gt;
        &lt;div class="h-3 bg-gray-100 rounded w-full"&gt;&lt;/div&gt;
      &lt;/div&gt;
    );
  }

  if (!preview) return null;

  return (
    &lt;a
      href={preview.url}
      target="_blank"
      rel="noopener noreferrer"
      class="block rounded-lg border border-gray-200 overflow-hidden
             hover:border-gray-400 transition-colors no-underline"
    &gt;
      {preview.image &amp;&amp; (
        &lt;img
          src={preview.image}
          alt=""
          class="w-full h-40 object-cover"
        /&gt;
      )}
      &lt;div class="p-4"&gt;
        &lt;div class="flex items-center gap-2 mb-2"&gt;
          {preview.favicon &amp;&amp; (
            &lt;img src={preview.favicon} alt="" class="w-4 h-4" /&gt;
          )}
          &lt;span class="text-xs text-gray-500"&gt;
            {preview.siteName || new URL(preview.url).hostname}
          &lt;/span&gt;
        &lt;/div&gt;
        &lt;p class="font-semibold text-sm text-gray-900 mb-1"&gt;
          {preview.title}
        &lt;/p&gt;
        &lt;p class="text-xs text-gray-600 line-clamp-2"&gt;
          {preview.description}
        &lt;/p&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  );
}

Der useLinkPreview Hook übernimmt den Abruf und ordnet die API-Antwort einer Flat zu Objekt, das Ihre Benutzeroberfläche nutzen kann. Die Fallback-Kette (data.og?.title || data.title) bedeutet, dass Sie immer etwas anzuzeigen haben, auch wenn eine Seite keine OG-Tags hat. Die Komponente Rendert ein Ladegerüst, während der API-Aufruf ausgeführt wird, und tauscht dann die Vorschaukarte ein.

SEO-Metadaten automatisch in einem CMS ausfüllen

Inhaltsredakteure fügen beim Schreiben von Artikeln Referenz-URLs ein. Anstatt sie zu kopieren und einzufügen Wenn Sie den Titel und die Beschreibung manuell eingeben, kann Ihr CMS diese Daten aus der URL abrufen und diese vorab ausfüllen SEO-Bereiche.

async function autoFillSeoFields(referenceUrl: string) {
  const res = await fetch("https://api.botoi.com/v1/url-metadata", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: \`Bearer \${process.env.BOTOI_API_KEY}\`,
    },
    body: JSON.stringify({ url: referenceUrl }),
  });

  const { data } = await res.json();

  return {
    seoTitle: data.og?.title || data.title || "",
    seoDescription: data.og?.description || data.description || "",
    ogImage: data.og?.image || "",
    canonical: data.canonical || referenceUrl,
    favicon: data.favicon || "",
  };
}

// Usage in a CMS admin panel
const fields = await autoFillSeoFields("https://stripe.com/docs/payments");
// fields.seoTitle       → "Payments | Stripe Documentation"
// fields.seoDescription → "Accept payments online..."
// fields.ogImage        → "https://images.stripe.com/..."

Wenn ein Redakteur eine URL in das Feld „Referenz“ einfügt, ruft das CMS auf autoFillSeoFields, Füllt die SEO-Titel-, Beschreibungs- und OG-Bildeingaben aus und ermöglicht dem Redakteur von dort aus Anpassungen. Der gleiche Ansatz funktioniert für Lesezeichen-Manager, Apps zum späteren Lesen und interne Wiki-Tools Generieren Sie automatisch Karten aus eingefügten Links.

Node.js-Funktion mit Timeout und Fehlerbehandlung

In der Produktion möchten Sie eine Zeitüberschreitung, damit eine langsame Zielseite Ihre Anfrage nicht auf unbestimmte Zeit blockiert. Diese Funktion umschließt den API-Aufruf mit einer 5-sekündigen Pause AbortController Auszeit und kehrt zurück null auf Scheitern statt Werfen.

async function getLinkPreview(url: string) {
  const controller = new AbortController();
  const timeout = setTimeout(() =&gt; controller.abort(), 5000);

  try {
    const res = await fetch("https://api.botoi.com/v1/url-metadata", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: \`Bearer \${process.env.BOTOI_API_KEY}\`,
      },
      body: JSON.stringify({ url }),
      signal: controller.signal,
    });

    if (!res.ok) {
      throw new Error(\`API returned \${res.status}\`);
    }

    const { success, data } = await res.json();

    if (!success) {
      return null;
    }

    return {
      title: data.og?.title || data.title,
      description: data.og?.description || data.description,
      image: data.og?.image,
      favicon: data.favicon,
      siteName: data.og?.site_name,
      canonical: data.canonical,
      twitterCard: data.twitter?.card,
    };
  } catch (err) {
    console.error(\`Failed to fetch preview for \${url}:\`, err);
    return null;
  } finally {
    clearTimeout(timeout);
  }
}

Die Funktion gibt ein sauberes Objekt mit den Feldern zurück, die Ihre Benutzeroberfläche benötigt. Anrufer berühren nicht das Rohe API-Antwort. Wenn die Zielseite nicht verfügbar ist oder die Anforderung abläuft, kehrt die Funktion zurück null und Ihre App kann einen Fallback anzeigen, anstatt abzustürzen.

Umgang mit Randfällen

Nicht jede URL kooperiert. Einige Seiten haben keine OG-Tags. Einige stecken hinter Weiterleitungsketten. Einige Nehmen Sie sich 10 Sekunden Zeit, um zu antworten. Hier erfahren Sie, wie Sie mit den einzelnen Fällen umgehen.

// 1. Pages with no OG tags: fall back to title + description
const preview = await getLinkPreview(url);
const displayTitle = preview?.title || "Untitled page";
const displayDesc = preview?.description || url;
const displayImage = preview?.image || "/fallback-thumbnail.png";

// 2. Detect redirects by comparing input URL to canonical
const inputUrl = "https://bit.ly/3xYzAbc";
const result = await getLinkPreview(inputUrl);
if (result?.canonical !== inputUrl) {
  console.log(\`Redirected to: \${result?.canonical}\`);
}

// 3. Batch multiple URLs with Promise.allSettled
const urls = [
  "https://github.com",
  "https://stripe.com",
  "https://vercel.com",
];

const previews = await Promise.allSettled(
  urls.map((u) =&gt; getLinkPreview(u))
);

const results = previews.map((p, i) =&gt; ({
  url: urls[i],
  preview: p.status === "fulfilled" ? p.value : null,
}));

Keine AND-Tags: Zurückgreifen auf title Und description. Wenn Wenn diese ebenfalls leer sind, wird die Roh-URL angezeigt. Zeigen Sie ein Platzhalterbild an, wenn og.image ist null.

Weiterleitungen: Die API folgt Weiterleitungen und gibt Metadaten von der letzten Seite zurück. Vergleichen Sie die Eingabe-URL mit canonical um zu erkennen, wann eine Weiterleitung stattgefunden hat.

Langsame Seiten: Legen Sie auf Ihrer Seite eine Zeitüberschreitung fest (in den meisten Fällen reichen 5 Sekunden). Die Die API selbst hat eine interne Zeitüberschreitung, aber Sie sollten Ihre eigene erzwingen, damit dies bei einem langsamen Ziel nicht der Fall ist behindern die Benutzererfahrung.

Batch-Abruf: Verwenden Promise.allSettled um Vorschauen abzurufen mehrere URLs parallel. Fehlgeschlagene Anfragen werden zurückgegeben null ohne den Rest zu blockieren.

Wichtige Punkte

  • POST /v1/url-metadata Gibt OG-Tags, Twitter-Karten-Tags, Favicon und Canonical zurück URL, Sprache und Schlüsselwörter in einer JSON-Antwort.
  • Die Antwort spiegelt die Daten wider, die Slack, Discord und iMessage zum Rendern von Linkvorschauen verwenden. Du Erhalten Sie dieselben Felder, ohne einen HTML-Parser zu schreiben.
  • Der anonyme Zugriff funktioniert mit 5 Anfragen pro Minute und ohne API-Schlüssel. Genug für die Entwicklung und Apps mit geringem Datenverkehr.
  • Zurückgreifen auf title Und description wenn OG-Tags fehlen. Die API gibt diese immer aus dem HTML zurück <head> wenn sie existieren.
  • Fügen Sie für den Produktionsgebrauch ein Timeout hinzu, speichern Sie die Ergebnisse nach URL und Handle zwischen null Antworten würdevoll. Überprüfen Sie die API-Dokumente für die vollständige Parameterreferenz.

FAQ

Was ist eine URL-Metadaten-API?
Eine URL-Metadaten-API ruft eine Webseite ab und extrahiert strukturierte Daten aus ihrem HTML: Seitentitel, Meta-Beschreibung, Open Graph-Tags (og:title, og:image, og:description), Twitter-Card-Tags, Favicon-URL, kanonische URL und Sprache. Sie senden eine URL und die API gibt alles als JSON zurück. Es erspart Ihnen, die Seite selbst abzurufen und Roh-HTML zu analysieren.
Wie generieren Slack, Discord und iMessage Linkvorschauen?
Wenn ein Benutzer eine URL einfügt, rufen diese Apps die Seite im Hintergrund ab und lesen ihre Open Graph-Meta-Tags (og:title, og:description, og:image). Sie rendern eine Vorschaukarte aus diesen Werten. Wenn OG-Tags fehlen, greifen sie auf den HTML-Titel und die Meta-Beschreibung zurück. Der botoi /v1/url-metadata-Endpunkt gibt dieselben Daten zurück, die diese Apps gelesen haben, sodass Sie identische Vorschaukarten in Ihrer eigenen Anwendung erstellen können.
Was passiert, wenn eine Seite keine Open Graph-Tags hat?
Die API gibt weiterhin den HTML-Titel, die Meta-Beschreibung, das Favicon, die kanonische URL und die Sprache zurück. Die og-Felder in der Antwort sind null. Ihr Frontend sollte auf Titel und Beschreibung zurückgreifen, wenn og.title und og.image fehlen.
Folgt die API Weiterleitungen?
Ja. Die API folgt HTTP 301/302/307/308-Weiterleitungen und gibt Metadaten von der endgültigen Ziel-URL zurück. Die Antwort enthält die aufgelöste URL und ihren HTTP-Statuscode, sodass Sie Weiterleitungsketten erkennen können.
Ist die URL-Metadaten-API kostenlos?
Der anonyme Zugriff erfordert keinen API-Schlüssel und ermöglicht 5 Anfragen pro Minute plus 100 pro Tag. Dies deckt Entwicklungs- und Anwendungsfälle mit geringem Datenverkehr ab. Bezahlte Pläne beginnen bei 9 $/Monat für höhere Tariflimits.

Starte mit botoi zu entwickeln

150+ API-Endpunkte für Abfragen, Textverarbeitung, Bildgenerierung und Entwickler-Tools. Kostenloser Tarif, keine Kreditkarte nötig.