This article explains a reusable structured data module.
It is typically implemented as a composable or utility.
It is usually written in TypeScript.
It exports a factory function.
That factory returns multiple helper functions.
Each helper function builds a Schema.org JSON LD object.
These objects are meant to be embedded in the page HTML.
Typically you embed them inside a script tag.
The script tag type should be application/ld+json.
Search engines read that JSON LD.
They use it to understand your pages.
They may produce rich results.
They may improve entity understanding.
They may improve crawl interpretation.
Important note
This composable only generates plain JavaScript objects.
It does not inject them into head by itself.
You still need to connect the output to your head management.
In most frameworks, you can do that via your head management system.
Or you can use a dedicated structured data integration.
The composable focuses on generation logic.
What this file contains
The file contains TypeScript interfaces.
Each interface defines the input shape for a generator.
Then the file defines the schema module.
Inside the schema module there are shared dependencies.
There is a route reference.
There is a locale reference.
There is a configuration reference.
Then there is baseUrl.
baseUrl comes from your configuration.
If baseUrl is missing, it falls back to a default domain.
After that, the file defines many generator functions.
All of them return a schema object.
Most return an object unconditionally.
One generator returns null when there is no data.
That generator is the FAQ schema generator.
How to use outputs in SEO
Search engines do not rank pages just because JSON LD exists.
But JSON LD helps them understand.
Better understanding can lead to better presentation.
Better presentation can lead to better click through.
Rich results can add extra screen space.
Extra screen space can increase trust.
It can also reduce ambiguity.
Structured data can help with
- Entity disambiguation
- Site identity
- Publisher identity
- Breadcrumb display
- FAQ rich results
- Job posting rich results
- Product like availability signals for services
- App rich results for SoftwareApplication
The exact rich result eligibility depends on search engine rules.
But the shapes used here are aligned with common Schema.org patterns.
Shared dependencies inside the schema module
The module reads the current route.
It reads the current locale.
It reads baseUrl.
These three values are used by helper methods.
The schema generators themselves accept explicit URLs.
So they are reusable across pages.
The helper methods focus on
- Getting the current page URL in a consistent way
- Building breadcrumb items from the route path
Now we will go function by function.
Organization schema
Generator
Organization schema generator
Goal
This function generates a Schema.org Organization entity.
An Organization is often used as the publisher.
It can also represent your brand entity.
It can connect your website to social profiles.
It can add contact and address info.
It can help build a knowledge graph entity.
Input interface
OrganizationSchemaOptions has these fields
Required
- name
- url
- logo
Optional
- alternateName
- description
- founder
- foundingDate
- foundingLocation
- telephone
- address
- contactPoint
- sameAs
Output shape
The base object includes
- [at]context set to https://schema.org
- [at]type set to Organization
- name
- url
- logo
Then it conditionally adds optional fields.
It only adds a field if you provided it.
This prevents empty fields.
That is helpful for clean output.
Address field
If address exists, it builds a PostalAddress object.
It sets [at]type to PostalAddress.
Then it spreads the address fields.
Those fields are
- streetAddress
- addressLocality
- addressRegion
- postalCode
- addressCountry
ContactPoint field
If contactPoint exists and is not empty, it maps each entry.
Each entry becomes a ContactPoint object.
It sets [at]type to ContactPoint.
Then it spreads the input.
This can represent sales, support, or other contact types.
sameAs field
If sameAs exists and is not empty, it adds sameAs.
sameAs is a list of URLs.
Common examples are
- Facebook page URL
- Instagram profile URL
- LinkedIn company page URL
- X profile URL
- YouTube channel URL
SEO value of Organization schema
- It defines who owns the site.
- It defines your brand name and logo.
- It can connect your brand to social profiles.
- It helps search engines connect content to a publisher.
- It can reduce ambiguity when your brand name is generic.
- It can help create a consistent entity graph.
WebPage schema
Generator
WebPage schema generator
Goal
This function describes a single web page.
It supports core page metadata.
It can connect the page to a website.
It can connect the page to a publisher.
It can attach a mainEntity.
Input interface
WebPageSchemaOptions
Required
- url
- name
- description
- inLanguage
Optional
- isPartOf
- publisher
- mainEntity
- datePublished
- dateModified
Output shape
The base object includes
- [at]context https://schema.org
- [at]type WebPage
- url
- name
- description
- inLanguage
isPartOf field
If isPartOf exists, it builds a Website object.
It sets [at]type to Website.
Then it adds url and name.
This connects a page to a website entity.
publisher field
If publisher exists, it builds an Organization object.
It sets [at]type to Organization.
It sets name.
It sets logo as an ImageObject.
The logo ImageObject has
- [at]type ImageObject
- url
mainEntity field
If mainEntity exists, it attaches it as is.
The type is Record.
This means you can pass any schema object.
For example, you can pass a RealEstateAgent.
Or you can pass an Article.
Or you can pass a FAQPage.
This is flexible.
But it also means you need to validate your own mainEntity.
datePublished and dateModified
If provided, they are added directly.
They should be ISO 8601 date strings.
Examples
- 2026-02-03
- 2026-02-03T10:00:00Z
SEO value of WebPage schema
- It clarifies the canonical page identity.
- It clarifies language.
- It can connect to a website and publisher.
- It can connect to a main entity.
- It can help search engines interpret page intent.
BreadcrumbList schema
Generator
BreadcrumbList schema generator
Goal
BreadcrumbList helps search engines understand hierarchy.
It may show breadcrumb rich results.
It can also help with sitelinks context.
Input interface
BreadcrumbSchemaOptions
- items is an array of name and item URL.
Output shape
The output includes
- [at]context https://schema.org
- [at]type BreadcrumbList
- itemListElement as an array of ListItem
Each ListItem includes
- [at]type ListItem
- position starting at 1
- name
- item
SEO value of BreadcrumbList
- It clarifies the user journey.
- It clarifies category and page relationships.
- It can appear in SERP snippets.
- It can reduce URL clutter in results.
RealEstateAgent schema
Generator
RealEstateAgent schema generator
Goal
This function describes a RealEstateAgent entity.
This is relevant for a real estate platform.
It can be used for company pages or agent profiles.
Input interface
RealEstateAgentSchemaOptions
Required
- name
- url
Optional
- image
- telephone
- priceRange
- address
- geo
- openingHoursSpecification
- sameAs
- areaServed
Output shape
Base object
- [at]context https://schema.org
- [at]type RealEstateAgent
- name
- [at]id equals options.url
- url equals options.url
This is a common pattern.
Using [at]id can help connect entities.
image field
If image exists, it is added directly.
You should provide an absolute URL.
telephone and email
If present, they are added as strings.
priceRange
If present, it is added.
It is usually a string like
- $$
- $1000 to $5000
address
If present, it becomes a PostalAddress.
Same structure as the Organization address.
geo
If present, it becomes GeoCoordinates.
It sets
- [at]type GeoCoordinates
- latitude
- longitude
openingHoursSpecification
If present and non empty, each item becomes OpeningHoursSpecification.
It sets [at]type OpeningHoursSpecification.
Then it spreads the input fields.
Those include
- dayOfWeek as an array of strings
- opens
- closes
sameAs
If present, it is added as a list of URLs.
areaServed
If present, it becomes a City.
It sets [at]type City.
It sets name.
SEO value of RealEstateAgent schema
- It defines an entity that can be referenced.
- It can support local intent signals.
- It can connect contact details and location.
- It can help clarify the business type.
LocalBusiness schema
Generator
LocalBusiness schema generator
Goal
This function describes a LocalBusiness entity.
This is a generic business listing schema.
It can represent branches or offices.
Input interface
LocalBusinessSchemaOptions
Required
- name
- url
Optional
- image
- telephone
- priceRange
- address
- geo
- openingHoursSpecification
- sameAs
Output shape
Base object
- [at]context https://schema.org
- [at]type LocalBusiness
- name
- [at]id equals url
- url
Optional fields are handled similarly to RealEstateAgent.
SEO value of LocalBusiness schema
- It supports local SEO context.
- It provides address and geo coordinates.
- It can support knowledge panel consistency.
- It can connect opening hours.
Service schema
Generator
Service schema generator
Goal
This function describes a Service.
A Service schema can represent what you offer.
It can connect a service type to a provider.
It can attach offers.
Input interface
ServiceSchemaOptions
Required
- serviceType
- provider
Optional
- areaServed
- description
- offers
Provider object
provider has
- name
- url
- logo
- sameAs optional
Output shape
Base object
- [at]context https://schema.org
- [at]type Service
- serviceType
- provider as an Organization
Provider is set to
- [at]type Organization
- name
- url
- logo
Provider sameAs
If provider.sameAs exists and is non empty, it is attached.
This uses a type cast to edit schema.provider.
areaServed
If present, it becomes a Place.
It sets
- [at]type Place
- name
description
If present, it is added.
offers
If offers exists, it creates an Offer object.
It sets [at]type Offer.
Then it spreads all fields from offers.
Offer fields can include
- url
- priceCurrency
- price
- priceSpecification
- availability
priceSpecification
If priceSpecification exists, it becomes a PriceSpecification object.
It sets [at]type PriceSpecification.
Then it spreads the priceSpecification fields.
Those fields can include
- price
- priceCurrency
- validFrom
SEO value of Service schema
- It clarifies what you do.
- It can connect a service to the provider entity.
- It can expose offer like details.
- It can support better matching to intent.
BlogPosting schema
Generator
BlogPosting schema generator
Goal
This function builds BlogPosting structured data.
It is used for blog content.
It can help eligibility for article rich results.
It can help publishers clarify authorship.
Input interface
BlogPostingSchemaOptions
Required
- mainEntityOfPage.url
- headline
- author.name
- publisher.name
- publisher.logo
- datePublished
Optional
- description
- image
- author.url
- dateModified
Output shape
Base object includes
- [at]context https://schema.org
- [at]type BlogPosting
- mainEntityOfPage as WebPage with [at]id set to URL
- headline
- author as Person with name
- publisher as Organization with name and logo ImageObject
- datePublished
Conditional fields
If description exists, it is added.
If image exists, it is added.
If author.url exists, author.url is attached.
If dateModified exists, dateModified is attached.
SEO value of BlogPosting schema
- It clarifies that content is a blog post.
- It clarifies author and publisher.
- It provides publish and modified dates.
- It helps search engines understand content freshness.
Article schema
Generator
Article schema generator
Goal
This function builds Article structured data.
It is similar to BlogPosting.
It is useful for editorial content and guides.
Input interface
ArticleSchemaOptions
Required
- mainEntityOfPage.url
- headline
- author.name
- publisher.name
- publisher.logo
- datePublished
Optional
- description
- image string or string array
- author.url
- dateModified
- keywords
Output shape
Base object includes
- [at]context https://schema.org
- [at]type Article
- mainEntityOfPage WebPage with [at]id
- headline
- author Person
- publisher Organization and ImageObject logo
- datePublished
Image handling
If image exists, it ensures schema.image is an array.
If the input is already an array, it uses it.
If the input is a string, it wraps it as a single element array.
This is convenient for consumers.
keywords
If keywords exists, it is added.
This is a plain string in this implementation.
Sometimes keywords is provided as comma separated.
SEO value of Article schema
- It clarifies content type as an article.
- It improves author and publisher clarity.
- It can help with article rich results.
- It supports date signals.
SoftwareApplication schema
Generator
SoftwareApplication schema generator
Goal
This function describes a software application.
This is appropriate for a SaaS platform.
It can help search engines understand your product.
It can connect offers and ratings.
Input interface
SoftwareApplicationSchemaOptions
Required
- name
- applicationCategory
- description
- url
- author.name
- author.url
Optional
- operatingSystem
- image
- offers
- aggregateRating
- applicationSubCategory
- softwareVersion
Output shape
Base object includes
- [at]context https://schema.org
- [at]type SoftwareApplication
- name
- applicationCategory
- description
- url
- author as Organization with name and url
operatingSystem
If present, it is attached.
For web apps, you might use Web.
For native apps, you might use iOS or Android.
image
If present, it is attached.
Provide an absolute URL.
offers
If offers exists, it builds an Offer object.
Offer includes
- [at]type Offer
- price
- priceCurrency
- availability
- url optional
aggregateRating
If present, it becomes AggregateRating.
It sets
- [at]type AggregateRating
- ratingValue
- ratingCount
applicationSubCategory and softwareVersion
If present, they are attached.
These can help describe versions and sub type.
SEO value of SoftwareApplication schema
- It clarifies your product as software.
- It can display pricing and availability.
- It can support rating snippets depending on policy.
- It helps search engines understand app category.
JobPosting schema
Generator
JobPosting schema generator
Goal
This function describes a job listing.
JobPosting can enable job rich results.
It can help distribute your job posts.
Input interface
JobPostingSchemaOptions
Required
- title
- description
- datePosted
- validThrough
- employmentType
- hiringOrganization.name
Optional
- identifier
- hiringOrganization.sameAs
- hiringOrganization.logo
- jobLocation
- remote
- applicantLocationRequirements
- baseSalary
- responsibilities
- qualifications
- skills
- educationRequirements
- experienceRequirements
- incentiveCompensation
- industry
- jobBenefits
Output shape
Base object includes
- [at]context https://schema.org/
- [at]type JobPosting
- title
- description
- datePosted
- validThrough
- employmentType
- hiringOrganization as Organization
identifier
If identifier exists, it becomes PropertyValue.
It sets
- [at]type PropertyValue
- name
- value
hiringOrganization fields
If sameAs exists, it is attached.
If logo exists, it is attached.
jobLocation
If jobLocation exists, it becomes Place with PostalAddress.
remote
If remote is provided, it sets schema.remote to a string.
It uses options.remote.toString.
This results in true or false as strings.
Some consumers expect a boolean.
But this is the current behavior.
If you depend on strict schema validation, review this.
applicantLocationRequirements
If provided, it becomes a Country object with name.
baseSalary
If provided, it builds MonetaryAmount.
It sets
- [at]type MonetaryAmount
- currency
- value as QuantitativeValue
QuantitativeValue includes
- [at]type QuantitativeValue
- unitText
- minValue optional
- maxValue optional
Responsibilities and other text fields
If provided, they are attached as strings.
This includes responsibilities, qualifications, skills, and more.
SEO value of JobPosting schema
- It can enable job rich results.
- It improves job distribution.
- It clarifies salary and location.
- It clarifies employer identity.
FAQPage schema
Generator
FAQPage schema generator
Goal
This function creates FAQPage structured data.
FAQ structured data can produce FAQ rich results.
It is often used on landing pages.
It can also be used on documentation pages.
Input interface
FAQSchemaOptions
- items is an array of question and answer.
Behavior for empty data
If items is missing or empty, the function returns null.
This is important.
It prevents injecting an empty FAQPage.
It also avoids invalid schema.
Output shape
- [at]context https://schema.org
- [at]type FAQPage
- mainEntity as an array
Each item becomes
- [at]type Question
- name set to the question
- acceptedAnswer as Answer
- acceptedAnswer.text set to the answer
SEO value of FAQPage schema
- It answers common questions directly.
- It can expand SERP snippets.
- It can increase click through when implemented correctly.
- It can improve relevance understanding.
Helper Current page URL builder
Goal
This helper builds the current page absolute URL.
It uses the route path.
It ensures language prefix is consistent.
It removes locale segments from the route.
Logic
- path is route.path
- langPrefix is /en when locale is en
- otherwise langPrefix is empty
- cleanPath removes a leading /en or /ar
- if the route becomes empty, it uses /
- it returns baseUrl + langPrefix + cleanPath
Why this matters for SEO
Absolute URLs are preferred inside schema.
A consistent URL reduces duplicate entity identities.
Locale paths can cause duplicates if not handled.
This helper ensures a stable, localized URL.
Helper Breadcrumb builder from route
Goal
This helper generates breadcrumb items automatically.
It uses route.path.
It splits the path into segments.
It skips locale segments.
It builds cumulative URLs.
It generates readable names.
Output
It returns an array of
- name
- item
The first breadcrumb is always Home.
If locale is ar, it uses العربية.
If locale is not ar, it uses Home.
The Home item is baseUrl + /.
Name generation details
For each non locale segment
- it splits by hyphen
- it capitalizes the first letter of each word
- it joins with space
So a segment like property-management becomes
Property Management
URL generation details
It builds currentPath incrementally.
It uses langPrefix based on locale.
It builds fullPath as baseUrl + langPrefix + currentPath.
Then it pushes { name, item }.
SEO value of auto breadcrumbs
Even if you render breadcrumbs in UI, schema breadcrumbs help crawlers.
They provide a machine readable hierarchy.
They can reduce ambiguity on nested routes.
They can improve display snippets.
Integration guidance
The composable returns generator functions.
A typical usage pattern is
- Build schema objects based on page data
- Serialize them to JSON
- Inject into head as JSON LD
Example high level approach
- For a homepage
- Organization
- WebPage
- BreadcrumbList with just Home
- Service or LocalBusiness as mainEntity
- For a blog post page
- BlogPosting
- WebPage with mainEntity set to BlogPosting
- BreadcrumbList
- For a guide page
- Article
- WebPage with mainEntity set to Article
- For a FAQ landing page
- FAQPage
- WebPage with mainEntity set to FAQPage
- For careers
- JobPosting
- WebPage with mainEntity set to JobPosting
Data quality checklist
Use absolute URLs everywhere.
Make sure baseUrl matches your production domain.
Make sure routes generate canonical paths.
Use consistent trailing slash rules.
Do not generate multiple conflicting schemas for the same entity.
Use [at]id consistently when you want to connect entities.
Make sure date strings are valid ISO 8601.
Make sure images are accessible and indexable.
Make sure logos are high quality and stable.
Provide sameAs links that are official.
Avoid placeholder values.
Avoid empty arrays.
Avoid injecting null schema.
Common mistakes and how this file avoids them
It only adds optional fields when they exist.
It maps arrays only when they have length.
It wraps Article image into an array.
It returns null for empty FAQ items.
It sets context and type explicitly.
It uses stable baseUrl.
Potential improvements you may consider
The JobPosting remote field is a string.
Some schema validators might expect a boolean or a different field.
If you see validation warnings, adjust accordingly.
The Organization founder field is a string.
Schema.org often allows Person or Organization.
If you need richer founder data, model it as a Person object.
The composable does not implement WebSite schema.
It uses Website type inside isPartOf.
If you want a full WebSite schema, add a generator.
The composable does not implement WebSite SearchAction.
If you have a site search, you can add it for sitelinks search box.
Testing structured data
After you inject JSON LD, test the page.
Use a structured data testing tool.
Validate that required fields exist.
Validate that URLs resolve.
Validate that language matches content.
Validate that breadcrumbs match navigation.
Validate that FAQ matches visible content.
Final summary
This module is a structured data factory.
It centralizes Schema.org JSON LD generation.
It supports multiple content types.
It supports localization aware URL helpers.
It supports breadcrumb automation.
Its SEO value comes from clarity.
Clarity supports richer understanding.
Richer understanding supports better presentation.
Appendix A Field by field quick reference
Organization
[at]context
[at]type
name
url
logo
alternateName
description
founder
foundingDate
foundingLocation
telephone
email
address PostalAddress
contactPoint ContactPoint array
sameAs array
WebPage
[at]context
[at]type
url
name
description
inLanguage
isPartOf Website
publisher Organization with logo ImageObject
mainEntity any schema object
datePublished
dateModified
BreadcrumbList
[at]context
[at]type
itemListElement ListItem array
ListItem position
ListItem name
ListItem item
RealEstateAgent
[at]context
[at]type
name
[at]id
url
image
telephone
email
priceRange
address PostalAddress
geo GeoCoordinates
openingHoursSpecification array
sameAs array
areaServed City
LocalBusiness
[at]context
[at]type
name
[at]id
url
image
telephone
priceRange
address PostalAddress
geo GeoCoordinates
openingHoursSpecification array
sameAs array
Service
[at]context
[at]type
serviceType
provider Organization
provider sameAs
areaServed Place
description
offers Offer
offers priceSpecification PriceSpecification
BlogPosting
[at]context
[at]type
mainEntityOfPage WebPage [at]id
headline
description
image
author Person name and url optional
publisher Organization with logo ImageObject
datePublished
dateModified
Article
[at]context
[at]type
mainEntityOfPage WebPage [at]id
headline
description
image array
author Person
publisher Organization with logo ImageObject
datePublished
dateModified
keywords
SoftwareApplication
[at]context
[at]type
name
applicationCategory
applicationSubCategory
description
url
operatingSystem
image
author Organization
offers Offer
aggregateRating AggregateRating
softwareVersion
JobPosting
[at]context
[at]type
title
description
identifier PropertyValue
datePosted
validThrough
employmentType
hiringOrganization Organization
jobLocation Place with PostalAddress
remote string
applicantLocationRequirements Country
baseSalary MonetaryAmount with QuantitativeValue
responsibilities
qualifications
skills
educationRequirements
experienceRequirements
incentiveCompensation
industry
jobBenefits
FAQPage
[at]context
[at]type
mainEntity Question array
Question name
acceptedAnswer Answer
Answer text
Appendix B Practical injection pattern
1 Generate the schema object.
2 JSON stringify it.
3 Inject it into a script tag in the page head.
4 Ensure the schema matches what users see.
5 Validate.
6 Monitor search console for enhancements.
Top comments (0)