---
title: SEO & Meta Tags
description: Best practices for search engine optimization with PageWeave — meta tags, Open Graph, structured data, and indexing.
section: Overview
order: 4
---

# SEO & Meta Tags

PageWeave generates the essential platform-level `<head>` elements automatically (`<meta charset>`, `<meta viewport>`, CSS). You provide the content-specific metadata.

## Basic SEO Checklist

For every public page, set these elements:

| Element | Tool | Required |
|---------|------|----------|
| `<title>` | `list_pages, get_page, create_page, update_page, delete_page` — `title` param | Yes |
| `<meta name="description">` | `get_html_head, update_html_head` | Yes |
| `<html lang>` | `list_websites, get_website, create_website, update_website` or `list_pages, get_page, create_page, update_page, delete_page` — `language` param | Yes |
| favicon | `get_html_head, update_html_head` | Recommended |

## Favicon

Upload via `list_assets, upload_asset` (PNG/SVG/ICO, 32x32px minimum). Add via `update_html_head`:

```html
<link rel="icon" type="image/png" href="/assets/favicon.png">
```

For broader browser support, include multiple sizes:

```html
<link rel="icon" type="image/svg+xml" href="/assets/favicon.svg">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon-32x32.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/apple-touch-icon.png">
```

## Meta Description

Concise summary, 150-160 characters. Used in search result snippets.

```html
<meta name="description" content="Artisan bakery in Berlin. Fresh sourdough, croissants, and custom cakes. Open daily 7-22.">
```

## Open Graph (Facebook, LinkedIn, etc.)

```html
<meta property="og:title" content="Sweet Crumbs Bakery">
<meta property="og:description" content="Artisan bakery in Berlin. Fresh sourdough daily.">
<meta property="og:image" content="https://example.com/assets/og-image.jpg">
<meta property="og:type" content="website">
<meta property="og:url" content="https://sweet-crumbs.pageweave.site/">
```

- `og:image` — 1200 x 630px JPEG/PNG recommended. Use `list_assets, upload_asset` to upload.
- `og:type` — `website` for pages, `article` for blog posts.

## Twitter Cards

```html
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Sweet Crumbs Bakery">
<meta name="twitter:description" content="Artisan bakery in Berlin.">
<meta name="twitter:image" content="https://example.com/assets/og-image.jpg">
```

## Canonical URLs

Prevent duplicate content issues:

```html
<link rel="canonical" href="https://sweet-crumbs.pageweave.site/menu/">
```

## Robots Meta

Control indexing per-page:

```html
<meta name="robots" content="noindex, nofollow">
```

Use `update_page_settings` to set `indexable: false` on a specific page. The page still renders normally for visitors, but search engines are asked not to index it, it is excluded from the sitemap, and it is omitted from auto-generated `/llms.txt`.

You can also control indexing for the entire site via the website-level `indexable` flag.

## JSON-LD Structured Data

Help search engines understand your content:

```html
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "LocalBusiness",
  "name": "Sweet Crumbs",
  "description": "Artisan bakery in Berlin",
  "url": "https://sweet-crumbs.pageweave.site/",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "Example Str. 1",
    "addressLocality": "Berlin",
    "postalCode": "10115",
    "addressCountry": "DE"
  }
}
</script>
```

## Website Indexing

Control whether search engines can index the entire site:

- **`indexable: true`** (default) — Search engines may crawl and index.
- **`indexable: false`** — Site is excluded from search results. PageWeave serves `X-Robots-Tag: noindex` on all pages.

Set via `list_websites, get_website, create_website, update_website(action: "update", update: { website: "...", indexable: true })`. Set per-page via `update_page_settings(website: "...", path: "/about", indexable: false)`.

## Language & Hreflang

Set the default language at the website level:

```
list_websites, get_website, create_website, update_website(action: "update", update: { website: "...", language: "de" })
```

Override per-page:

```
list_pages, get_page, create_page, update_page, delete_page(action: "create", website: "...", create: { path: "/en/about", html: "...", language: "en" })
```

For multilingual sites, add hreflang links via `update_html_head`:

```html
<link rel="alternate" hreflang="de" href="https://example.com/de/">
<link rel="alternate" hreflang="en" href="https://example.com/en/">
<link rel="alternate" hreflang="x-default" href="https://example.com/">
```

For the complete internationalization guide — URL strategy, language switchers, RTL support, per-locale SEO, and scalable translation patterns — see [Internationalization (i18n)](/docs/i18n).

## Implementation

Use `update_html_head(replacements: [{ old_html: "", new_html: "...", mode: "append" }])` to add meta tags. The platform appends your extras after its own generated elements.

**Do NOT add:** `<meta viewport>`, `<meta charset>` — these are handled automatically.

## Assets for Social Sharing

Upload Open Graph images via `list_assets, upload_asset` or `request_upload_url`. Use the `relative_url` from the response in your `og:image` and `twitter:image` tags. The original URL auto-serves WebP/AVIF to browsers that support it.
