Creative Works

Table of contents

  1. CreativeWork — Base Type
  2. createArticle / createNewsArticle / createBlogPosting
    1. Article-specific fields
    2. Minimum for Google rich result
  3. createWebPage
    1. Fields (additional to CreativeWork)
    2. Example
  4. createWebSite
    1. Fields
    2. Example
  5. createDataset
    1. Fields
  6. createRecipe
    1. Fields
    2. NutritionInformation fields
  7. createCourse
    1. Fields
    2. CourseInstance (for hasCourseInstance)
  8. createSoftwareApplication / createMobileApplication / createWebApplication
    1. Fields
    2. ApplicationCategory values
  9. createVideoObject
    1. Fields
    2. ClipSchema — Key Moments
    3. BroadcastEventSchema — Livestream
    4. SeekToActionSchema — Key Moments
  10. createBook
    1. BookSchema fields
    2. BookEditionSchema fields
    3. ReadActionSchema
    4. BorrowActionSchema
    5. Full Example
  11. createMathSolver
    1. Fields
  12. createClaimReview
    1. ClaimReviewSchema fields
    2. ClaimSchema fields
    3. Example

CreativeWork — Base Type

All creative work types share these base fields (inherited from ThingSchema + CreativeWorkSchema):

Field Type Notes
author string \| Person \| Organization? Content author
publisher string \| Person \| Organization? Publisher
datePublished string? ISO 8601 publication date
dateModified string? ISO 8601 last-modified date
headline string? (max 110 chars) Article headline
keywords string \| string[]? Topics
inLanguage string \| Language? BCP 47, e.g. "en-US"
license string? (URL) Content license
thumbnailUrl string? (URL) Thumbnail image
isAccessibleForFree boolean? For paywalled content
image string \| ImageObject \| []? Representative image(s)
hasPart object[]? Sub-parts (for paywalls)
isPartOf object? Parent work
text string? Full text content
abstract string? Summary
encodingFormat string? MIME type
contentUrl string? Direct URL to content
copyrightYear number? Copyright year
copyrightHolder Person \| Organization? Copyright holder

createArticle / createNewsArticle / createBlogPosting

import { createArticle, createNewsArticle, createBlogPosting } from 'schemaorg-kit';
Factory @type Google Rich Result
createArticle "Article" Top Stories, general article
createNewsArticle "NewsArticle" Top Stories, AMP
createBlogPosting "BlogPosting" General article

Article-specific fields

Field Type Notes
articleBody string? Full article text
articleSection string? Section/category
wordCount number? Word count (non-negative integer)
image string \| ImageObject \| []? Google requires ≥1 image, ≥1200px wide
video VideoObject \| VideoObject[]? Embedded video
speakable SpeakableSpecification? For Google Assistant

Minimum for Google rich result

createArticle({
  headline: 'Article Title',           // required (max 110 chars)
  image: 'https://example.com/img.jpg', // required (≥1200px wide)
  datePublished: '2025-01-01',          // required
  author: { '@type': 'Person', name: 'Alice' }, // required
});

createWebPage

import { createWebPage } from 'schemaorg-kit';

Represents an individual web page. Useful in @graph alongside Article, Organization, etc.

Fields (additional to CreativeWork)

Field Type Notes
url string? Page URL
name string? Page title
breadcrumb BreadcrumbList? Page breadcrumb
reviewedBy Person \| Organization? Medical/legal review
lastReviewed string? ISO 8601 review date
speakable SpeakableSpecification? For Google Assistant
significantLink string \| string[]? Important outgoing links
primaryImageOfPage ImageObject? Primary image
relatedLink string \| string[]? Related links

Example

const page = createWebPage({
  '@id': 'https://example.com/about#webpage',
  name: 'About Us — Acme',
  url: 'https://example.com/about',
  description: 'Learn about Acme Corporation.',
  datePublished: '2024-01-01',
  dateModified: '2025-03-15',
  inLanguage: 'en-US',
  isPartOf: { '@id': 'https://example.com/#website' },
  breadcrumb: {
    '@type': 'BreadcrumbList',
    itemListElement: [
      { '@type': 'ListItem', position: 1, name: 'Home', item: 'https://example.com' },
      { '@type': 'ListItem', position: 2, name: 'About' },
    ],
  },
});

createWebSite

import { createWebSite } from 'schemaorg-kit';

Represents the entire website. Used for knowledge panel signals.

potentialAction (SearchAction) was deprecated by Google in November 2024. The Sitelinks Searchbox no longer appears in search results. The field is harmless to include but has no effect. See Google’s announcement.

