schemaorg-kit
v1.3.0
Published
Type-safe schema.org structured data builder — all Google rich result types, Zod validation, JSON-LD @graph
Maintainers
Readme
schemaorg-kit
Type-safe schema.org structured data for every Google rich result type — Zod validation, JSON-LD
@graph, full TypeScript inference.
Features
- 40+ factory functions covering all Google-supported rich result types
- Zod v4 validation with descriptive error messages at runtime
- Full TypeScript autocomplete — every field, every enum value
@graphsupport for multi-entity pages with cross-references- Two APIs — named factories (
createProduct) or unifiedschema("Product", {...}) - Dual ESM + CJS build — works in Next.js, Remix, Astro, Node.js, and beyond
- Zero dependencies at runtime — Zod is a peer dependency you already have
Installation
npm install schemaorg-kit zodRequires Node.js ≥ 18 and Zod ≥ 4.3.
Quick Start
import {
createProduct,
createOffer,
createBreadcrumbList,
} from "schemaorg-kit";
const product = createProduct({
name: "Running Shoes",
sku: "RS-001",
offers: createOffer({
price: 99.99,
priceCurrency: "USD",
availability: "InStock",
}).toObject(),
});
// Inject directly into HTML
document.head.innerHTML += product.toScript();
// Or get the plain object
const jsonLd = product.toJsonLd(); // includes @contextOutput Methods
Every node returned by a factory exposes these methods:
| Method | Returns | Description |
| -------------- | ------------------------- | ------------------------------------------------------------------ |
| .toObject() | T | Raw validated object — use this when nesting inside another schema |
| .toJsonLd() | Record<string, unknown> | Object with @context: "https://schema.org" added |
| .toScript() | string | Full <script type="application/ld+json"> tag, ready for HTML |
| .toString() | string | Pretty-printed JSON string |
| .validate() | this | Throws a ZodError if data is invalid (chainable) |
| .safeParse() | Zod result | Returns { success, data, error } without throwing |
Composing Schemas
Call .toObject() when embedding one schema inside another:
import { createPerson, createOrganization, createArticle } from "schemaorg-kit";
const author = createPerson({ name: "Jane Doe", url: "https://janedoe.com" });
const article = createArticle({
headline: "Hello World",
author: author.toObject(), // <-- nest with .toObject()
publisher: createOrganization({
name: "Acme Blog",
url: "https://acmeblog.com",
logo: "https://acmeblog.com/logo.png",
}).toObject(),
});
console.log(article.toScript());@graph Support
Use createGraph to output multiple schema nodes in a single <script> tag. Use SchemaIds for consistent @id cross-references:
import {
SchemaIds,
createGraph,
createOrganization,
createWebSite,
createWebPage,
} from "schemaorg-kit";
const ids = new SchemaIds("https://example.com");
const graph = createGraph([
createOrganization({
"@id": ids.organization(),
name: "Acme Corp",
url: "https://example.com",
}),
createWebSite({
"@id": ids.website(),
name: "Acme",
url: "https://example.com",
publisher: ids.ref("organization"), // { "@id": "https://example.com/#organization" }
}),
createWebPage({
"@id": ids.webpage(),
url: "https://example.com",
}),
]);
console.log(graph.toScript());SchemaIds provides well-known methods (organization(), website(), webpage(), person(), etc.), custom() for arbitrary fragments, forPath() for page-scoped IDs, and ref() for cross-reference objects.
Unified Factory
As an alternative to named imports, use the schema() factory with any registered type name:
import { schema } from "schemaorg-kit";
const product = schema("Product", { name: "Shoes", sku: "SH-001" });
const event = schema("Event", { name: "Conference", startDate: "2025-09-01" });Supported Types
Things
| Factory | Schema.org Type |
| ---------------------- | ---------------- |
| createPerson | Person |
| createOrganization | Organization |
| createCorporation | Corporation |
| createNGO | NGO |
| createOnlineStore | OnlineStore |
| createOnlineBusiness | OnlineBusiness |
| createProduct | Product |
| createProductGroup | ProductGroup |
| createEvent | Event |
| createPlace | Place |
| createLocalBusiness | LocalBusiness |
| createRestaurant | Restaurant |
| createHotel | Hotel |
| createMovie | Movie |
Creative Works
| Factory | Schema.org Type |
| --------------------------- | --------------------------------------- |
| createBook | Book (with ReadAction / BorrowAction) |
| createArticle | Article |
| createNewsArticle | NewsArticle |
| createBlogPosting | BlogPosting |
| createWebPage | WebPage |
| createWebSite | WebSite |
| createDataset | Dataset |
| createRecipe | Recipe |
| createCourse | Course |
| createSoftwareApplication | SoftwareApplication |
| createMobileApplication | MobileApplication |
| createWebApplication | WebApplication |
| createMathSolver | MathSolver |
| createClaimReview | ClaimReview (Fact Check) |
Intangibles & Other
| Factory | Schema.org Type |
| ------------------------------------------------ | ------------------------------ |
| createOffer | Offer |
| createImageObject | ImageObject |
| createVideoObject | VideoObject |
| createJobPosting | JobPosting |
| createQAPage / createQuiz / createQuestion | QAPage / Quiz / Question |
| createDiscussionForumPosting | DiscussionForumPosting |
| createProfilePage | ProfilePage |
| createVacationRental | VacationRental |
| createLanguage | Language |
Helpers
| Helper | What it does |
| ----------------------------- | ------------------------------------------------------------ |
| createBreadcrumbList([...]) | Builds a BreadcrumbList from a plain array |
| createFAQPage([...]) | Builds a FAQPage from {question, answer} pairs |
| createCarousel([...]) | Wraps schema nodes in an ItemList carousel |
| createPaywalledArticle(...) | Article with isAccessibleForFree: false paywalled sections |
Common Patterns
Product with Price Range and Shipping
import {
createProduct,
AggregateOfferSchema,
OfferShippingDetailsSchema,
DefinedRegionSchema,
} from "schemaorg-kit";
const product = createProduct({
name: "Premium Headphones",
offers: AggregateOfferSchema.parse({
lowPrice: 79,
highPrice: 129,
priceCurrency: "USD",
offerCount: 4,
offers: {
price: 79,
priceCurrency: "USD",
availability: "InStock",
shippingDetails: OfferShippingDetailsSchema.parse({
shippingRate: { value: 0, currency: "USD" },
shippingDestination: DefinedRegionSchema.parse({
addressCountry: "US",
}),
deliveryTime: {
handlingTime: { minValue: 0, maxValue: 1, unitCode: "DAY" },
transitTime: { minValue: 3, maxValue: 5, unitCode: "DAY" },
},
}),
},
}),
});FAQ Page
import { createFAQPage } from "schemaorg-kit";
const faq = createFAQPage([
{
question: "What is schemaorg-kit?",
answer: "A type-safe schema.org builder.",
},
{ question: "Does it support @graph?", answer: "Yes, via createGraph()." },
]);
document.head.innerHTML += faq.toScript();BreadcrumbList
import { createBreadcrumbList } from "schemaorg-kit";
const breadcrumb = createBreadcrumbList([
{ name: "Home", url: "https://example.com" },
{ name: "Products", url: "https://example.com/products" },
{ name: "Shoes" }, // last item — url is optional
]);Extending with Custom Types
import { extendThing, makeFactory } from "schemaorg-kit";
import { z } from "zod";
const PodcastSchema = extendThing("PodcastSeries", {
webFeed: z.url(),
numberOfEpisodes: z.number().int().optional(),
});
const createPodcast = makeFactory(PodcastSchema);
const podcast = createPodcast({
name: "My Show",
webFeed: "https://example.com/feed.rss",
});Project Structure
src/
├── core/
│ ├── base.ts # SchemaNode<T> class + makeFactory()
│ ├── registry.ts # Unified schema() factory + REGISTRY
│ ├── graph.ts # SchemaGraph + createGraph()
│ └── ids.ts # SchemaIds + SchemaId (cross-reference helpers)
├── types/
│ ├── shared/ # Reusable building blocks
│ │ ├── Offer.ts # Offer, AggregateOffer, MerchantReturnPolicy, UnitPriceSpecification, ItemCondition
│ │ ├── ShippingDetails.ts # OfferShippingDetails, DefinedRegion, ShippingDeliveryTime
│ │ ├── Rating.ts # Rating, AggregateRating, Review, EmployerAggregateRating
│ │ ├── VideoObject.ts # VideoObject, Clip, BroadcastEvent, SeekToAction
│ │ ├── InteractionCounter.ts # InteractionCounter (likes, shares, views)
│ │ ├── MemberProgram.ts # MemberProgram, MemberProgramTier (loyalty)
│ │ ├── ShippingService.ts # ShippingService, ShippingConditions, ServicePeriod
│ │ └── ...
│ ├── things/ # Person, Organization, Product, Place, Event, ...
│ ├── creative-works/ # Article, WebPage, WebSite, Recipe, Book, ...
│ ├── intangibles/ # JobPosting, FAQPage, ItemList, ProfilePage, ...
│ └── lodging/ # VacationRental, Accommodation
├── helpers/ # Ergonomic wrappers (breadcrumb, faq, carousel, paywalled)
└── index.ts # Public APILinks
- Docs: https://6f5.github.io/schemaorg-kit/
- npm: https://www.npmjs.com/package/schemaorg-kit
- Issues: https://github.com/6f5/schemaorg-kit/issues
License
MIT
