Structured data, settled
Schema Markup for Therapists: The Type That Fits Your License, the JSON-LD to Paste, and How to Prove It Worked
If you are looking for Schema Therapy, the treatment approach developed by Jeffrey Young, this is not that page. This page is about schema.org markup, the code that tells search engines what your practice is.
Somebody told you your website needs schema markup and did not explain what that means. Two questions matter: which type applies to your license, and what exactly do you paste. Both are answered below, with two complete blocks to copy.
By Emirhan Cetin, founder. Checked 6 September 2026.

The short answer
Most therapy practices should declare two types at once, ["MedicalBusiness", "MedicalOrganization"], and never Physician unless a prescriber runs the practice. Schema markup does not lift your position by itself. It makes your practice legible to machines and decides how the listing can be drawn. Two complete blocks follow, one solo and one group, both copy and paste.
01 Expectations
What schema markup does for a therapy practice, and what it does not
It does not raise your position in the search results. Google treats structured data as a description of the page rather than a vote for it, so nothing here moves a ranking on its own. What it buys is eligibility for how your entry is drawn, and a clean set of facts for anything trying to work out which practice you are. Both are worth having. Neither is a growth lever by itself.
I have not run a controlled before-and-after schema test on a therapist website, so there is no number from me. What I can tell you is what the markup is for. It resolves ambiguity. Search engines and answer engines are trying to decide whether the Riverside Counseling on your website is the same Riverside Counseling in the directory listing and the Business Profile, and consistent structured data is the cheapest way to make that answer obvious.
If you want the inventory version of this topic, which schema types exist and what each one is for, that is already written up in the guide to schema markup for therapy websites.
The finding this page is built on
There is no Psychologist type in schema.org. Requesting that URL returns a 404. If you were told to use one, it does not exist.
02 The type
The type problem: schema.org was built for physicians, not therapists
schema.org has a type for a physician, a hospital and a clinic. It has none for a therapist and none for a psychologist. The type that fits a talk-therapy practice is a two-item array, ["MedicalBusiness", "MedicalOrganization"].
Why Physician is the wrong type for an LCSW, LMFT or LPC
Physician is a subtype of MedicalOrganization reserved for medical practitioners. Putting it on a counseling practice asserts a license nobody in the building holds, in a machine-readable format, on a page a board could read. It is not a clever reclassification, it is a false statement about your credentials. Say it once and move on: unless somebody at the practice prescribes, Physician is not your type.
Psychologists get the same answer for a different reason. There is no Psychologist type to choose. Request schema.org/Psychologist and the response is a 404, because that class was never defined. A doctorate belongs on a Person node through jobTitle, honorificSuffix and hasCredential, not in a type name. The psychologists page covers what else changes at doctoral level.
MedicalBusiness: what you get, and the two properties you quietly lose
MedicalBusiness is defined as covering different businesses run by health professionals, which fits a private practice exactly. It inherits LocalBusiness and then Organization, so you get address, geo, openingHoursSpecification, telephone and priceRange. That is the local layer, and it is most of what you need.
It does not inherit MedicalOrganization. So isAcceptingNewPatients, medicalSpecialty and healthPlanNetworkId are not in its vocabulary at all. The single fact a person searching for a therapist most wants, whether you have space, cannot be expressed on the type you were told to use.
MedicalOrganization and MedicalClinic: where isAcceptingNewPatients lives
MedicalClinic is the one type that descends from both branches, which is why it carries medicalSpecialty and availableService alongside the local properties. The catch is its definition, a facility often associated with a hospital or a medical school. That is a poor description of one clinician and a waiting room with two chairs.
The resolution is a multi-type array. JSON-LD lets a node declare more than one type, so ["MedicalBusiness", "MedicalOrganization"] gives you both property sets, asserts no license anybody lacks, and validates clean. It is legal and it is boring. Group practices with a real office can reasonably use ["MedicalClinic", "MedicalBusiness"] instead.
Your license, your type: the decision table
Find your row, use that type, and stop researching. The only row where Physician belongs anywhere is the prescriber row, and even there it goes on the clinician rather than on the business.
| Your license | What you were probably told | Type on the practice node | Person node too? | medicalSpecialty |
|---|---|---|---|---|
| LCSW, LMFT, LPC, LPCC | Physician, or MedicalBusiness on its own. Physician asserts a license nobody in the building holds, and MedicalBusiness alone cannot say whether you are taking new clients. | ["MedicalBusiness", "MedicalOrganization"] | Yes, one Person node | No, use knowsAbout |
| Psychologist (PhD, PsyD) | schema.org/Psychologist. That URL returns a 404, so the type does not exist. | ["MedicalBusiness", "MedicalOrganization"] | Yes, one Person node | No, use knowsAbout |
| Psychiatrist or PMHNP | Physician on the business. It is the right type here, but it belongs on the clinician. | ["MedicalBusiness", "MedicalOrganization"] | Yes, and Physician on the Person | Yes, Psychiatric |
| Group practice with an office | LocalBusiness, or MedicalBusiness on its own. Neither can say whether the practice is taking new clients. | ["MedicalClinic", "MedicalBusiness"] | One per clinician, each with its own id | Only if the practice prescribes |
| Online only, no public address | LocalBusiness, or MedicalBusiness on its own. Neither can say whether you are taking new clients. | ["MedicalBusiness", "MedicalOrganization"] | Yes, one Person node | No, use knowsAbout |
The psychiatrist row is the only one where Physician is correct, and even there it belongs on the clinician, not on the business. Online-only practices drop address and geo and carry areaServed instead.
03 The code
Copy this: complete JSON-LD for a solo therapist
Paste this into the head of your website, change the details to yours, and validate it. It is three nodes joined by @id: the practice, the clinician, and a catalog of what you offer. Nothing is elided and nothing is a placeholder. The practice in it is invented, the structure is not.
JSON-LD
{
"@context": "https://schema.org",
"@graph": [
{
"@type": ["MedicalBusiness", "MedicalOrganization"],
"@id": "https://riversidecounseling.com/#practice",
"name": "Riverside Counseling",
"url": "https://riversidecounseling.com/",
"telephone": "+1-503-555-0142",
"email": "hello@riversidecounseling.com",
"address": {
"@type": "PostalAddress",
"streetAddress": "1200 SW Morrison St, Suite 410",
"addressLocality": "Portland",
"addressRegion": "OR",
"postalCode": "97205",
"addressCountry": "US"
},
"geo": {
"@type": "GeoCoordinates",
"latitude": 45.5219,
"longitude": -122.6842
},
"areaServed": [
{ "@type": "State", "name": "Oregon" },
{ "@type": "State", "name": "Washington" }
],
"openingHoursSpecification": [
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday"],
"opens": "09:00",
"closes": "17:00"
}
],
"isAcceptingNewPatients": true,
"priceRange": "$$",
"paymentAccepted": "Cash, Credit Card, HSA, FSA",
"currenciesAccepted": "USD",
"founder": { "@id": "https://riversidecounseling.com/#jordan-reyes" },
"employee": { "@id": "https://riversidecounseling.com/#jordan-reyes" },
"hasOfferCatalog": { "@id": "https://riversidecounseling.com/#services" },
"sameAs": [
"https://www.psychologytoday.com/us/therapists/jordan-reyes-portland-or/123456",
"https://www.linkedin.com/in/jordanreyeslcsw/"
]
},
{
"@type": "Person",
"@id": "https://riversidecounseling.com/#jordan-reyes",
"name": "Jordan Reyes",
"honorificSuffix": "LCSW",
"jobTitle": "Licensed Clinical Social Worker",
"url": "https://riversidecounseling.com/about/",
"image": "https://riversidecounseling.com/images/jordan-reyes.jpg",
"worksFor": { "@id": "https://riversidecounseling.com/#practice" },
"knowsAbout": [
"Cognitive Behavioral Therapy",
"EMDR",
"Perinatal mental health",
"Anxiety"
],
"hasCredential": {
"@type": "EducationalOccupationalCredential",
"name": "Licensed Clinical Social Worker",
"credentialCategory": "license",
"identifier": "L1234",
"recognizedBy": {
"@type": "Organization",
"name": "Oregon Board of Licensed Social Workers"
}
},
"alumniOf": {
"@type": "CollegeOrUniversity",
"name": "Portland State University"
},
"sameAs": [
"https://www.psychologytoday.com/us/therapists/jordan-reyes-portland-or/123456"
]
},
{
"@type": "OfferCatalog",
"@id": "https://riversidecounseling.com/#services",
"name": "Services",
"itemListElement": [
{
"@type": "Offer",
"itemOffered": {
"@type": "Service",
"name": "Individual therapy, 50 minutes",
"provider": { "@id": "https://riversidecounseling.com/#practice" }
},
"priceSpecification": {
"@type": "PriceSpecification",
"price": 180,
"priceCurrency": "USD"
}
}
]
}
]
}The block, node by node
The first node is the practice: both types, the address, the hours, the coordinates, and isAcceptingNewPatients, which is only legal here because of the second type in the array. The second is the clinician as a Person, pointing back with worksFor while the practice points forward with employee. The third is an OfferCatalog carrying one service and its price.
The @id values are what hold it together. They are URIs, not page addresses, so a fragment on your own domain is the correct form. Use the same string every time you refer to a node and search engines treat every mention as one entity. Change one character and you have created a second practice that shares your phone number. Add the block once, in the site head, rather than pasting a copy into every page and letting the copies drift apart.
Your license goes in hasCredential, not in a property you invented
EducationalOccupationalCredential with credentialCategory set to license, an identifier holding your license number, and recognizedBy naming the actual board that issued it. That last field is the one doing real work: it names a body whose public register anybody can open and check you against. That is a verifiable credential rather than a claim, which is the whole point of putting it in the markup at all. The E-E-A-T guide covers why that matters for health content.
Invented properties do nothing, quietly
acceptedInsurance or yearsExperience to a node will not break the block and will not earn a penalty. Parsers drop terms that are not in the vocabulary and carry on. That is worse than an error, because the block still validates and you believe you published a fact that nothing ever read. Check every property against schema.org before you ship it.04 Group practice
A group practice as one connected entity: the @id pattern
A five-clinician practice is one organization with several people in it, and the markup has to say so. One practice node, one Person node per clinician with a stable @id, and the same @id repeated on every page that mentions them. Get that right and you have one entity. Get it wrong and you have five unrelated ones.
JSON-LD
{
"@context": "https://schema.org",
"@graph": [
{
"@type": ["MedicalClinic", "MedicalBusiness"],
"@id": "https://eastbaytherapygroup.com/#practice",
"name": "East Bay Therapy Group",
"url": "https://eastbaytherapygroup.com/",
"telephone": "+1-510-555-0188",
"isAcceptingNewPatients": true,
"address": {
"@type": "PostalAddress",
"streetAddress": "88 Grand Ave, Suite 200",
"addressLocality": "Oakland",
"addressRegion": "CA",
"postalCode": "94612",
"addressCountry": "US"
},
"employee": [
{ "@id": "https://eastbaytherapygroup.com/#dana-okafor" },
{ "@id": "https://eastbaytherapygroup.com/#sam-liu" }
],
"department": { "@id": "https://eastbaytherapygroup.com/#berkeley-office" }
},
{
"@type": "Person",
"@id": "https://eastbaytherapygroup.com/#dana-okafor",
"name": "Dana Okafor",
"honorificSuffix": "LMFT",
"url": "https://eastbaytherapygroup.com/team/dana-okafor/",
"worksFor": { "@id": "https://eastbaytherapygroup.com/#practice" },
"knowsAbout": ["Couples therapy", "Emotionally Focused Therapy"],
"hasCredential": {
"@type": "EducationalOccupationalCredential",
"name": "Licensed Marriage and Family Therapist",
"credentialCategory": "license",
"identifier": "MFC98765",
"recognizedBy": {
"@type": "Organization",
"name": "California Board of Behavioral Sciences"
}
}
},
{
"@type": "Person",
"@id": "https://eastbaytherapygroup.com/#sam-liu",
"name": "Sam Liu",
"honorificSuffix": "PsyD",
"url": "https://eastbaytherapygroup.com/team/sam-liu/",
"worksFor": { "@id": "https://eastbaytherapygroup.com/#practice" },
"knowsAbout": ["Psychological assessment", "ADHD evaluation"]
},
{
"@type": ["MedicalClinic", "MedicalBusiness"],
"@id": "https://eastbaytherapygroup.com/#berkeley-office",
"name": "East Bay Therapy Group, Berkeley",
"url": "https://eastbaytherapygroup.com/berkeley/",
"parentOrganization": { "@id": "https://eastbaytherapygroup.com/#practice" },
"address": {
"@type": "PostalAddress",
"streetAddress": "1919 Addison St",
"addressLocality": "Berkeley",
"addressRegion": "CA",
"postalCode": "94704",
"addressCountry": "US"
}
}
]
}One organization, many Person nodes
MedicalClinic is defensible for a group with a physical office, and it brings medicalSpecialty and availableService with it. Only set medicalSpecialty to Psychiatric if the practice really does have prescribers, because that is a physician specialty and the enumeration has no member that means talk therapy. Each clinician gets a Person node, their own bio page URL, and their own license in hasCredential.
One @id, repeated on every page
Each clinician’s bio page repeats only their own Person node, with the identical @id and a worksFor reference back to the practice. It does not re-declare the whole organization. Repeating the same identifier everywhere is exactly what makes five pages describe one team instead of five strangers. A second office becomes a department of the parent, with parentOrganization pointing back, and it gets its own address rather than borrowing the main one. The group practice guide covers the rest of what changes at that size.
This is also the most common thing to break. A clinician leaves, the bio page is deleted, and the practice node keeps pointing at an @id that resolves to nothing. Removing a person means removing them from employee too.
05 The gaps
Insurance and specialties: the properties schema.org does not have
Two of the facts clients most want cannot be expressed properly in schema.org. There is no property for the insurance you accept, and the specialty enumeration has no member for talk therapy. Both have honest workarounds. Neither workaround is inventing a property and hoping.
There is no acceptedInsurance property. Here is what to do instead
The only native hook is healthPlanNetworkId on MedicalOrganization, and it wants a network identifier rather than the word Aetna, so for most practices it is unusable. Use it only if you genuinely know your network ID. Otherwise put the plan names in visible text on the page, where a human reader and an answer engine can both find them, and use Offer with PriceSpecification for your self-pay rate. Visible text is not a consolation prize here. It is the thing that gets read.
medicalSpecialty has no member for talk therapy
The MedicalSpecialty enumeration runs from Anesthesia to Urologic. The closest member to what you do is Psychiatric, which is a physician specialty, so a non-prescribing therapist claiming it is back in the same false-credential territory as Physician. Omit the property and carry your specialties in knowsAbout on the Person node instead, which is a free-text list and describes expertise rather than asserting a medical classification.
"knowsAbout": [
"Cognitive Behavioral Therapy",
"EMDR",
"Perinatal mental health",
"Grief and loss"
]06 Limits
What never goes in your markup: HIPAA limits and the review rule
Structured data is published to the open web, so everything in it is public by definition. Nothing client-specific belongs anywhere near it. And the star ratings you were hoping for from your own testimonials are not available to a therapy practice for two separate reasons, either of which would be enough on its own.
Markup is public, so nothing client-specific goes in it
Safe: sameAs pointing at your Psychology Today or LinkedIn profile, which is public business information rather than protected health information, and knowsAbout listing the conditions you treat, which describes your expertise and names no patient. Not safe: any review node quoting a client, and any potentialAction or booking URL that posts intake answers to a third-party endpoint you have no business associate agreement with. The HIPAA website checklist covers the rest of the surface.
Why your testimonials will not produce star ratings
Google’s self-serving review policy, published in 2019, says it does not show review rich results for LocalBusiness and Organization or their subtypes when the entity controls the reviews. MedicalBusiness is a subtype of LocalBusiness, so that is every therapy practice on earth. The current review snippet documentation goes further and no longer lists LocalBusiness among supported types at all. Marking up testimonials you host yourself cannot win stars and can earn a manual action.
And your board restricts asking in the first place
07 Proof
Proving it worked: two validators and the report in Search Console
Paste the URL into the Schema Markup Validator to find out whether the JSON-LD is legal, then into the Rich Results Test to find out whether Google will draw anything with it. They disagree constantly, both answers matter, and the third check is the Enhancements section of Search Console once the page has been crawled.
Rich Results Test against Schema Markup Validator
The validator parses everything and tells you if a property sits on a type that does not define it, which is precisely how you would have caught the MedicalBusiness problem yourself. The Rich Results Test only reports the handful of types Google draws differently in the search results, so it will often say nothing about your practice node at all. That is the expected outcome, not a bug, and it is the single most common reason people think their markup failed.
What a real error looks like, and what to ignore
The rule is short. Fix everything labeled an error, because those are properties in the wrong place or values in the wrong format. Read the warnings, which are usually recommended fields you left empty, and add the ones you can honestly fill. Ignore any message that only tells you the page is not eligible for a rich result when the type was never eligible to begin with. Then check Search Console a week later: the Enhancements reports are the only place that tells you what Google saw on the live crawl rather than on demand.
To see what any other site is running, view source and search for application/ld+json, or drop the URL into the validator and read the type list it returns. That is also how you audit a competitor in about thirty seconds, and how you check whether the plugin you installed is emitting anything at all.
Rich Results Test
What will Google draw?
- Only reports types Google has a rich result for.
- Silence about your practice node is the normal outcome, not a fault.
- Renders a preview of what the listing could look like.
Schema Markup Validator
Is the JSON-LD legal?
- Parses everything, whether or not Google renders it.
- Flags a property used on a type that does not define it, which is the whole MedicalBusiness problem in one line.
- The one to run first, and the one to run after every edit.
Valid in one and invisible in the other is the expected result for a therapy practice. Fix errors. Read warnings. Ignore anything that only says the type was never eligible for a rich result.
Checked 6 September 2026
FAQ rich results were deprecated in May 2026 and the documentation was removed in June.
08 2026
What changed in 2026, and what still earns a rich result
Two features are gone. FAQ rich results were restricted to government and health sites in 2023, deprecated in May 2026, and the documentation was removed in June. Self-hosted review stars were never available to a LocalBusiness subtype. What still works is duller and more durable.
Keep the FAQPage markup anyway. It is still valid schema.org, it costs nothing to leave in place, and answer engines read the page source whether or not Google draws a widget from it. What has changed is the reason for writing it: it is no longer a way to take up more room in the search results.
What still produces something visible in the search results: breadcrumbs, which most site builders emit already; Article on blog content; and the organization data that feeds a knowledge panel, which is corroborated by your website but driven mainly by a verified Business Profile. For a therapy practice that last one is where the effort pays, and it pays through consistency rather than cleverness.
| Feature | Status, checked 6 September 2026 | Worth it for a therapy site |
|---|---|---|
| FAQ rich result | Restricted to government and health sites in August 2023, deprecated May 2026, documentation removed June 2026 | Keep the markup, expect no listing change |
| Review stars from your own testimonials | Not shown for LocalBusiness and its subtypes when the business controls the reviews. LocalBusiness is no longer listed as a supported type at all | Do not mark these up |
| Breadcrumb | Supported | Yes, and most site builders emit it already |
| Article | Supported | Yes, on the blog, not on service pages |
| Organization and site name | Supported | Yes, this is where the effort pays |
| Business Profile knowledge panel data | Fed mainly by your verified profile, corroborated by the site | Yes, and consistency is the whole job |
09 AI search
Does schema markup affect AI Overviews?
Partly, and less directly than it is sold. Structured data helps an answer engine resolve which entity you are, which matters when another practice two states over shares your name. What nobody outside Google can show is a confirmed weighting of JSON-LD in whether an AI Overview cites you.
Entity resolution is the real mechanism and it is worth the work on its own. A model summarizing sources has to decide whether three mentions of a practice name refer to one business. Consistent @id values, a sameAs pointing at profiles that already exist, and a phone number that matches every healthcare directory you are listed in make that decision easy. Three different phone numbers across three listings make it impossible, and that is a real problem this fixes.
The honest limit of the evidence: nobody has published a controlled test isolating schema from everything else a page does, and I have not run one either. Clean markup travels with clean structure and a page that answers its question, so anyone claiming a number for schema alone is separating things that in practice never move separately. The AI search guide goes through what is measurable. One related point while it comes up: Google stated in August 2026 that it does not use llms.txt files for Search and that they neither help nor hurt visibility.
10 Upkeep
When to touch your schema again, and where the plugins stop
Markup is not a one-time job, and the things that break it are ordinary business events rather than technical ones. Six triggers are worth a diary note. After that, the honest read on the free route: the plugins get you most of the way, and they stop in a specific place.
- The address changes, or you move from a shared room to your own suite.
- The hours change, which is the most common silent mismatch with your Business Profile.
- A clinician joins or leaves, leaving an @id reference pointing at a page that no longer exists.
- The phone number changes and the markup keeps the old one for months.
- A plugin or theme update quietly stops emitting the block.
- A site migration changes the URLs inside every @id at once.
On the DIY route: Yoast and Rank Math will both emit a LocalBusiness node and can usually be configured to emit MedicalBusiness. That covers the address, the hours and the phone, which is genuinely most of the value, and for a solo practice on a small budget it is a reasonable place to stop. What none of them does is emit a Person node with hasCredential and a named licensing board, or handle the multi-clinician @id pattern in section four.
If you would rather not do it at all, technical SEO and schema are in all three packages at $197, $497 and $997 a month. A page and a schema block for each clinician starts at $497. The technical checklist and the on-page guide cover the layers either side of this one.
11 FAQ
Questions therapists ask about schema markup
What is a schema markup example?
A schema markup example is a block of JSON-LD in a script tag in the page source, naming what the page is about in a vocabulary search engines already read. The shortest useful one for a therapy practice names the type, the practice, the website, a phone number and whether you are taking referrals. Everything else on this page is that block with more facts in it.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": ["MedicalBusiness", "MedicalOrganization"],
"name": "Riverside Counseling",
"url": "https://riversidecounseling.com/",
"telephone": "+1-503-555-0142",
"isAcceptingNewPatients": true
}
</script>schema.org medicalbusiness psychologist: which type should a psychologist use?
The same one a social worker or a counselor uses, because schema.org has no Psychologist type at all. Requesting schema.org/Psychologist returns a 404. Use the multi-type array of MedicalBusiness and MedicalOrganization on the practice, then carry the doctorate on a Person node through jobTitle, honorificSuffix and hasCredential. Physician is for prescribers and asserts a license a psychologist does not hold.
Is medical schema markup right for a therapy practice?
Yes, with one correction. The medical branch of schema.org is the right neighborhood, since the definition of MedicalBusiness explicitly covers different businesses run by health professionals. Of the healthcare schema types available, it is the closest fit for a talk-therapy practice. The correction is that MedicalBusiness alone cannot express whether you are taking new clients, because that property lives on the other branch. Declaring both types fixes it, and you add the second type in the same line.
What category do therapists fall under for business directories?
In structured data the answer is the medical branch of schema.org: MedicalBusiness for the practice, plus MedicalOrganization so the patient-facing properties are available. In a directory that asks for a plain category, mental health and counseling headings are the honest fit. Pick the heading your license supports rather than the one with the most traffic, and use the same name, address and phone in every listing.
Is therapy a Google Business Profile category?
Not as the word therapy on its own. The categories a talk-therapy practice normally chooses from are Psychotherapist, Counselor, Mental health service and Psychologist, and Google Business Profile categories are a separate system from schema.org types, so choosing one does not set the other. Set both, keep them consistent, and pick the category your license supports.
How can I see what schema markup a website is using?
Three ways, in order of effort. View the page source and search for application/ld+json, which shows you the raw block. Paste the URL into the Schema Markup Validator, which parses it and lists every type it found. Or use the Rich Results Test, which tells you which of those types Google would act on. The first is fastest, the third is the one that answers whether it is doing anything.
12 Next
Paste it yourself, or have the whole graph built
Both blocks above are yours to use and you owe me nothing for them. If you would rather it was implemented, validated and kept in step with your Business Profile, that is included in every package at $197, $497 and $997 a month. The review is free and you keep the findings whether or not you hire me.
| What you get | $197a month | $497a month | $997a month |
|---|---|---|---|
| Technical SEO and schema markup | Included | Included | Included |
| A page and schema block per clinician | Not included | Included | Included |
| Directories and citations | Included | Included | Included |
| Google Business Profile managed | Not included | Included | Included |
| Off-page work and links | Not included | Included | Included |
| Grid local rank tracking | Not included | Included | Included |
| New website built and hosted | Not included | Not included | Included |
Read the full guideWhat the work coversBusiness Profile categoriesAsk a question instead