Fields

Field Type Notes
name string? Site name
url string? Homepage URL
inLanguage string \| string[]? Site language(s)
publisher Person \| Organization? Site owner
potentialAction SearchAction? Sitelinks searchboxdeprecated Nov 2024
copyrightYear number? Copyright year

Example

const site = createWebSite({
  '@id': 'https://acme.com/#website',
  name: 'Acme Corporation',
  url: 'https://acme.com',
  inLanguage: 'en-US',
  publisher: { '@id': 'https://acme.com/#organization' },
});

createDataset

import { createDataset, PropertyValueSchema } from 'schemaorg-kit';

For Google Dataset Search. Required: name, description.

Fields

Field Type Notes
name string Required — dataset name
description string? What the data contains
url string? Landing page URL
identifier string? DOI or other persistent ID
license string? License URL
creator Person \| Organization \| []? Dataset creator(s)
publisher Person \| Organization? Publisher
datePublished string? ISO 8601
dateModified string? ISO 8601
keywords string \| string[]? Subject keywords
variableMeasured string \| PropertyValue \| []? Variables in the dataset
measurementTechnique string? How data was collected
temporalCoverage string? ISO 8601 date/interval
spatialCoverage Place? Geographic coverage
distribution DataDownload \| DataDownload[]? Downloadable files
hasPart Dataset[]? Sub-datasets
isBasedOn string? Source dataset URL
citation string? How to cite
inLanguage string? Language
isAccessibleForFree boolean? Open access?

createRecipe

import { createRecipe, NutritionInformationSchema } from 'schemaorg-kit';

Google required: name, image. Enables the Recipe rich result with ratings, nutrition, and cooking time.

Fields

Field Type Notes
name string Required
image string \| ImageObject \| [] Required — multiple aspect ratios recommended
author Person \| Organization \| []? Recipe author
datePublished string? Publication date
description string? Short description
prepTime string? ISO 8601 duration, e.g. "PT15M"
cookTime string? ISO 8601 duration
totalTime string? ISO 8601 duration
recipeYield string \| number \| string[]? Serving size
recipeCategory string? e.g. “Dessert”, “Breakfast”
recipeCuisine string? e.g. “Italian”, “Mexican”
recipeIngredient string[]? List of ingredients
recipeInstructions (string \| HowToStep \| HowToSection)[]? Step-by-step instructions
nutrition NutritionInformation? Per-serving nutrition data
video VideoObject \| VideoObject[]? Cooking video
aggregateRating AggregateRating? User ratings
review Review \| Review[]? User reviews
keywords string \| string[]? Tags
cookingMethod string? e.g. “Baking”, “Grilling”
suitableForDiet string \| string[]? Schema.org diet enum URLs
estimatedCost string? Rough cost

NutritionInformation fields

NutritionInformationSchema.parse({
  calories: '350 calories',
  proteinContent: '12 grams',
  carbohydrateContent: '45 grams',
  fatContent: '8 grams',
  fiberContent: '3 grams',
  sugarContent: '5 grams',
  sodiumContent: '480 milligrams',
  servingSize: '1 cup (240g)',
});

createCourse

import { createCourse } from 'schemaorg-kit';

Required: name, description. Eligible for Course rich results.

Fields

Field Type Notes
name string Required
description string? Required for rich result
provider Organization \| Person? Who offers the course
url string? Course landing page
hasCourseInstance CourseInstance[]? Specific scheduled instances
image string \| ImageObject \| []? Course image
inLanguage string? Language
educationalLevel string? e.g. “beginner”, “undergraduate”
teaches string \| string[]? Skills taught
skillLevel string? Skill level
numberOfCredits number? Academic credits
occupationalCredentialAwarded string? Certificate or degree
educationalCredentialAwarded string? Academic credential
about object \| object[]? Topics covered
aggregateRating AggregateRating? Course rating

CourseInstance (for hasCourseInstance)

{
  '@type': 'CourseInstance',
  courseMode: 'online' | 'onsite' | 'blended',
  startDate: '2025-09-01',  // ISO 8601
  endDate: '2025-12-15',
  location: { '@type': 'Place', name: 'Room 204' },  // for onsite
  instructor: { '@type': 'Person', name: 'Prof. Smith' },
  offers: { '@type': 'Offer', price: 0, priceCurrency: 'USD' },
}

createSoftwareApplication / createMobileApplication / createWebApplication

