Quick start
Send a single POST request and get structured JSON back. Works in any language with an HTTP client.
curl -X POST https://metasnap.vercel.app/api/scrape \
-H "Content-Type: application/json" \
-d '{"url":"https://github.com"}'
Quick meta-tag scrape
Fetches a URL, parses the HTML, and returns every relevant meta tag — title, description, Open Graph, Twitter Card, favicon — in a clean JSON shape. Use this for previews or to build your own meta tag inspector.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
url |
string | Yes | Any HTTP/HTTPS URL. Protocol is auto-prefixed if missing. |
Response shape
{
"title": "string",
"description": "string",
"ogTitle": "string",
"ogDescription": "string",
"ogImage": "string (absolute URL)",
"ogUrl": "string",
"ogType": "string",
"ogSiteName": "string",
"twitterCard": "string",
"twitterTitle": "string",
"twitterDescription": "string",
"twitterImage": "string",
"twitterSite": "string",
"favicon": "string (absolute URL)",
"url": "string (final URL after redirects)",
"domain": "string"
}
Try it live
Code samples
curl -X POST https://metasnap.vercel.app/api/scrape \
-H "Content-Type: application/json" \
-d '{"url":"https://github.com"}'
const res = await fetch("https://metasnap.vercel.app/api/scrape", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ url: "https://github.com" }),
});
const meta = await res.json();
console.log(meta.ogImage);
import httpx
resp = httpx.post(
"https://metasnap.vercel.app/api/scrape",
json={"url": "https://github.com"},
)
meta = resp.json()
print(meta["ogImage"])
const meta = await fetch("https://metasnap.vercel.app/api/scrape", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ url: "https://github.com" }),
}).then(r => r.json());
console.log(`Title: ${meta.title}`);
console.log(`OG Image: ${meta.ogImage}`);
Deep SEO audit
Runs 15+ checks (title length, meta description, OG image, canonical, JSON-LD, viewport, robots, h1, and more), computes a 0–100 score with a letter grade, generates smart title/description suggestions, and returns a copy-paste optimised meta tag bundle.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
url |
string | Yes | The URL to audit. |
Response shape
{
"meta": { /* same shape as /api/scrape */ },
"score": 87,
"grade": "B",
"summary": "Good — a few small tweaks will polish it.",
"checks": [
{
"label": "Title length",
"status": "pass | warn | fail",
"detail": "57 chars",
"tip": "Optional fix suggestion"
}
/* ...15+ entries */
],
"suggestions": {
"title": "Optimised <= 60 char suggestion",
"description": "Optimised <= 160 char suggestion"
},
"bundle": "<!-- Primary Meta Tags -->..."
}
Try it live
Code samples
curl -X POST https://metasnap.vercel.app/api/audit \
-H "Content-Type: application/json" \
-d '{"url":"https://stripe.com"}'
const audit = await fetch("https://metasnap.vercel.app/api/audit", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ url: "https://stripe.com" }),
}).then(r => r.json());
console.log(`Score: ${audit.score} (${audit.grade})`);
audit.checks
.filter(c => c.status !== "pass")
.forEach(c => console.log(`- ${c.label}: ${c.tip}`));
import httpx
audit = httpx.post(
"https://metasnap.vercel.app/api/audit",
json={"url": "https://stripe.com"},
timeout=20,
).json()
print(f"Score: {audit['score']} ({audit['grade']})")
for check in audit["checks"]:
if check["status"] != "pass":
print(f"- {check['label']}: {check['tip']}")
Broken-link auditor
Crawls a single URL, extracts every anchor tag, and concurrently checks the first 25 unique destinations for HTTP status. Returns Active / Redirect / Broken classifications and which links are internal vs external.
Response shape
{
"targetUrl": "string",
"linksCount": 42,
"checkedCount": 25,
"results": [
{
"url": "string",
"text": "anchor text",
"internal": true,
"status": 200,
"label": "Active | Redirect | Broken | Failed"
}
]
}
Try it live
Code samples
curl -X POST https://metasnap.vercel.app/api/audit-links \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com"}'
const data = await fetch("https://metasnap.vercel.app/api/audit-links", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ url: "https://example.com" }),
}).then(r => r.json());
const broken = data.results.filter(r => r.label === "Broken");
console.log(`${broken.length} broken links found`);
Image proxy / CORS bypass
Proxies image downloads (OG images, favicons) so you can save them
client-side without CORS issues. Returns the raw image bytes with the original Content-Type and a
Content-Disposition: attachment header.
Query parameters
| Field | Type | Required | Description |
|---|---|---|---|
url |
string | Yes | The image URL to fetch. |
Code samples
<a href="/api/download?url=https://github.com/og-image.png" download>
Download OG image
</a>
const target = "https://github.com/og-image.png";
const res = await fetch(`/api/download?url=${encodeURIComponent(target)}`);
const blob = await res.blob();
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "og-image.png";
a.click();
URL.revokeObjectURL(url);
curl -L -o og.png \
"https://metasnap.vercel.app/api/download?url=https://github.com/og-image.png"
Errors
All endpoints return JSON with a detail field on failure.
| Status | Meaning | Example |
|---|---|---|
400 |
Bad request | {"detail": "URL is required"} |
500 |
Fetch failed (network, DNS, TLS, target 4xx/5xx, etc.) | {"detail": "Fetch failed: ..."} |