SEO Module
The SEO module provides comprehensive tools for adding search engine optimization metadata to your FastHTML applications. It includes components for meta tags, Open Graph, Twitter Cards, and structured data (JSON-LD).
SEO vs PageMeta
Faststrap provides both SEO(...) and PageMeta(...) intentionally.
SEO(...) is the low-level SEO builder
Use it when you want direct control over SEO and social metadata only.
PageMeta(...) is the high-level head composer
Use it when you want one call that can combine:
- SEO tags
- canonical handling
- optional PWA tags
- optional favicon links
- dedupe guarantees
Quick decision
- Need only SEO/social tags: use
SEO(...). - Need full head composition with less boilerplate: use
PageMeta(...). - Need JSON-LD schema: use
StructuredData.*(...)with eitherSEO(...)orPageMeta(...).
Quick Start
from fasthtml.common import *
from faststrap import SEO, StructuredData, PageMeta
app = FastHTML()
@app.get("/")
def home():
return (
SEO(
title="My Site - Welcome",
description="The best site on the internet",
image="/assets/og-image.jpg",
url="https://mysite.com/"
),
Container(
H1("Welcome!"),
)
)
Alternative quick start with PageMeta
@app.get("/")
def home():
return (
PageMeta(
title="My Site - Welcome",
description="The best site on the internet",
canonical="https://mysite.com/",
include_pwa=True,
pwa_name="My Site",
pwa_short_name="MySite",
),
Container(H1("Welcome!")),
)
Components
SEO()
The main component for generating SEO meta tags.
Parameters:
title(str): Page title (also used for og:title and twitter:title)description(str): Page descriptionkeywords(list[str]): List of keywordsimage(str): Image URL for social sharingurl(str): Canonical URLog_type(str): Open Graph type ("website", "article", "product")article(bool): If True, adds article-specific meta tagspublished_time(str): Article published time (ISO 8601)modified_time(str): Article modified time (ISO 8601)author(str): Article author namesection(str): Article section/categorytags(list[str]): Article tagstwitter_card(str): Twitter card typetwitter_site(str): Twitter site handle (@username)twitter_creator(str): Twitter creator handlerobots(str): Robots meta tag value (default: "index, follow")canonical(str): Canonical URL (if different from url)locale(str): Page locale (e.g., "en_US")alternate_locales(list[str]): List of alternate locales
Returns: Tuple of meta tag elements to include in page head
StructuredData
Helper class for generating Schema.org structured data in JSON-LD format.
Methods
StructuredData.article()
Generate Article structured data.
StructuredData.article(
headline="Blog Post Title",
description="Post description",
image="https://example.com/image.jpg",
author="John Doe",
published="2026-02-12T10:00:00Z",
modified="2026-02-12T14:30:00Z"
)
StructuredData.product()
Generate Product structured data.
StructuredData.product(
name="Product Name",
description="Product description",
image="https://example.com/product.jpg",
price="99.99",
currency="USD",
rating=4.5,
review_count=127,
availability="InStock"
)
StructuredData.breadcrumb()
Generate BreadcrumbList structured data.
StructuredData.breadcrumb([
("Home", "https://example.com/"),
("Products", "https://example.com/products"),
("Item", "https://example.com/products/item")
])
StructuredData.organization()
Generate Organization structured data.
StructuredData.organization(
name="Company Name",
url="https://example.com",
logo="https://example.com/logo.png",
social_links=[
"https://twitter.com/company",
"https://linkedin.com/company/company"
]
)
StructuredData.local_business()
Generate LocalBusiness structured data.
StructuredData.local_business(
name="Business Name",
address={
"street": "123 Main St",
"city": "Springfield",
"state": "IL",
"zip": "62701",
"country": "US"
},
phone="+1-555-123-4567",
hours={
"Monday-Friday": "9:00-17:00",
"Saturday": "10:00-14:00",
"Sunday": "10:00-14:00"
}
)
Usage Examples
Basic Page SEO
@app.get("/")
def home():
return (
SEO(
title="My Site - Home",
description="Welcome to my site",
keywords=["python", "fasthtml", "web"],
image="/assets/og-image.jpg",
url="https://mysite.com/"
),
Container(H1("Home"))
)
Blog Post with Article SEO
@app.get("/blog/{slug}")
def blog_post(slug: str):
post = get_post(slug)
return (
SEO(
title=f"{post.title} - My Blog",
description=post.excerpt,
image=post.featured_image,
url=f"https://mysite.com/blog/{slug}",
article=True,
published_time=post.published_at,
modified_time=post.updated_at,
author=post.author,
section="Technology",
tags=post.tags,
twitter_site="@myblog",
twitter_creator="@author"
),
StructuredData.article(
headline=post.title,
description=post.excerpt,
image=post.featured_image,
author=post.author,
published=post.published_at,
modified=post.updated_at
),
Container(
H1(post.title),
Div(post.content)
)
)
E-commerce Product Page
@app.get("/product/{id}")
def product_page(id: str):
product = get_product(id)
return (
SEO(
title=f"{product.name} - Buy Online",
description=product.description,
image=product.images[0],
url=f"https://mysite.com/product/{id}",
og_type="product",
twitter_site="@mystore"
),
StructuredData.product(
name=product.name,
description=product.description,
image=product.images[0],
price=str(product.price),
currency="USD",
rating=product.avg_rating,
review_count=product.review_count,
availability="InStock" if product.in_stock else "OutOfStock"
),
Container(
H1(product.name),
P(product.description)
)
)
Local Business Page
@app.get("/")
def home():
return (
SEO(
title="Joe's Coffee - Best Coffee in Town",
description="Visit Joe's Coffee for the best coffee in Springfield",
image="/assets/shop.jpg",
url="https://joescoffee.com/"
),
StructuredData.local_business(
name="Joe's Coffee Shop",
address={
"street": "123 Main St",
"city": "Springfield",
"state": "IL",
"zip": "62701",
"country": "US"
},
phone="+1-555-123-4567",
hours={
"Monday-Friday": "7:00-19:00",
"Saturday": "8:00-17:00",
"Sunday": "8:00-17:00"
}
),
Container(H1("Joe's Coffee"))
)
Multi-language Site
@app.get("/es/about")
def about_es():
return (
SEO(
title="Acerca de Nosotros",
description="Información sobre nuestra empresa",
url="https://example.com/es/about",
locale="es_ES",
alternate_locales=["en_US", "fr_FR"]
),
Container(H1("Acerca de Nosotros"))
)
Generated HTML
Basic Meta Tags
<title>Page Title</title>
<meta name="title" content="Page Title">
<meta name="description" content="Page description">
<meta name="keywords" content="keyword1, keyword2, keyword3">
<meta name="robots" content="index, follow">
<link rel="canonical" href="https://example.com/page">
Open Graph Tags
<meta property="og:title" content="Page Title">
<meta property="og:description" content="Page description">
<meta property="og:image" content="https://example.com/image.jpg">
<meta property="og:url" content="https://example.com/page">
<meta property="og:type" content="website">
<meta property="og:locale" content="en_US">
Twitter Card Tags
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Page Title">
<meta name="twitter:description" content="Page description">
<meta name="twitter:image" content="https://example.com/image.jpg">
<meta name="twitter:site" content="@sitehandle">
Article Tags
<meta property="og:type" content="article">
<meta property="article:published_time" content="2026-02-12T10:00:00Z">
<meta property="article:modified_time" content="2026-02-12T14:30:00Z">
<meta property="article:author" content="John Doe">
<meta property="article:section" content="Technology">
<meta property="article:tag" content="python">
<meta property="article:tag" content="fasthtml">
Structured Data (JSON-LD)
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Blog Post Title",
"description": "Post description",
"image": "https://example.com/image.jpg",
"author": {
"@type": "Person",
"name": "John Doe"
},
"datePublished": "2026-02-12T10:00:00Z",
"dateModified": "2026-02-12T14:30:00Z"
}
</script>
Best Practices
1. Always Include Basic SEO
Every page should have at minimum:
- Title
- Description
- Canonical URL
SEO(
title="Page Title - Site Name",
description="Page description (150-160 characters)",
url="https://example.com/page"
)
2. Use Descriptive Titles
- Keep titles under 60 characters
- Include your brand name
- Make titles unique per page
3. Write Compelling Descriptions
- Keep descriptions 150-160 characters
- Include target keywords naturally
- Make them actionable
description="Learn 10 essential Python tips to write cleaner code. Perfect for beginners and experienced developers."
4. Use High-Quality Images
- Use images at least 1200x630px for social sharing
- Use absolute URLs for images
- Optimize images for fast loading
image="https://example.com/assets/og-image.jpg" # Good
image="/assets/og-image.jpg" # Works, but absolute is better
5. Add Structured Data
Use structured data for:
- Blog posts (Article)
- Products (Product)
- Local businesses (LocalBusiness)
- Organizations (Organization)
6. Test Your SEO
Use these tools to validate:
API Reference
See the SEO API documentation for complete parameter details and return types.
Examples
See the examples directory for complete working examples.