Skip to main content

SEO & Discoverability

Radish-generated apps include built-in SEO infrastructure: structured data (JSON-LD), sitemap, robots.txt, analytics integration, and AI discoverability (llms.txt).

JSON-LD Structured Data

Every generated app includes src/lib/seo/json-ld.ts with schema.org helpers for rich search results.

Usage

With <JsonLd> component (recommended):

<script>
import { JsonLd, productLd, breadcrumbLd } from '@radish/components';

let { data } = $props();
</script>

<JsonLd data={productLd(data.product)} />
<JsonLd data={breadcrumbLd([
{ name: 'Home', url: '/' },
{ name: 'Products', url: '/products' },
{ name: data.product.name, url: `/products/${data.product.id}` }
])} />

With toJsonLd() helper (manual):

<script>
import { toJsonLd, productLd } from '$lib/seo/json-ld';
// or: import { toJsonLd, productLd } from '@radish/components';

let { data } = $props();
</script>

<svelte:head>
{@html toJsonLd(productLd(data.product))}
</svelte:head>

Available Helpers

FunctionSchema TypeUse For
productLd()ProductE-commerce products with price, brand, availability
articleLd()ArticleBlog posts, news articles
courseLd()CourseEducational content with instructor, pricing
organizationLd()OrganizationCompany/brand info with logo
breadcrumbLd()BreadcrumbListNavigation path for breadcrumbs
faqLd()FAQPageFAQ pages with Q&A pairs
entityLd()AnyGeneric mapper for custom entity types

Product Example

productLd({
name: 'Organic Coffee Beans',
description: 'Premium single-origin beans',
price: 24.99,
currency: 'USD',
brand: 'FairTrade',
sku: 'COF-001',
images: ['/images/coffee.jpg'],
availability: 'in_stock',
url: 'https://myshop.com/products/coffee'
})

Generic Entity Mapper

For entities without a specific helper, entityLd() auto-maps common field names:

import { toJsonLd, entityLd } from '$lib/seo/json-ld';

// Maps: name→name, description→description, price→price,
// imageUrl→image, createdAt→dateCreated, etc.
const ld = entityLd(data.course, 'Course');
Entity FieldSchema.org Property
name, titlename
descriptiondescription
priceprice
image, imageUrl, thumbnailUrlimage
createdAtdateCreated
publishedAtdatePublished
updatedAtdateModified
author, authorNameauthor

Custom field mappings:

entityLd(record, 'Recipe', {
cookTime: 'cookTime',
ingredients: 'recipeIngredient'
})

Sitemap

Generated at /sitemap.xml as a dynamic SvelteKit endpoint. Edit src/routes/sitemap.xml/+server.ts to add pages:

const staticPages = [
{ path: '/', changefreq: 'daily', priority: '1.0' },
{ path: '/about', changefreq: 'monthly', priority: '0.5' },
];

// Add database-driven pages:
const products = await new ProductService(systemAuth()).list({ limit: 1000 });
for (const p of products.items) {
staticPages.push({ path: `/products/${p.id}`, changefreq: 'weekly', priority: '0.7' });
}

Robots.txt

Generated at /robots.txt as a dynamic endpoint. Includes sitemap reference. Edit src/routes/robots.txt/+server.ts to add rules.

Google Analytics

Set GOOGLE_ANALYTICS_ID in .env:

GOOGLE_ANALYTICS_ID=G-XXXXXXXXXX

Initialize in your root layout:

<script>
import { onMount } from 'svelte';
import { initAnalytics } from '$lib/analytics';

onMount(() => initAnalytics());
</script>

Track custom events:

import { trackEvent } from '$lib/analytics';
trackEvent('purchase', { value: 29.99, currency: 'USD' });

AI Discoverability (llms.txt)

Generated at /llms.txt — describes the app for AI assistants. Edit src/routes/llms.txt/+server.ts to customize.

See llmstxt.org for the specification.