Library / SDK
artiebits/svelte-seo avatar
artiebits/svelte-seo

svelte-seo: one component for meta tags, Open Graph and JSON-LD

Optimize your website for search engines and social media with meta tags, Open Graph, and JSON-LD.

564 stars24 forksJavaScriptMIT

At a glance

What is it?
svelte-seo is a Svelte component that emits the head tags a page needs for search engines and social previews, covering meta tags, Open Graph, Twitter Card and JSON-LD, with Svelte 5 as the peer dependency. It is MIT licensed and deliberately thin, which means the sitemap and the crawlability of the rendered output are your problem, not the library's.
Who is it for?
svelte-seo fits a Svelte or SvelteKit team that wants one component to emit the head tags a page needs, with Open Graph and Twitter Card handled in the same place, and that wants JSON-LD emitted from typed objects rather than by hand.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the component actually renders

svelte-seo is a package for optimizing a Svelte app for search engines and social media with meta tags, Open Graph and JSON-LD, and the project describes it as a powerful and easy to use package that improves a website's visibility and ranking in search results.

The basic usage is a component with two properties:

svelte
<script>
  import SvelteSeo from "svelte-seo";
</script>

<SvelteSeo
  title="Simple page title"
  description="Simple description about a page"
/>

That is the whole contract for a simple page. A title and a description, rendered into the document head, and the search engine and the social card both get what they need.

The component is imported as the default export, and the package exports map shows the shape of the distribution. The exports field points at dist/index.d.ts for types and dist/index.js under the svelte condition, and the files field publishes only dist, so what ships is the built package rather than the source.

The audience is Svelte developers who keep retyping the same head tags across routes and want one component to own them, and the project asks for sponsorship to keep the maintenance going.

The property list and the crawler directives

The property table is the real reference, and it mixes three different kinds of option that a user should think about differently.

The first group is descriptive metadata for search results. The title is a page title that will appear in search results, the description is a page description that will appear in search results, and the keywords are keywords that give search engines more information about the content of the page. The canonical is the canonical URL of the page, and the base is a default URL and target for all links on a page. The applicationName is the name of the web application that the page represents, and the themeColor is a suggested color that user agents should use to customize the display of the page or the surrounding user interface. The amp property is a URL to the AMP version of the webpage.

The second group is crawler instructions, and these are booleans that default to false. nofollow prevents Googlebot from following any links on the page. noindex prevents the page from being included in the index. nositelinkssearchbox opts out of Google's Sitelinks search box, and notranslate prevents Google from translating the page.

The third group is the social card configuration, which is covered in its own section below.

The booleans deserve a note. A default of false means the tags are absent unless you ask for them, so a page is indexable and followable by default, which is the safe default for a site. But a page that needs to be hidden from search needs the explicit flag, and a staging deployment of a public site is exactly where that flag is easy to forget. The component will not warn you either way.

Open Graph, Twitter Card and Facebook, and the multi platform property

The advanced usage passes nested objects for the social platforms, and the shape of those objects is where most of the real work happens.

The openGraph object carries its own title, description, image, url, type and site_name, plus an images array where each entry has a url, a width, a height and an alt. Those image dimensions are not decoration. A social crawler that receives a single image with no declared size has to guess the aspect ratio, and the platforms use different rules for a small card and a large one, so an image entry without width and height is a card that may render cropped.

The twitter object carries a card, a site handle, a title, a description and an image, with the card value in the example set to summary_large_image. The card type is the switch that decides how much of the image the platform shows, and picking summary when you have a wide image is the usual way a link preview looks wrong.

The facebook object in the example carries only an appId, which is the piece Facebook needs for its own crawler to be able to fetch and verify the image.

The interesting design decision is that these are separate props with separate shapes rather than one set of tags that gets copied into three formats. The trade is that you write the title and the description twice, once for the page and once for each social platform, in exchange for being able to set the image and the alt text per platform. For a site where every page shares a template, that duplication is per page and per platform, and it is the cost you pay for the control.

The example also shows a subtlety worth copying. The openGraph images array in the documentation is a set of four images, and the fourth entry has a url and an alt but no width or height, while the first three have both. That mirrors how these cards are actually specified in practice, with a primary image that is fully described and secondary images that are not.

JSON-LD and setting defaults once

JSON-LD is the structured data half of the package, and it is the part that carries the most configuration surface.

The dependency list in the manifest is a single package, schema-dts at ^1.1.5, which is the schema.org type definitions. That is the mechanism behind the JSON-LD support: the structured data you emit is typed against the schema.org vocabulary rather than being free-form JSON, so a typo in a type name is a type error rather than a silently ignored field.

The properties are grouped by platform, with dedicated sections for Open Graph, Twitter, Facebook and JSON-LD in the documentation table of contents, and a separate section on setting default SEO properties. The defaults matter because the same title and description usually appear on every route of a site, and a site-wide default that a page can override is a different arrangement from repeating the props on every component.

What the documentation does not cover, and what you should find out before relying on it, is the shape of the JSON-LD prop itself and how the schema.org types are exposed. The presence of schema-dts as a runtime dependency tells you the types are shipped rather than only used at build time, and the accompanying documentation site is where the detail lives.

One practical consequence of emitting JSON-LD from a component is worth planning for. Because the structured data is derived from your page props, a page that renders different content in different states can emit a schema that disagrees with what the visitor sees, and a crawler that fetches the page without running the script sees no schema at all. That is a rendering consideration, not a library limitation, but it decides whether the JSON-LD is worth having.

Building, testing and the Svelte 5 peer dependency

The package is developed as a SvelteKit library project, and the scripts in the manifest describe the workflow.

