Structured data for a services business
What to mark up when you sell work rather than products, what it gets you, and the markup that will earn you a manual action.
What is in this
Most structured data advice is written for e-commerce, where the payoff is obvious: a price, a stock status and a star rating attached to your listing. A services business has none of those, which leaves people either skipping it or reaching for markup they are not entitled to.
Here is what actually applies when you sell work, taken from this site's own build.
The types that apply
Four, and they do different jobs.
LocalBusiness or ProfessionalService. This is the entity: who you are, where you are, what area you serve. Use both types on one node if you are a professional service with a location, because they answer different questions. ProfessionalService says what kind of business it is; LocalBusiness is the type local results key off, and without it your address is a fact on a page rather than a place.
Person. Worth having if you are the business, or if a named person is the reason anyone hires you. It is what lets an engine connect the author of a post to the founder of the company to the speaker at a conference.
Service, inside an OfferCatalog. One node per thing you actually sell. This is where a services business does the work that an e-commerce site does with products, and it is the part most sites skip.
BreadcrumbList and FAQPage. The two that visibly change a search listing. Breadcrumbs replace the URL in the result with a readable trail. FAQ markup has been narrowed over the years and still earns expansion for some sites, and both are trivial to emit from content you already have on the page.
For a blog, add BlogPosting. Not because it draws a rich result any more, but because it makes the dates, the author and the subject explicit to anything reading the page, which increasingly includes things that are not search engines.
Connecting them with @id
This is the part that gets left out, and it is where most of the value is.
A page with four separate blocks of markup describes four unconnected things. A page where the Service nodes belong to a business, the business has a founder, and that founder is the Person who wrote the article describes one entity with a shape.
The mechanism is @id. Give each node a stable identifier, usually a URL with a fragment, and refer to it from the others rather than repeating the object.
On this site the business is #business, the person is #person and the site itself is #website. The business's founder points at #person. The WebSite node's publisher points at #business. An article's author points at #person again. Nothing is described twice, and nothing can drift out of agreement with itself, which is the practical benefit: one place to change the description of the business.
Use @graph to put the nodes in one block. Multiple separate ld+json blocks are also valid and get merged, which matters when a component rendered inside an article needs to emit its own node without reaching the page's props.
Reviews and the self-serving rating trap
Now the part worth writing this post for.
It is tempting, when you have happy clients, to mark up an aggregateRating on your own business. The markup is easy, the stars are the most visible rich result there is, and plenty of sites do it.
It is against Google's policy. Reviews collected and displayed by the business about itself are self-serving, and marking them up is a documented reason for a manual action against the site. The penalty is not that the stars fail to appear. It is that structured data enforcement is applied to the domain.
Where the line falls on reviews
Fine to mark up
- A review you wrote about something else
- Ratings on a third-party platform, on that platform
- A testimonial shown as ordinary page content
- Client names and logos, with permission
Self-serving, do not
- aggregateRating on your own business node
- Review nodes for testimonials you collected
- A rating assembled from a form on your own site
- Any of the above with a source you cannot show
The testimonials themselves are fine. Put them on the page, name the client, make them real. What you cannot do is wrap them in markup that asks a search engine to print stars beside your listing on your own authority.
The same instinct causes two smaller problems worth naming. Marking up content that is not on the page is against policy and easy to do by accident when the markup is generated from a CMS field the template stopped rendering. And inventing a priceRange you do not publish anywhere is a claim with nothing behind it; if your prices are not public, leave the field out rather than guessing.
Checking it
Three things, and they answer different questions.
The Rich Results Test tells you whether Google can parse it and which rich results it is eligible for. This is the one to use while building.
Schema.org's validator tells you whether the markup is valid schema, which is a wider question than whether Google has a feature for it. Useful precisely because the interesting types for a services business often have no rich result attached.
Search Console's enhancement reports tell you what is happening at scale on the live site, which is the only place a template-level mistake shows up as a pattern rather than one bad page.
Then the thing nobody does: view the source of a page you did not build, and read what your CMS actually emitted. Structured data is invisible on the page, which means it is the easiest thing on a site to break without anybody noticing. It is also the first thing lost in a migration, for exactly that reason.
The performance page shows the artifacts this site ships, including the markup described here. Most of the argument for doing any of this now is not about rich results at all: it is that the things reading your pages are increasingly not search engines, and structured data is the only part of a page that tells them what they are looking at.
Also worth reading
-
Performance
Getting cited by AI search, for a site with ten pages
llms.txt, structured data and the machine-readable artifacts, and an honest assessment of which of them anything currently reads.
-
Performance
Core Web Vitals, explained for the person who has to fix them
Three metrics, what each actually measures, and which of your problems each one is telling you about. Without the jargon.
-
Platform limits
Custom code in Webflow, and where it belongs
Webflow's code fields have a hard character limit and no version control. What belongs in them, what belongs elsewhere, and how to keep a site maintainable either way.
Reach out and see if we are a good fit.
Currently booking two to four weeks out.