# Page metadata in one request

> Extract the title, description, Open Graph tags, JSON-LD, emails and phone numbers of any URL with one API call. $0.001 per page, errors free.

Add includeMetadata=true to any request and get the metadata of the page as JSON: title, description, language, canonical URL, Open Graph tags, JSON-LD, links, emails and phone numbers.

- $1 free credit, no card
- No subscription
- Failed requests are free

[Get API key](https://dashboard.grabber.sh/signup) · [Read the docs](https://grabber.sh/docs/parameters)

## One request, structured metadata

Metadata comes in the JSON envelope, next to the format you ask for.

- JSON-LD parsed into objects
- Every Open Graph tag
- No extra charge

### cURL

```bash
curl -G https://api.grabber.sh/fetch \
  -H "Authorization: Bearer $GRABBER_API_KEY" \
  --data-urlencode "url=https://shop.example.com/products/trail-runner-2" \
  -d "formats=links" \
  -d "includeMetadata=true"
```

### Python

```python
import os
import requests

response = requests.get(
    "https://api.grabber.sh/fetch",
    params={"url": "https://shop.example.com/products/trail-runner-2", "formats": "links", "includeMetadata": "true"},
    headers={"Authorization": f"Bearer {os.environ['GRABBER_API_KEY']}"},
    timeout=130,
)
response.raise_for_status()
print(response.text)
```

### Node.js

```javascript
const params = new URLSearchParams({ url: 'https://shop.example.com/products/trail-runner-2', formats: 'links', includeMetadata: 'true' })

const response = await fetch(`https://api.grabber.sh/fetch?${params}`, {
  headers: { Authorization: `Bearer ${process.env.GRABBER_API_KEY}` },
  signal: AbortSignal.timeout(130_000),
})
if (!response.ok) throw new Error(`Grabber answered ${response.status}`)
console.log(await response.text())
```

### Go

```go
package main

import (
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"time"
)

func main() {
	query := url.Values{"url": {"https://shop.example.com/products/trail-runner-2"}, "formats": {"links"}, "includeMetadata": {"true"}}
	req, _ := http.NewRequest("GET", "https://api.grabber.sh/fetch?"+query.Encode(), nil)
	req.Header.Set("Authorization", "Bearer "+os.Getenv("GRABBER_API_KEY"))

	client := &http.Client{Timeout: 130 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)
	fmt.Println(res.Status)
	fmt.Println(string(body))
}
```

### PHP

```php
<?php
$query = http_build_query(['url' => 'https://shop.example.com/products/trail-runner-2', 'formats' => 'links', 'includeMetadata' => 'true']);

$ch = curl_init("https://api.grabber.sh/fetch?$query");
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('GRABBER_API_KEY')],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 130,
]);
$body = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE), "\n", $body;
```

### Response (data.metadata)

```json
{
  "canonicalUrl": "https://shop.example.com/products/trail-runner-2",
  "title": "Trail Runner 2 | Example Shop",
  "description": "A 240 g trail shoe with a grippy outsole.",
  "languageCode": "en",
  "openGraph": [
    {
      "property": "og:image",
      "content": "https://shop.example.com/img/tr2.jpg"
    }
  ],
  "jsonLd": [
    {
      "@type": "Product",
      "name": "Trail Runner 2",
      "offers": {
        "price": "129.00",
        "priceCurrency": "USD"
      }
    }
  ],
  "emails": [
    "support@example.com"
  ]
}
```

## How it works

1. **Send the URL.** Call `GET /fetch` with `url`, `includeMetadata=true` and the format you also want.
2. **Grabber reads the page.** It loads the page and reads its meta tags, Open Graph tags and JSON-LD blocks, and finds emails and phone numbers.
3. **Use the fields.** Every field is always present: a value the page does not have is null or an empty list.

## What people build with it

### Link previews

Show a title, description and image for any URL your users paste.

### Product data

Read prices, names and availability from the Product JSON-LD that shops publish.

### Directories and CRMs

Fill in the name, description and contact details of a company from its own site.

### SEO checks

Find pages with a missing description, a wrong canonical URL or broken structured data.

## Pricing

Prepaid credit, taken one request at a time. Ask for several formats in one request at the price of one.

| Request | Price |
| --- | --- |
| A page | **$0.001** |
| A page with `js_render=true` | **$0.005** |
| Any error | $0 |
| Credit when you sign up | $1, about 1,000 pages |

## Questions

### Which fields do I get?

canonicalUrl, title, description, author, keywords, languageCode, openGraph, jsonLd, links, phones and emails. Every field is always there; one the page does not have is null or an empty list.

### Is the JSON-LD parsed?

Yes. Each JSON-LD block on the page comes back as a JSON object, ready to read.

### Does metadata cost extra?

No. It is part of the same page load, so a request with metadata costs $0.001, like any other.

### Can I use it with unwrap=true?

No. Metadata lives in the JSON envelope, so includeMetadata is ignored when unwrap is true. Leave unwrap off and read data.metadata.

## Related

- [Link extractor](https://grabber.sh/link-extractor): Every link on a page, as absolute URLs.
- [URL to Markdown](https://grabber.sh/url-to-markdown): Clean Markdown for LLMs and RAG.
- [HTML to text](https://grabber.sh/html-to-text): Plain text with no markup at all.
- [All parameters](https://grabber.sh/docs/parameters): Every option of GET /fetch.

## Give your agents the web

Sign up in a minute and fetch your first 1,000 pages for free.

[Get API key](https://dashboard.grabber.sh/signup) · [Read the docs](https://grabber.sh/docs)
