Svelte Meta Tags for Svelte 5 SEO and JSON-LD

Set Svelte SEO metadata, social cards, canonical URLs, robots directives, and schema.org JSON-LD.

Svelte Meta Tags is a Svelte component library that manages page metadata and JSON-LD structured data.

MetaTags writes titles, descriptions, canonical URLs, robots directives, Open Graph data, and Twitter cards.

SvelteKit projects can keep site defaults in a root layout and merge page-level metadata with deepMerge.

Features

  • MetaTags component for standard SEO and social metadata.
  • JsonLd component with schema-dts types for schema.org data.
  • SvelteKit helpers for layout defaults and page-level metadata.
  • Recursive metadata overrides through deepMerge.
  • Open Graph fields for basic objects, articles, books, profiles, videos, images, and audio.
  • Twitter summary, large-image, app, and player card metadata.
  • Language alternate links and mobile alternate URLs.
  • Custom meta and link tags outside the predefined property set.

How To Use It

Install svelte-meta-tags

Install the package with npm:

npm install -D svelte-meta-tags
pnpm add -D svelte-meta-tags
yarn add -D svelte-meta-tags

Optional Svelte CLI Setup

Run this command if you want the add-on to wire up MetaTags:

npx sv add @sv-addon/svelte-meta-tags

Basic Usage

Import MetaTags into a page or layout. The component writes the generated metadata to <svelte:head>.

<script lang="ts">
  import { MetaTags } from 'svelte-meta-tags';
</script>
<MetaTags
  title="Pricing"
  titleTemplate="%s | Acme"
  description="Compare Acme plans and pricing."
  canonical="https://acme.dev/pricing"
  openGraph={{
    type: 'website',
    url: 'https://acme.dev/pricing',
    title: 'Acme Pricing',
    description: 'Compare Acme plans and pricing.',
    images: [
      {
        url: 'https://acme.dev/images/pricing-og.jpg',
        width: 1200,
        height: 630,
        alt: 'Acme pricing plans'
      }
    ]
  }}
  twitter={{
    cardType: 'summary_large_image',
    site: '@acme',
    title: 'Acme Pricing',
    description: 'Compare Acme plans and pricing.',
    image: 'https://acme.dev/images/pricing-og.jpg',
    imageAlt: 'Acme pricing plans'
  }}
/>

Share Metadata Defaults Across SvelteKit Pages

defineBaseMetaTags freezes a metadata object and returns it as baseMetaTags. definePageMetaTags does the equivalent for pageMetaTags. deepMerge recursively merges nested objects, keeps the layout value when the page value is undefined, and replaces arrays in full.

+layout.ts

import { defineBaseMetaTags } from 'svelte-meta-tags';
import type { LayoutLoad } from './$types';
export const load: LayoutLoad = ({ url }) => {
  const pageUrl = new URL(url.pathname, url.origin).href;
  const baseTags = defineBaseMetaTags({
    title: 'Acme',
    titleTemplate: '%s | Acme',
    description: 'Frontend infrastructure for modern web applications.',
    canonical: pageUrl,
    openGraph: {
      type: 'website',
      url: pageUrl,
      siteName: 'Acme'
    }
  });
  return { ...baseTags };
};

+page.ts

import { definePageMetaTags } from 'svelte-meta-tags';
import type { PageLoad } from './$types';
export const load: PageLoad = () => {
  const pageTags = definePageMetaTags({
    title: 'Pricing',
    description: 'Compare Acme plans and pricing.',
    openGraph: {
      title: 'Acme Pricing',
      description: 'Compare Acme plans and pricing.'
    }
  });
  return { ...pageTags };
};

+layout.svelte

<script lang="ts">
  import { page } from '$app/state';
  import { MetaTags, deepMerge } from 'svelte-meta-tags';
  let { data, children } = $props();
  let metaTags = $derived(
    deepMerge(data.baseMetaTags, page.data.pageMetaTags)
  );
</script>
<MetaTags {...metaTags} />
{@render children()}

Add JSON-LD Structured Data

JsonLd inserts "@context": "https://schema.org" automatically. Its output prop defaults to head. Set output="body" when the script should render at the component location.

<script lang="ts">
  import { JsonLd } from 'svelte-meta-tags';
</script>
<JsonLd
  schema={{
    '@type': 'Article',
    headline: 'Managing SEO Metadata in Svelte 5',
    datePublished: '2026-09-10',
    author: {
      '@type': 'Organization',
      name: 'Acme'
    }
  }}
/>

Multiple Related Schemas

Use @graph when several related schema objects belong to one graph. A plain array is accepted.

<JsonLd
  schema={{
    '@graph': [
      {
        '@type': 'WebSite',
        name: 'Acme',
        url: 'https://acme.dev'
      },
      {
        '@type': 'Organization',
        name: 'Acme',
        url: 'https://acme.dev'
      }
    ]
  }}
/>

MetaTags Props

Three behaviors deserve attention before using the API reference. titleTemplate replaces every %s token with title and renders no <title> when title is absent. robots defaults to index,follow and renders a robots tag even when the prop is omitted. Set robots={false} to suppress that tag. A falsy robots value paired with additionalRobotsProps logs a console warning.

PropTypePurpose
titlestringPage title
titleTemplatestringTitle template with %s replacement
robotsstring | booleanRobots directives
additionalRobotsPropsAdditionalRobotsPropsExtra robots directives
descriptionstringMeta description
canonicalstringCanonical URL
keywordsReadonlyArray<string>Meta keywords
mobileAlternateMobileAlternateAlternate mobile URL and media query
languageAlternatesReadonlyArray<LanguageAlternate>Alternate language URLs
twitterTwitterTwitter card configuration
facebookFacebookFacebook App ID metadata
openGraphOpenGraphOpen Graph configuration
additionalMetaTagsReadonlyArray<MetaTag>Custom meta elements
additionalLinkTagsReadonlyArray<LinkTag>Custom link elements

Metadata Utilities

ExportPurpose
deepMerge(target, source)Recursively merges layout and page metadata
defineBaseMetaTags(obj)Freezes MetaTagsProps and returns it under baseMetaTags
definePageMetaTags(obj)Freezes MetaTagsProps and returns it under pageMetaTags

JsonLd Props

The schema prop uses schema-dts types and accepts one schema object, an array, or an @graph object.

PropTypePurpose
schemaFlexibleSchema | FlexibleSchema[] | GraphWrappedThingschema.org structured data
output"head" | "body"Script location. Default: head

Alternatives and Related Resources

FAQs

Q: Does svelte-meta-tags work outside SvelteKit?
A: Yes. MetaTags and JsonLd use Svelte head rendering and do not depend on SvelteKit internals. The +layout.ts, +page.ts, and deepMerge metadata pattern is specific to SvelteKit.

Q: Why did my default Open Graph images disappear after a page override?
A: deepMerge replaces a layout array when the page metadata defines an array for that property. Define the complete openGraph.images array in the page metadata when you override it.

Q: Do I need to add @context to JsonLd schema objects?
A: No. JsonLd automatically inserts "@context": "https://schema.org".

oekazuma

oekazuma

Web Engineer

Leave a Reply

Your email address will not be published. Required fields are marked *