Shared Types
Shared building blocks used across multiple schema types. Import them to compose rich nested schemas.
Table of contents
- PostalAddressSchema
- GeoCoordinatesSchema
- ImageObjectSchema / ImageOrUrl / createImageObject
- ContactPointSchema
- MonetaryAmountSchema / PriceSpecificationSchema
- RatingSchema / AggregateRatingSchema / ReviewSchema
- OfferSchema / createOffer / ItemAvailability / ItemCondition
- AggregateOfferSchema
- OfferShippingDetailsSchema / DefinedRegionSchema / ShippingDeliveryTimeSchema
- MerchantReturnPolicySchema
- OpeningHoursSpecificationSchema
- HowToStepSchema / HowToSectionSchema
- PersonOrOrgRef
- ClipSchema / BroadcastEventSchema / SeekToActionSchema / VideoObjectSchema
- InteractionCounterSchema
- MemberProgramSchema / MemberProgramTierSchema
- ShippingServiceSchema / ShippingConditionsSchema / ServicePeriodSchema
PostalAddressSchema
import { PostalAddressSchema, type PostalAddress } from 'schemaorg-kit';
Physical mailing address. Use with Organization.address, LocalBusiness.address, JobPosting.jobLocation, etc.
const address = PostalAddressSchema.parse({
streetAddress: '123 Main Street',
addressLocality: 'San Francisco', // city
addressRegion: 'CA', // state/province
postalCode: '94105',
addressCountry: 'US', // ISO 3166-1 alpha-2
postOfficeBoxNumber: 'PO Box 123', // optional
});
// { "@type": "PostalAddress", ... }
You can also pass a plain object literal directly — any field accepting PostalAddress also accepts the raw object shape.
GeoCoordinatesSchema
import { GeoCoordinatesSchema, type GeoCoordinates } from 'schemaorg-kit';
GPS coordinates. Used with LocalBusiness.geo, Place.geo, VacationRental.geo.
const geo = GeoCoordinatesSchema.parse({
latitude: 37.78825,
longitude: -122.4324,
});
// { "@type": "GeoCoordinates", "latitude": 37.78825, "longitude": -122.4324 }
ImageObjectSchema / ImageOrUrl / createImageObject
import {
ImageObjectSchema,
ImageOrUrl,
createImageObject,
type ImageObject,
} from 'schemaorg-kit';
A detailed image object with Google image metadata fields.
ImageObject fields
| Field | Type | Notes |
|---|---|---|
url |
string |
Required — image URL |
contentUrl |
string? |
Direct file URL (if different from page URL) |
width |
number \| QuantitativeValue? |
Pixel width |
height |
number \| QuantitativeValue? |
Pixel height |
caption |
string? |
Image caption |
description |
string? |
Image description |
name |
string? |
Image name/title |
creator |
Person \| Organization? |
Who created the image |
creditText |
string? |
Credit line to display |
copyrightNotice |
string? |
Copyright notice |
license |
string? |
License URL |
acquireLicensePage |
string? |
Where to get a license |
representativeOfPage |
boolean? |
Primary image of its page |
encodingFormat |
string? |
MIME type, e.g. "image/jpeg" |
uploadDate |
string? |
ISO 8601 upload date |
thumbnailUrl |
string? |
Thumbnail URL |
const image = createImageObject({
url: 'https://example.com/photo.jpg',
width: 1200,
height: 675,
caption: 'Team at the annual conference',
creator: { '@type': 'Person', name: 'Bob Chen' },
creditText: 'Photo by Bob Chen / Acme Corp',
license: 'https://creativecommons.org/licenses/by/4.0/',
});
ImageOrUrl
ImageOrUrl accepts either a URL string or a full ImageObject. It’s used on fields like Thing.image, Organization.logo, Article.image, etc.:
// Both are valid:
{ image: 'https://example.com/photo.jpg' }
{ image: { '@type': 'ImageObject', url: 'https://example.com/photo.jpg', width: 1200 } }
// Arrays are also accepted on most types:
{ image: ['https://example.com/1.jpg', 'https://example.com/2.jpg'] }
ContactPointSchema
import { ContactPointSchema, type ContactPoint } from 'schemaorg-kit';
A specific contact channel. Used in Organization.contactPoint.
const contact = ContactPointSchema.parse({
contactType: 'customer support', // required
telephone: '+1-800-555-0100',
email: 'support@example.com', // must be valid email
availableLanguage: ['English', 'Spanish'],
hoursAvailable: 'Mo-Fr 09:00-18:00',
contactOption: 'TollFree',
areaServed: 'US',
});
MonetaryAmountSchema / PriceSpecificationSchema
import { MonetaryAmountSchema, PriceSpecificationSchema } from 'schemaorg-kit';
Used for JobPosting.baseSalary and VacationRental pricing.
// Salary range
const salary = MonetaryAmountSchema.parse({
currency: 'USD',
value: {
'@type': 'QuantitativeValue',
minValue: 80000,
maxValue: 120000,
unitText: 'YEAR', // or 'HOUR', 'MONTH', 'WEEK'
},
});
// Single price
const price = PriceSpecificationSchema.parse({
price: 9.99,
priceCurrency: 'USD',
valueAddedTaxIncluded: true,
validFrom: '2025-01-01',
validThrough: '2025-12-31',
});
RatingSchema / AggregateRatingSchema / ReviewSchema
import {
RatingSchema,
AggregateRatingSchema,
ReviewSchema,
EmployerAggregateRatingSchema,
type Rating,
type AggregateRating,
type Review,
} from 'schemaorg-kit';
RatingSchema
A single rating value.
const rating = RatingSchema.parse({
ratingValue: 4.5,
bestRating: 5, // default if omitted
worstRating: 1, // default if omitted
ratingExplanation: 'Great product, fast shipping.',
reviewAspect: 'quality',
});
AggregateRatingSchema
Average across many ratings. Either ratingCount or reviewCount is required.
const aggregateRating = AggregateRatingSchema.parse({
ratingValue: 4.7,
ratingCount: 12400, // total number of ratings
reviewCount: 890, // total number of written reviews
bestRating: 5,
worstRating: 1,
});
ReviewSchema
An individual user review.
const review = ReviewSchema.parse({
author: { '@type': 'Person', name: 'Jane Smith' },
reviewRating: { '@type': 'Rating', ratingValue: 5, bestRating: 5 },
reviewBody: 'Exceptional product. Well worth the price.',
datePublished: '2025-02-14',
publisher: { '@type': 'Organization', name: 'Trustpilot' },
itemReviewed: { '@type': 'Product', name: 'Trail Runner Pro' },
});
EmployerAggregateRatingSchema
For employer ratings (Glassdoor-style).
const rating = EmployerAggregateRatingSchema.parse({
ratingValue: 4.1,
ratingCount: 2340,
bestRating: 5,
worstRating: 1,
itemReviewed: { '@type': 'Organization', name: 'Acme Corp' },
});
OfferSchema / createOffer / ItemAvailability / ItemCondition
import {
OfferSchema, createOffer, ItemAvailability, ItemCondition,
UnitPriceSpecificationSchema,
type Offer,
} from 'schemaorg-kit';
Pricing information for products, apps, courses, events, etc.
Offer fields
| Field | Type | Notes |
|---|---|---|
price |
number \| string |
Price (use 0 for free) |
priceCurrency |
string |
ISO 4217 code (3 chars), e.g. "USD" |
availability |
ItemAvailability? |
Auto-transforms to schema.org URL |
itemCondition |
ItemCondition? |
Auto-transforms to schema.org URL |
url |
string? |
Purchase URL |
priceValidUntil |
string? |
ISO 8601 expiry date |
validFrom |
string? |
Offer start date |
validThrough |
string? |
Offer end date |
seller |
{ @type, name }? |
Who is selling |
category |
string? |
Offer category |
inventoryLevel |
QuantitativeValue? |
Stock level |
priceSpecification |
UnitPriceSpecification \| []? |
Loyalty/unit pricing (see below) |
shippingDetails |
OfferShippingDetails \| []? |
Shipping info (see below) |
hasMerchantReturnPolicy |
MerchantReturnPolicy? |
Return policy |
ItemAvailability values
| Input | Transformed output |
|---|---|
"InStock" |
https://schema.org/InStock |
"OutOfStock" |
https://schema.org/OutOfStock |
"PreOrder" |
https://schema.org/PreOrder |
"SoldOut" |
https://schema.org/SoldOut |
"LimitedAvailability" |
https://schema.org/LimitedAvailability |
"OnlineOnly" |
https://schema.org/OnlineOnly |
"InStoreOnly" |
https://schema.org/InStoreOnly |
"BackOrder" |
https://schema.org/BackOrder |
"Discontinued" |
https://schema.org/Discontinued |
ItemCondition values
| Input | Transformed output |
|---|---|
"NewCondition" |
https://schema.org/NewCondition |
"UsedCondition" |
https://schema.org/UsedCondition |
"RefurbishedCondition" |
https://schema.org/RefurbishedCondition |
"DamagedCondition" |
https://schema.org/DamagedCondition |
// Using createOffer factory (returns SchemaNode)
const offer = createOffer({
price: 29.99,
priceCurrency: 'USD',
availability: 'InStock', // → "https://schema.org/InStock"
itemCondition: 'NewCondition', // → "https://schema.org/NewCondition"
priceValidUntil: '2025-12-31',
url: 'https://example.com/buy',
});
// Using OfferSchema directly (returns plain object)
const offerObj = OfferSchema.parse({
price: 0,
priceCurrency: 'USD',
availability: 'InStock',
});
UnitPriceSpecificationSchema
For loyalty pricing, member-tier pricing, or unit-based pricing on Google Merchant Listings.
| Field | Type | Notes |
|---|---|---|
price |
number \| string |
Required |
priceCurrency |
string |
Required — ISO 4217 (3 chars) |
priceType |
string? |
"SRP", "ListPrice", "SalePrice", etc. |
validForMemberTier |
string \| object? |
Member tier this price applies to |
referenceQuantity |
QuantitativeValue? |
Unit reference (e.g. per 100g) |
membershipPointsEarned |
QuantitativeValue? |
Loyalty points earned |
validFrom |
string? |
ISO 8601 |
validThrough |
string? |
ISO 8601 |
import { UnitPriceSpecificationSchema } from 'schemaorg-kit';
const loyaltyPrice = UnitPriceSpecificationSchema.parse({
price: 24.99,
priceCurrency: 'USD',
priceType: 'SalePrice',
validForMemberTier: { '@type': 'MemberProgramTier', name: 'Gold' },
membershipPointsEarned: { '@type': 'QuantitativeValue', value: 50 },
});
AggregateOfferSchema
import { AggregateOfferSchema, type AggregateOffer } from 'schemaorg-kit';
For products sold by multiple sellers at different prices. Use in place of (or alongside) OfferSchema on Product.offers.
Fields
| Field | Type | Notes |
|---|---|---|
lowPrice |
number? |
Lowest available price |
highPrice |
number? |
Highest available price |
priceCurrency |
string? |
ISO 4217 currency code (3 chars) |
offerCount |
number? |
Number of sellers |
offers |
Offer \| Offer[]? |
Individual seller offers |
availability |
ItemAvailability? |
Overall availability |
url |
string? |
Canonical product URL |
import { createProduct, AggregateOfferSchema } from 'schemaorg-kit';
const product = createProduct({
name: 'Trail Runner Pro',
offers: AggregateOfferSchema.parse({
lowPrice: 89.99,
highPrice: 149.99,
priceCurrency: 'USD',
offerCount: 12,
availability: 'InStock',
}),
});
OfferShippingDetailsSchema / DefinedRegionSchema / ShippingDeliveryTimeSchema
import {
OfferShippingDetailsSchema,
DefinedRegionSchema,
ShippingDeliveryTimeSchema,
type OfferShippingDetails,
type DefinedRegion,
type ShippingDeliveryTime,
} from 'schemaorg-kit';
Required for Google’s Merchant Listing shipping eligibility. Add shippingDetails to Offer on a product page.
OfferShippingDetailsSchema fields
| Field | Type | Notes |
|---|---|---|
shippingRate |
{ value, currency }? |
Shipping cost (use value: 0 for free) |
shippingDestination |
DefinedRegion \| DefinedRegion[]? |
Where it ships |
deliveryTime |
ShippingDeliveryTime? |
How long it takes |
doesNotShip |
boolean? |
Explicitly mark no-ship regions |
shippingLabel |
string? |
Display label, e.g. "Free shipping" |
DefinedRegionSchema fields
| Field | Type | Notes |
|---|---|---|
addressCountry |
string? |
ISO 3166-1 alpha-2 country code |
addressRegion |
string \| string[]? |
State/province codes |
postalCodePrefix |
string \| string[]? |
Zip code prefix(es) |
postalCodeRange |
{ postalCodeBegin, postalCodeEnd }? |
Zip range |
ShippingDeliveryTimeSchema fields
| Field | Type | Notes |
|---|---|---|
handlingTime |
{ minValue, maxValue, unitCode: "DAY" }? |
Days to process order |
transitTime |
{ minValue, maxValue, unitCode: "DAY" }? |
Days in transit |
cutoffTime |
string? |
Order cutoff, e.g. "14:00:00" |
Example — Free US shipping
import { createProduct, OfferShippingDetailsSchema, DefinedRegionSchema, ShippingDeliveryTimeSchema } from 'schemaorg-kit';
const product = createProduct({
name: 'Trail Runner Pro',
offers: {
'@type': 'Offer',
price: 129.99,
priceCurrency: 'USD',
availability: 'InStock',
shippingDetails: OfferShippingDetailsSchema.parse({
shippingLabel: 'Free Standard Shipping',
shippingRate: { value: 0, currency: 'USD' },
shippingDestination: DefinedRegionSchema.parse({ addressCountry: 'US' }),
deliveryTime: ShippingDeliveryTimeSchema.parse({
handlingTime: { minValue: 0, maxValue: 1 },
transitTime: { minValue: 3, maxValue: 7 },
cutoffTime: '14:00:00',
}),
}),
},
});
MerchantReturnPolicySchema
import { MerchantReturnPolicySchema, type MerchantReturnPolicy } from 'schemaorg-kit';
Used on Organization.hasMerchantReturnPolicy and Product.hasMerchantReturnPolicy to improve Product rich result eligibility.
Fields
| Field | Type | Notes |
|---|---|---|
applicableCountry |
string \| string[]? |
ISO 3166-1 alpha-2 |
returnPolicyCategory |
string? |
Schema.org enum URL |
merchantReturnDays |
number? |
Days allowed for returns |
returnMethod |
string? |
Schema.org enum URL |
returnFees |
string? |
Schema.org enum URL |
refundType |
string? |
Schema.org enum URL |
merchantReturnLink |
string? |
URL to return policy page |
returnShippingFeesAmount |
MonetaryAmount? |
Shipping cost for returns |
itemCondition |
ItemCondition \| []? |
Condition(s) eligible for return |
returnLabelSource |
string? |
Schema.org enum URL |
returnPolicyCountry |
string? |
ISO 3166-1 alpha-2 |
restockingFee |
MonetaryAmount \| number? |
Restocking fee |
returnPolicySeasonalOverride |
SeasonalOverride \| []? |
Holiday return window |
customerRemorseReturnFees |
string? |
Buyer’s remorse return fees |
itemDefectReturnFees |
string? |
Defective item return fees |
const returnPolicy = MerchantReturnPolicySchema.parse({
applicableCountry: ['US', 'CA', 'GB'],
returnPolicyCategory: 'https://schema.org/MerchantReturnFiniteReturnWindow',
merchantReturnDays: 30,
returnMethod: 'https://schema.org/ReturnByMail',
returnFees: 'https://schema.org/FreeReturn',
merchantReturnLink: 'https://example.com/returns',
returnPolicySeasonalOverride: {
'@type': 'MerchantReturnPolicySeasonalOverride',
startDate: '2025-11-15',
endDate: '2026-01-31',
returnPolicyCategory: 'https://schema.org/MerchantReturnFiniteReturnWindow',
merchantReturnDays: 60,
},
});
OpeningHoursSpecificationSchema
import { OpeningHoursSpecificationSchema, type OpeningHoursSpecification } from 'schemaorg-kit';
Used with LocalBusiness.openingHoursSpecification and LocalBusiness.specialOpeningHoursSpecification.
import { OpeningHoursSpecificationSchema } from 'schemaorg-kit';
// Regular hours
const weekdays = OpeningHoursSpecificationSchema.parse({
dayOfWeek: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'],
opens: '09:00:00',
closes: '17:00:00',
});
// Special holiday hours (use specialOpeningHoursSpecification)
const holiday = OpeningHoursSpecificationSchema.parse({
dayOfWeek: 'Thursday',
opens: '00:00:00', // midnight to midnight = closed
closes: '00:00:00',
validFrom: '2025-12-25',
validThrough: '2025-12-25',
});
Valid dayOfWeek values: "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday", "PublicHolidays"
HowToStepSchema / HowToSectionSchema
import { HowToStepSchema, HowToSectionSchema } from 'schemaorg-kit';
For Recipe.recipeInstructions and HowTo types.
// Simple step
const step = HowToStepSchema.parse({
name: 'Preheat',
text: 'Preheat oven to 350°F (175°C).',
url: 'https://example.com/recipe#step-1',
image: 'https://example.com/recipe/step-1.jpg',
});
// Section with sub-steps
const section = HowToSectionSchema.parse({
name: 'Prepare the sauce',
itemListElement: [
{ '@type': 'HowToStep', text: 'Dice the tomatoes.' },
{ '@type': 'HowToStep', text: 'Sauté garlic in olive oil.' },
{ '@type': 'HowToStep', text: 'Add tomatoes and simmer for 20 minutes.' },
],
});
PersonOrOrgRef
import { PersonOrOrgRef, type PersonOrOrgRefType } from 'schemaorg-kit';
A union type used for fields that accept either a Person or an Organization. Accepts:
- A URL string (reference by URL)
- A
{ "@type": "Person", ... }object - A
{ "@type": "Organization", ... }object
Used on: author, publisher, creator, contributor, copyrightHolder, hiringOrganization, etc.
// All of these are valid:
{ author: 'https://example.com/authors/alice' } // URL reference
{ author: { '@type': 'Person', name: 'Alice' } } // Person object
{ author: { '@type': 'Organization', name: 'Acme' } } // Org object
{ author: createPerson({ name: 'Alice' }).toObject() } // From factory
ClipSchema / BroadcastEventSchema / SeekToActionSchema / VideoObjectSchema
See Creative Works → createVideoObject.
InteractionCounterSchema
import { InteractionCounterSchema, type InteractionCounter } from 'schemaorg-kit';
Tracks user interactions (likes, shares, views, etc.). Used on VideoObject.interactionStatistic, DiscussionForumPosting.interactionStatistic, Person.interactionStatistic, and Organization.interactionStatistic.
| Field | Type | Notes |
|---|---|---|
interactionType |
string |
Required — Full URL, e.g. "https://schema.org/LikeAction" |
userInteractionCount |
number |
Required — Non-negative integer |
const counter = InteractionCounterSchema.parse({
interactionType: 'https://schema.org/WatchAction',
userInteractionCount: 1250000,
});
Common interaction types: LikeAction, ShareAction, WatchAction, CommentAction, FollowAction, WriteAction
MemberProgramSchema / MemberProgramTierSchema
import { MemberProgramSchema, MemberProgramTierSchema, type MemberProgram } from 'schemaorg-kit';
For Google’s Merchant Listing loyalty program support. Used on Organization.hasMemberProgram.
MemberProgramTierSchema fields
| Field | Type | Notes |
|---|---|---|
name |
string |
Required — Tier name, e.g. “Gold” |
hasTierBenefit |
string \| string[] |
Required — Benefit names |
hasTierRequirement |
string \| object? |
Requirements to reach this tier |
membershipPointsEarned |
QuantitativeValue? |
Points earned per purchase |
url |
string? |
Tier details page |
MemberProgramSchema fields
| Field | Type | Notes |
|---|---|---|
name |
string |
Required — Program name |
description |
string? |
Program description |
hasTiers |
MemberProgramTier \| []? |
Loyalty tiers |
url |
string? |
Program page URL |
const loyaltyProgram = MemberProgramSchema.parse({
name: 'Acme Rewards',
description: 'Earn points on every purchase.',
url: 'https://acme.com/rewards',
hasTiers: [
MemberProgramTierSchema.parse({
name: 'Silver',
hasTierBenefit: ['Free shipping on orders over $25'],
}),
MemberProgramTierSchema.parse({
name: 'Gold',
hasTierBenefit: ['Free shipping on all orders', '10% member discount'],
membershipPointsEarned: { '@type': 'QuantitativeValue', value: 2, unitText: 'points per dollar' },
}),
],
});
ShippingServiceSchema / ShippingConditionsSchema / ServicePeriodSchema
import {
ShippingServiceSchema,
ShippingConditionsSchema,
ServicePeriodSchema,
type ShippingService,
} from 'schemaorg-kit';
Organization-level shipping service definitions for Google Merchant Listings. Used on Organization.hasShippingService.
ShippingServiceSchema fields
| Field | Type | Notes |
|---|---|---|
name |
string? |
Service name, e.g. “Standard Shipping” |
description |
string? |
Service description |
shippingConditions |
ShippingConditions \| []? |
Rate/region/time rules |
handlingTime |
ServicePeriod? |
Business-day handling window |
fulfillmentType |
string? |
"Delivery", "Pickup", "DigitalDelivery" |
validForMemberTier |
string \| object? |
Restrict to a loyalty tier |
ShippingConditionsSchema fields
| Field | Type | Notes |
|---|---|---|
shippingRate |
MonetaryAmount? |
Shipping cost |
shippingDestination |
DefinedRegion \| []? |
Where it ships |
shippingOrigin |
DefinedRegion \| []? |
Where it ships from |
deliveryTime |
ShippingDeliveryTime? |
Handling + transit time |
doesNotShip |
boolean? |
Explicitly mark no-ship |
orderValue |
MonetaryAmount? |
Minimum order value |
numItems |
QuantitativeValue? |
Item count constraint |
weight |
QuantitativeValue? |
Weight constraint |
ServicePeriodSchema fields
| Field | Type | Notes |
|---|---|---|
businessDays |
OpeningHoursSpecification? |
Which days orders are processed |
cutoffTime |
string? |
ISO 8601 time, e.g. "14:00:00-05:00" |
duration |
string? |
ISO 8601 duration, e.g. "P3D" |
import { createOrganization, ShippingServiceSchema, ShippingConditionsSchema } from 'schemaorg-kit';
const org = createOrganization({
name: 'Acme Store',
hasShippingService: ShippingServiceSchema.parse({
name: 'Free Standard Shipping',
fulfillmentType: 'Delivery',
shippingConditions: ShippingConditionsSchema.parse({
shippingRate: { '@type': 'MonetaryAmount', currency: 'USD', value: 0 },
shippingDestination: { '@type': 'DefinedRegion', addressCountry: 'US' },
deliveryTime: {
'@type': 'ShippingDeliveryTime',
transitTime: { '@type': 'QuantitativeValue', minValue: 3, maxValue: 7 },
},
}),
}),
});