Building is svelte-kit sync followed by svelte-package, and there is a prepublishOnly hook that runs the build. Type checking is svelte-kit sync with svelte-check against the jsconfig.json, with a watch variant. Tests are run with playwright, and linting is prettier --check with eslint, with a format script for the other direction.

The dependency versions say a lot about the current state of the toolchain. Svelte is at ^5.38.2 in dev dependencies, @sveltejs/kit at ^2.36.1, and @sveltejs/package at 2.5.0, and Vite is at ^8.0.0. The peer dependency is svelte 5, which is the important one, because that is the constraint a consuming application has to satisfy. A project still on Svelte 4 cannot use this version.

The repo also carries a .husky/ directory and lint-staged configuration, with a per-extension rule: .svelte files go through prettier, and .js and .svelte files go through eslint with a cache and a fix flag. There is a .prettierignore and an eslint.config.js, plus svelte.config.js and vite.config.js.

The test story is the part to note. The tests are Playwright tests, not unit tests, which is the right shape for a component whose entire output is the document head, since what you want to assert is what a crawler sees in the rendered HTML rather than what a component tree contains.

Where svelte-seo is the wrong choice

The first limit is the scope, which is the page head and nothing else. There is no sitemap generation, no robots.txt handling, no canonical URL auditing across routes, no hreflang, and no per route configuration file. If your problem is that a crawler cannot find your pages, this component does not address it.

The second is the dependency on server side rendering for the tags to mean anything. The keywords list ssr, and the reason is straightforward: a crawler that fetches your HTML and finds no meta tags does not run your JavaScript to discover them. A purely client-side rendered Svelte application therefore gains nothing from this component, no matter how it is configured. That is a hard deployment constraint, and it decides the question before any of the features do.

The third is that the per platform duplication is real. The advanced example writes the title three times and the description three times, once for the page, once for Open Graph and once for Twitter. For a site where the social copy differs meaningfully from the search copy that is the right shape, and for a site where they are the same string it is repetition that can drift out of sync, because nothing enforces that the two stay equal.

The fourth is that the package is small by design. One runtime dependency, one component, and a set of props. That is a virtue when you want exactly this, and a limitation when you want a whole SEO layer with a config file, a route table and a build step.

Compare that with the alternative of putting the head tags in your own layout component. The difference in approach is that a layout component gives you total control, no dependency, and no props to keep in sync, while svelte-seo gives you the tags for the supported platforms already assembled, at the cost of a dependency and a version constraint on Svelte 5.

Licence, release cadence and what to verify before you ship it

svelte-seo is released under the MIT licence, with the licence field in the package manifest set to MIT and the text in the LICENSE file at the repository root. The MIT terms permit use, modification and redistribution including inside a commercial application, provided the copyright notice and licence text are kept with copies, and you should read the LICENSE file yourself for the exact wording.

The release history is a steady 2.x line: v1.7.0 on 2025-09-27, v2.0.0 on 2025-11-08 and v2.1.0 on 2026-03-21, and the current manifest version is 2.1.0. The repository is not archived, and the last push was on 2026-10-20, so the tree is a few days old relative to today. There is a CHANGELOG.md in the tree, which is where the breaking changes between 1.x and 2.x will be recorded, and the jump from 1.7 to 2.0 suggests there were some.

What to verify before you ship it is a short list. Read the property table end to end and check the two or three properties you actually need rather than assuming the defaults suit you, since the crawler directives all default to false and are silent when omitted. Then fetch one of your rendered pages with a plain HTTP client and look at the head, because that is what a crawler does, and a component that renders correctly in the browser can still be absent from the served HTML if your app is not server side rendered.

Finally, check the Svelte 5 peer requirement against your own application, and if you generate JSON-LD, view it in a validator rather than trusting the emitted markup, because a schema with a wrong type or a missing field will not throw at build time.

Editorial conclusion

svelte-seo fits a Svelte or SvelteKit team that wants one component to emit the head tags a page needs, with Open Graph and Twitter Card handled in the same place, and that wants JSON-LD emitted from typed objects rather than by hand. It does not fit a project that needs a sitemap, a robots policy or per route configuration, because the scope is the page head, and it does not fit an application that renders on the client only, since server side rendering is what makes the tags visible to a crawler. Before you adopt it, read the property table end to end, check that the crawler you care about sees the rendered head rather than the client-side result, and confirm the peer dependency of Svelte 5 matches your application.

Frequently asked questions

What does svelte-seo do?

It is a Svelte component that adds the head tags a page needs for search engines and social media, covering meta tags, Open Graph, Twitter Card and JSON-LD. The documentation describes it as a package designed to optimize a Svelte app for search engines and social media, improving visibility and ranking in search results.

How do I install svelte-seo?

It is a dev dependency, and the documentation lists three package managers: npm install -D svelte-seo, yarn add -D svelte-seo or pnpm add -D svelte-seo. The package declares a peer dependency on svelte 5.

Which SEO properties does svelte-seo support?

The property table covers title, description, keywords, base, applicationName, themeColor, the crawler directives nofollow, noindex, nositelinkssearchbox and notranslate, the canonical URL, and the AMP URL, alongside the nested openGraph, twitter and facebook objects and the JSON-LD structured data.

Does svelte-seo need server side rendering?

For the tags to be visible to a crawler, yes. The package keywords include ssr, and a crawler that fetches the HTML without running the JavaScript will not see meta tags that are only added on the client.

What licence does svelte-seo use?

It is released under the MIT licence, with the licence field in the package manifest set to MIT and the text in the LICENSE file at the repository root. The current version is 2.1.0, released on 2026-03-21, and the last push was on 2026-10-20.

Official sources

  1. artiebits/svelte-seo on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/artiebits-svelte-seo.svg)](https://hysenlabs.com/projects/artiebits-svelte-seo)

Was this useful?