import {
  createSoftwareApplication,
  createMobileApplication,
  createWebApplication,
} from 'schemaorg-kit';
Factory @type Platform
createSoftwareApplication "SoftwareApplication" Desktop
createMobileApplication "MobileApplication" iOS / Android
createWebApplication "WebApplication" Browser

Google required: name, offers.price, and either aggregateRating or review.

Fields

Field Type Notes
name string? App name
description string? App description
applicationCategory string? e.g. "FinanceApplication", "GameApplication"
operatingSystem string \| string[]? e.g. ["ANDROID 8.0+", "iOS 14.0+"]
offers Offer \| Offer[]? Pricing (free = price: 0)
aggregateRating AggregateRating? App store rating
review Review? Individual review
screenshot string \| ImageObject \| []? App screenshots
softwareVersion string? Current version
fileSize string? Download size
downloadUrl string? Download link
installUrl string? Installation URL
countriesSupported string[]? Country codes
featureList string \| string[]? Feature list
browserRequirements string? WebApplication only
isAccessibleForFree boolean? Free app?

ApplicationCategory values

"GameApplication", "SocialNetworkingApplication", "TravelApplication", "ShoppingApplication", "SportsApplication", "LifestyleApplication", "BusinessApplication", "DesignApplication", "DeveloperApplication", "DriverApplication", "EducationalApplication", "HealthApplication", "FinanceApplication", "SecurityApplication", "BrowserApplication", "CommunicationApplication", "DesktopEnhancementApplication", "EntertainmentApplication", "MultimediaApplication", "HomeApplication", "UtilitiesApplication", "ReferenceApplication"


createVideoObject

import { createVideoObject, ClipSchema, BroadcastEventSchema } from 'schemaorg-kit';

Fields

Field Type Notes
name string? Video title
description string? Video description
thumbnailUrl string \| string[]? Required for rich result — multiple aspect ratios
uploadDate string? Required — ISO 8601
duration string? ISO 8601 duration, e.g. "PT1H12M30S"
contentUrl string? Direct video file URL
embedUrl string? Embed URL (YouTube, Vimeo, etc.)
hasPart Clip[]? Key moments (chapters)
isLiveBroadcast boolean? Is/was live
publication BroadcastEvent? Live broadcast details
potentialAction SeekToAction \| []? Key moments via URL template
regionsAllowed string \| string[]? ISO 3166-1 country codes
requiresSubscription boolean? Paywalled?
interactionStatistic InteractionCounter? View count

ClipSchema — Key Moments

ClipSchema.parse({
  name: 'Introduction',
  startOffset: 0,       // seconds from start
  endOffset: 120,       // seconds from start
  url: 'https://example.com/video.mp4#t=0',
})

BroadcastEventSchema — Livestream

BroadcastEventSchema.parse({
  isLiveBroadcast: true,
  startDate: '2025-06-01T09:00:00-07:00',
  endDate:   '2025-06-01T11:00:00-07:00',
})

SeekToActionSchema — Key Moments

Enables timestamp deep-links for videos hosted on your own site (non-YouTube). The target URL template must contain a {seek_to_second_number} placeholder.

import { SeekToActionSchema } from 'schemaorg-kit';

SeekToActionSchema.parse({
  target: 'https://example.com/video?t={seek_to_second_number}',
  // 'startOffset-input' defaults to 'required name=seek_to_second_number'
})

createBook

import {
  createBook,
  BookEditionSchema,
  ReadActionSchema,
  BorrowActionSchema,
  BookFormatType,
} from 'schemaorg-kit';

For Google Book Actions (invite-only). Google uses a two-level structure: a work node (the book itself) containing workExample entries (individual editions). Each edition has a potentialAction — either ReadAction (read online) or BorrowAction (borrow from a library).

BookSchema fields

Field Type Notes
name string Required — book title
author Person \| Organization \| [] Required — author(s)
workExample BookEdition \| BookEdition[]? Individual editions (eBook, print, audio…)
isbn string? ISBN-13 preferred
description string? Book synopsis
image string \| ImageObject \| []? Cover image
url string? Canonical book page
sameAs string \| string[]? WorldCat, Open Library, Wikidata, etc.

BookEditionSchema fields

Field Type Notes
bookFormat BookFormatType? "EBook", "Hardcover", "Paperback", "AudioBook", "GraphicNovel"
inLanguage string? BCP 47 language code
isbn string? Edition ISBN
name string? Edition-specific title
potentialAction ReadAction \| BorrowAction \| []? How to acquire the edition
url string? Edition landing page
datePublished string? Edition publication date

ReadActionSchema

