Read meta tags
Somewhere between the title tag and the closing head, a page carries dozens of small instructions for search engines, social platforms and browsers, and any one of them can be wrong for months before someone notices. This endpoint reads the full head section of a URL and hands back every meta, Open Graph and Twitter tag it finds, exactly as written.
Run — free
Runs in your browser. Free, unlimited — your data never leaves this page.
Why meta tags quietly break and stay broken
A canonical tag gets copy-pasted from a staging environment and never updated, a robots directive left over from a redesign accidentally blocks indexing, an Open Graph image points to a file that was deleted months ago. None of these mistakes show up when you look at the rendered page in a browser, which is exactly why they survive so long; you have to look at the raw head markup to catch them, and doing that by hand across dozens of pages is slow and error-prone, the kind of check that quietly falls off a launch checklist under deadline pressure.
What this endpoint reads
Submit a URL and get a task_id, then the full set of tags through a webhook or a signed link valid for 24 hours: title, meta description, canonical URL, robots directives, viewport, charset, every Open Graph property present (og:title, og:image, og:type and the rest), and the full Twitter Card set. Nothing is summarized or interpreted, the values come back exactly as they appear in the markup, which matters when the whole point is verifying correctness.
Tags with decades of history and still evolving
The meta description has been part of HTML since the 1990s and search engines have used it, dropped it, and reconsidered it for snippets more than once over the years. Open Graph came later, built specifically so social platforms could render a consistent card, and the Twitter Card format layered its own overlapping conventions on top. The result is a stack of tags with real history, genuine overlap, and no shortage of ways to get them subtly wrong.
A natural fit for automated QA
Because the call returns structured, comparable data, it's easy to script: run it across every page after a deploy and diff the output against a known-good baseline, or sweep an entire sitemap monthly to catch canonical tags or robots directives that drifted since the last check. That turns a task usually done by a person clicking view-source into a check that runs unattended.
What you can do with it
Post-deploy SEO regression checks
Compare meta tags across key pages before and after a release to catch an accidentally missing canonical or a blocked robots directive.
Social share QA
Verify that og:image and og:title are set correctly on new landing pages before they get shared and cached by social platforms.
Competitive and industry research
Read how competitor pages structure their titles, descriptions and Open Graph data to inform your own on-page strategy.
Site-wide metadata audits
Sweep an entire sitemap to find pages with duplicate titles, missing descriptions, or inconsistent Twitter Card tags.
FAQ
How do I extract meta tags from a page with this API?
Send a POST request to /web/metadata with the target URL; you get a task_id immediately and the full tag set arrives by webhook or a signed link once processing finishes.
Is the meta tags extractor API free?
The tool above runs free in your browser. The API is paid — each call draws from your prepaid ForHosting KIT balance: top up from $10.00 (it never expires), pay each request's published price, and a call with no balance returns HTTP 402. No subscription, no tokens, and a failed task is never charged.
Which tags does it read?
It reads the title, meta description, canonical URL, robots directives, viewport and charset, the full set of Open Graph properties, and the Twitter Card tags present in the page's head.
Does it check whether the tags are correct or just read them?
It reads and returns the raw values exactly as they appear in the markup; deciding whether a value is correct for your site is left to you or your QA logic.
Can I run it across an entire sitemap?
Yes, submit each URL as its own request and let the webhook collect results, which works well for scripted, sitemap-wide audits.
How is this different from viewing page source manually?
It returns the tags as structured data instead of raw HTML you'd have to parse yourself, which makes it practical to diff and automate at scale.
How do I receive the results?
Choose a signed webhook for automatic delivery, or fetch the output from a signed link that stays valid for 24 hours.
Is the extracted markup stored afterward?
No, results are deleted once the retention window ends and are never used to train any model.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, and soon from our app, email and Telegram.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/web/metadata \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://ejemplo.com"}'const res = await fetch("https://api.kit.forhosting.com/web/metadata", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"url": "https://ejemplo.com"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/web/metadata",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"url": "https://ejemplo.com"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/web/metadata", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"url":"https://ejemplo.com"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"url":"https://ejemplo.com"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/web/metadata", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"url": "https://ejemplo.com"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "web.metadata",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
timeout_sec | 30 |
max_crawl_pages | 25 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |