Extract OpenGraph, Twitter Cards, and metadata from URLs or HTML. Use when building link previews, SEO tools, or scraping webpage metadata.
Use this skill when helping users extract metadata from webpages, build link previews, create SEO tools, or parse OpenGraph/Twitter Card data.
import { extract } from "ogie";
const result = await extract("https://github.com");
if (result.success) {
console.log(result.data.og.title);
console.log(result.data.og.description);
console.log(result.data.og.images[0]?.url);
}
extract(url, options?)Fetch and extract metadata from a URL.
import { extract } from "ogie";
const result = await extract("https://example.com", {
timeout: 10000,
maxRedirects: 5,
userAgent: "MyBot/1.0",
fetchOEmbed: true,
convertCharset: true,
});
if (result.success) {
console.log(result.data.og.title);
console.log(result.data.twitter.card);
console.log(result.data.basic.favicon);
}
extractFromHtml(html, options?)Extract metadata from an HTML string without network requests.
import { extractFromHtml } from "ogie";
const html = `
<html>
<head>
<meta property="og:title" content="My Page">
<meta property="og:image" content="/images/hero.jpg">
</head>
</html>
`;
const result = extractFromHtml(html, {
baseUrl: "https://example.com", // Required for relative URLs
});
extractBulk(urls, options?)Extract metadata from multiple URLs with rate limiting.
import { extractBulk } from "ogie";
const result = await extractBulk(
["https://github.com", "https://twitter.com", "https://youtube.com"],
{
concurrency: 10,
concurrencyPerDomain: 3,
minDelayPerDomain: 200,
onProgress: (p) => console.log(`${p.completed}/${p.total}`),
}
);
for (const item of result.results) {
if (item.result.success) {
console.log(`${item.url}: ${item.result.data.og.title}`);
}
}
createCache(options?)Create an LRU cache for extraction results.
import { extract, createCache } from "ogie";
const cache = createCache({
maxSize: 100,
ttl: 300_000, // 5 minutes
});
// First call fetches, second returns cached
await extract("https://github.com", { cache });
await extract("https://github.com", { cache }); // Instant
Ogie extracts from 12 sources:
| Property | Description |
|---|---|
data.og |
OpenGraph (title, images, etc.) |
data.twitter |
Twitter Cards |
data.basic |
HTML meta tags, favicon, title |
data.article |
Article metadata (dates, author) |
data.video |
Video metadata (actors, duration) |
data.music |
Music metadata (album, duration) |
data.book |
Book metadata (ISBN, authors) |
data.profile |
Profile metadata (name, gender) |
data.jsonLd |
JSON-LD structured data |
data.dublinCore |
Dublin Core metadata |
data.appLinks |
App Links for deep linking |
data.oEmbed |
oEmbed data (if enabled) |
data.oEmbedDiscovery |
Discovered oEmbed endpoints |
import { extract, isFetchError, isParseError } from "ogie";
const result = await extract(url);
if (!result.success) {
switch (result.error.code) {
case "INVALID_URL":
case "FETCH_ERROR":
case "TIMEOUT":
case "PARSE_ERROR":
case "NO_HTML":
case "REDIRECT_LIMIT":
console.error(result.error.message);
}
if (isFetchError(result.error)) {
console.log(`HTTP Status: ${result.error.statusCode}`);
}
}
| Option | Type | Default | Description |
|---|---|---|---|
timeout |
number |
10000 |
Request timeout in ms |
maxRedirects |
number |
5 |
Max redirects to follow |
userAgent |
string |
ogie/1.0 |
Custom User-Agent |
baseUrl |
string |
β | Base URL for relative paths |
fetchOEmbed |
boolean |
false |
Fetch oEmbed endpoint |
convertCharset |
boolean |
false |
Auto charset detection |
allowPrivateUrls |
boolean |
false |
Allow localhost/private IPs |
cache |
Cache |
β | Cache instance |
bypassCache |
boolean |
false |
Force fresh fetch |
| Option | Type | Default | Description |
|---|---|---|---|
concurrency |
number |
10 |
Max parallel requests |
concurrencyPerDomain |
number |
3 |
Max parallel per domain |
minDelayPerDomain |
number |
200 |
Min ms between domain requests |
requestsPerMinute |
number |
600 |
Global rate limit |
continueOnError |
boolean |
true |
Continue on failures |
Ogie includes built-in protections:
// Allow private URLs for local development
await extract("http://localhost:3000", {
allowPrivateUrls: true,
});
const result = await extract(url);
if (result.success) {
const preview = {
title: result.data.og.title || result.data.basic.title,
description: result.data.og.description || result.data.basic.description,
image: result.data.og.images[0]?.url,
siteName: result.data.og.siteName,
favicon: result.data.basic.favicon,
};
}
const result = await extract(url);
if (result.success) {
const issues = [];
if (!result.data.og.title) issues.push("Missing og:title");
if (!result.data.og.description) issues.push("Missing og:description");
if (!result.data.og.images.length) issues.push("Missing og:image");
if (!result.data.twitter.card) issues.push("Missing twitter:card");
}
const urls = ["https://a.com", "https://b.com", "https://c.com"];
const result = await extractBulk(urls, {
concurrency: 5,
onProgress: (p) => console.log(`${p.succeeded}/${p.total} done`),
});
console.log(`Success rate: ${result.stats.succeeded}/${result.stats.total}`);