ReadActionSchema.parse({
  target: 'https://read.example.com/book-slug',   // URL or EntryPoint object
  expectsAcceptanceOf: { '@type': 'Offer', price: 9.99, priceCurrency: 'USD' },
})

BorrowActionSchema

BorrowActionSchema.parse({
  lender: {
    '@type': 'LibrarySystem',
    name: 'City Public Library System',
    '@id': 'https://www.worldcat.org/wcpa/oclc/12345',
  },
  target: 'https://catalog.library.example/borrow/isbn/9780132350884',
})

Full Example

import { createBook, BookEditionSchema, ReadActionSchema, BorrowActionSchema } from 'schemaorg-kit';

const book = createBook({
  name: 'Clean Code',
  author: { '@type': 'Person', name: 'Robert C. Martin' },
  isbn: '9780132350884',
  description: 'A handbook of agile software craftsmanship.',
  image: 'https://example.com/covers/clean-code.jpg',
  sameAs: [
    'https://www.worldcat.org/oclc/71196630',
    'https://openlibrary.org/books/OL7353243M',
  ],
  workExample: [
    BookEditionSchema.parse({
      name: 'Clean Code (eBook)',
      bookFormat: 'EBook',
      inLanguage: 'en',
      isbn: '9780136083252',
      potentialAction: ReadActionSchema.parse({
        target: 'https://read.example.com/clean-code',
        expectsAcceptanceOf: { '@type': 'Offer', price: 9.99, priceCurrency: 'USD' },
      }),
    }),
    BookEditionSchema.parse({
      name: 'Clean Code (Hardcover)',
      bookFormat: 'Hardcover',
      inLanguage: 'en',
      isbn: '9780132350884',
      potentialAction: BorrowActionSchema.parse({
        lender: { '@type': 'LibrarySystem', name: 'San Francisco Public Library' },
        target: 'https://sfpl.org/catalog/borrow/clean-code',
      }),
    }),
  ],
});

createMathSolver

import { createMathSolver, SolveMathActionSchema } from 'schemaorg-kit';

For Google’s Math Solver rich result. Required: name, potentialAction.

Fields

Field Type Notes
name string Required — solver name
url string? Solver URL
potentialAction SolveMathAction \| SolveMathAction[]? Required — solve action
mathExpression string \| string[]? Example expressions
educationalLevel string? Level (e.g. “high school”)
teaches string \| string[]? Topics covered
usageInfo string? URL to terms/usage page — Google required
learningResourceType string? Defaults to "Math Solver"
assesses string \| string[]? Topics the solver assesses
const solver = createMathSolver({
  name: 'Algebra Step Solver',
  potentialAction: {
    '@type': 'SolveMathAction',
    eduQuestionType: 'Algebra',
    target: {
      '@type': 'EntryPoint',
      urlTemplate: 'https://solver.example.com/solve?expr={math_expression_string}',
      actionAccessibilityRequirement: {
        '@type': 'ActionAccessSpecification',
        requiresSubscription: false,
      },
    },
  },
});

createClaimReview

import { createClaimReview, ClaimSchema, ClaimReviewSchema } from 'schemaorg-kit';

For Google’s Fact Check rich result. Required: url, claimReviewed, reviewRating.alternateName.

ClaimReviewSchema fields

Field Type Notes
url string Required — URL of the fact-check article
claimReviewed string Required — The text of the claim
reviewRating Rating Required — Must include alternateName (e.g. “False”)
author Person \| Organization? The fact-checker
itemReviewed Claim? The structured Claim object
datePublished string? ISO 8601
dateModified string? ISO 8601
inLanguage string? Language code

ClaimSchema fields

Field Type Notes
author Person \| Organization? Who made the claim
datePublished string? When the claim was made
firstAppearance string? URL of first appearance
appearance string \| string[]? URL(s) of other appearances

Example

const factCheck = createClaimReview({
  url: 'https://factcheck.example.com/2025/claim-about-climate',
  claimReviewed: 'Global temperatures have not risen since 2010.',
  reviewRating: {
    '@type': 'Rating',
    alternateName: 'False',
    ratingValue: 1,
    bestRating: 5,
    worstRating: 1,
  },
  author: { '@type': 'Organization', name: 'FactCheck.org' },
  datePublished: '2025-06-15',
  itemReviewed: ClaimSchema.parse({
    author: { '@type': 'Person', name: 'Jane Doe' },
    datePublished: '2025-06-10',
    firstAppearance: 'https://blog.example.com/climate-post',
  }),
});