Svelte SEO is a component library that manages meta tags, Open Graph properties, Twitter Cards, and JSON-LD structured data in Svelte applications.
It handles the configuration of HTML head elements to optimize pages for search engines and social media platforms.
You can use the library to configure everything from basic title and description tags to complex Open Graph images and JSON-LD schemas.
The package supports multiple social platforms and structured data formats. It handles the technical details of meta tag implementation so you can focus on content strategy and page structure.
Features
🔧 Meta Tag Management: Handles title, description, keywords, canonical URLs, and other standard HTML meta elements for search engine indexing.
🌐 Open Graph Support: Configures Facebook and social media sharing previews with properties for titles, descriptions, images, videos, and content types like articles, profiles, and media.
🐦 X(Twitter) Card Integration: Generates Twitter-specific meta tags for summary cards, large image cards, player cards, and app cards with proper sizing and attribution.
📱 Progressive Web App Metadata: Manages PWA-related tags like manifest links, theme colors, and application names for installable web apps.
🔍 JSON-LD Structured Data: Implements schema.org markup for rich search results with support for websites, articles, organizations, products, and other entity types.
🌍 Multi-Language Configuration: Handles alternate language tags and locale specifications for international sites with multiple language versions.
🎯 Per-Page Customization: Applies default SEO properties across all pages while allowing overrides for specific routes and content types.
🔗 Application Indexing Control: Prevent staging or admin environments from appearing in search results using noindex flags.
Use Cases
- E-commerce Product Pages: Configure unique Open Graph images, structured product data, and Twitter Cards for each product listing to improve social sharing and search visibility.
- Content Marketing Sites: Set up article-specific metadata with JSON-LD markup for authors, publication dates, and categories to qualify for rich snippets in search results.
- Multi-Language Applications: Define language alternates and locale-specific metadata for international audiences with proper hreflang tags and regional Open Graph properties.
- Progressive Web Apps: Configure manifest links, theme colors, and app metadata consistently across your SvelteKit application for proper installation behavior.
How to Use It
1. Install the package using your preferred package manager.
npm install -D svelte-seo
# or
yarn add -D svelte-seo
# or
pnpm add -D svelte-seo2. Import the component inside your Svelte file. You can then place the <SvelteSeo /> component anywhere in your markup. It injects the necessary tags into the <head> of the document.
<script>
import SvelteSeo from "svelte-seo";
</script>
<SvelteSeo
title="Dashboard | My App"
description="View your analytics and account settings."
canonical="https://myapp.com/dashboard"
/>3. For pages that require rich social previews and structured data, pass objects to the openGraph, twitter, and jsonLd props. This example sets up a blog post with a summary card for Twitter and article data for Google.
<script>
import SvelteSeo from "svelte-seo";
const post = {
title: "Understanding Svelte Stores",
summary: "A deep dive into state management in Svelte.",
slug: "understanding-svelte-stores",
image: "https://myapp.com/images/stores-banner.jpg"
};
</script>
<SvelteSeo
title={post.title}
description={post.summary}
openGraph={{
title: post.title,
description: post.summary,
url: `https://myapp.com/blog/${post.slug}`,
type: "article",
images: [
{
url: post.image,
width: 800,
height: 600,
alt: "Svelte Stores Diagram",
},
],
site_name: "My Tech Blog",
}}
twitter={{
card: "summary_large_image",
site: "@mytechblog",
title: post.title,
description: post.summary,
image: post.image,
imageAlt: "Svelte Stores Diagram",
}}
jsonLd={{
"@context": "https://schema.org",
"@type": "BlogPosting",
headline: post.title,
image: [post.image],
datePublished: "2023-10-15T08:00:00+08:00",
author: {
"@type": "Person",
name: "Jane Doe"
}
}}
/>4. You can enforce default SEO settings by adding the component to your root layout file (e.g., +layout.svelte in SvelteKit). Properties defined here persist across all pages unless a specific page overrides them.
<!-- src/routes/+layout.svelte -->
<script>
import SvelteSeo from "svelte-seo";
</script>
<SvelteSeo
title="My Default Title"
description="Default description for the application."
openGraph={{
site_name: "My App Name",
type: "website"
}}
twitter={{
site: "@myapp",
card: "summary"
}}
/>
<slot />5. The <SvelteSeo /> component accepts the following SEO properties.
| Property | Type | Description |
|---|---|---|
title | string | A page title that will appear in search results. |
description | string | A page description that will appear in search results. |
keywords | string | Keywords that give search engines more information about the content of the page. |
base | string | A default URL and target for all links on a page. |
applicationName | string | The name of the web application that the page represents. |
themeColor | string | A suggested color that user agents should use to customize the display of the page. |
nofollow | boolean | Prevents Googlebot from following any links on the page. Default is false. |
noindex | boolean | Prevents the page from being included in the index. Default is false. |
nositelinkssearchbox | boolean | Opt out of Google’s Sitelinks search box. Default is false. |
notranslate | boolean | Prevents Google from translating the page. |
canonical | string | The canonical URL of the page. |
amp | string | A URL to the AMP version of the webpage. |
manifest | string | The URL to a JSON file that tells the browser about your Progressive Web App. |
languageAlternates | Array | Provides Google with information about the variations of your content in other languages. |
twitter.title | string | The title of the content, maximum 70 characters. |
twitter.description | string | A description of the content, maximum 200 characters. |
twitter.image | string | The URL of an image to use in the Twitter card. Images must be less than 5MB. |
twitter.imageAlt | string | A text description of the image for visually impaired users. Max 420 characters. |
twitter.card | string | The type of Twitter card: summary, summary_large_image, player, or app. |
twitter.site | string | The @username of the website. |
twitter.creator | string | The @username of the content creator. |
twitter.player | string | The HTTPS URL of the player iframe. |
twitter.playerWidth | string | The width of the iframe in pixels. |
twitter.playerHeight | string | The height of the iframe in pixels. |
twitter.playerStream | string | The URL to the raw video or audio stream. |
twitter.appNameIphone | string | The name of your iPhone app. |
twitter.appUrlIphone | string | The custom URL scheme for your app on iPhone. |
twitter.appNameIpad | string | The name of your iPad-optimized app. |
twitter.appIdIpad | string | Your app’s ID in the iTunes App Store. |
twitter.appNameGoogleplay | string | The name of your Android app. |
twitter.appIdGoogleplay | string | Your app’s ID in the Google Play Store. |
twitter.appUrlGoogleplay | string | The custom URL scheme for your app on Google Play. |
facebook.appId | string | A unique number that identifies your app (Facebook App ID). |
openGraph.title | string | The title of your object as it should appear within the graph. |
openGraph.type | string | The type of your object (e.g., “video.movie”). |
openGraph.url | string | The canonical URL of your object used as its permanent ID. |
openGraph.audio | string | An audio file to accompany the content. |
openGraph.audioSecure_url | string | An alternate URL to use if the webpage requires HTTPS. |
openGraph.audioType | string | The MIME type for the audio. |
openGraph.description | string | A one- or two-sentence description of your object. |
openGraph.determiner | string | The word that appears before the title, e.g., “the” or “a”. |
openGraph.locale | string | The locale of the content, e.g., “en_US”. |
openGraph.localeAlternate | string[] | Alternate locales for the content. |
openGraph.site_name | string | The name of the website where the content is hosted. |
openGraph.images | Array | Properties about images related to the web page. |
openGraph.videos | Object | Properties about videos related to the web page. |
openGraph.music | Object | OpenGraph for music files. |
openGraph.movie | Object | OpenGraph for a movie. |
openGraph.article | Object | OpenGraph for an article. |
openGraph.book | Object | OpenGraph for a book. |
openGraph.profile | Object | OpenGraph for a profile. |
jsonLd | Object | JSON-LD structured data object. |
Related Resources
- Next SEO: Manages meta tags and structured data for Next.js applications with similar configuration patterns.
- Svelte Meta Tags: Handles meta tag injection in Svelte with a different API approach.
- React Helmet: Controls document head elements in React applications with dynamic updates.
FAQs
Q: Can I set different SEO properties for each page in SvelteKit?
A: Yes. Place the SvelteSeo component in individual page files with specific properties. These override any defaults you set in layout files. Each route can have unique metadata.
Q: How do I test that my Open Graph tags work correctly?
A: Use the Facebook Sharing Debugger at developers.facebook.com/tools/debug or the Twitter Card Validator. These tools show exactly how your pages will appear when shared and report any configuration errors.
Q: Does this package work with static site generation in SvelteKit?
A: Yes. The meta tags render during the build process when you use static adapter settings. The generated HTML includes all configured metadata without client-side JavaScript execution.
Q: Can I use multiple JSON-LD schemas on the same page?
A: Yes. Create multiple SvelteSeo components with different jsonLd objects or combine multiple schema types in a single object using an array structure at the root level.
Q: What happens if I set both default and page-specific values for the same property?
A: The page-specific value takes precedence. When you declare a property in a page component, it replaces the default value from your layout entirely rather than merging with it.


