Case study Healthcare, Australia and New Zealand
One structured data model across two markets
Structured data across the AU and NZ sites was fragmented and didn't say which clinics or doctors belonged to which market. That risked the wrong market surfacing in local search, and every new page added more markup to fix by hand.
- Client
- A multi-clinic healthcare group
- My role
- Owned the structured data model end to end, from audit to template implementation
- Disciplines
- Structured data, Technical SEO, Content architecture, CMS architecture
Client anonymised. Details are generalised and contain no confidential figures.
Context
The group runs patient-facing websites for Australia and New Zealand, covering the organisation, its clinics, its doctors and its health articles. Structured data had been added piece by piece as pages were built, so what a page said about itself depended on when it was made and who made it. Both markets share the same kinds of page, but the details a patient relies on, such as which clinic is nearby and how to reach it, differ by market.
Constraints
- Shared templates had to output the right organisation and contact details for each market.
- Markup could only describe what the page visibly shows, with no unsupported claims.
- Statements about doctors and treatments had to stay accurate and conservative.
- A doctor could be linked to more than one clinic, so relationships couldn't be one to one.
- New pages had to inherit correct markup without anyone writing JSON-LD by hand.
Diagnosis
I pulled the structured data out of every page type in both markets and compared it with what each page actually showed. The problem lay less in missing markup than in markup that disagreed with itself.
- The organisation was declared in more than one place in slightly different forms, with nothing tying the versions together. Search engines were being handed several unconnected copies of the same group.
- Clinic pages described a place but didn’t say which organisation or market it belonged to.
- Doctor pages described each doctor in isolation, with no link to the clinics where they practise.
- Articles weren’t connected to a publisher or author in any consistent way.
- Templates had no concept of market, so a fix made for one country could carry its details into the other.
For a business that depends on local enquiries, this has a cost. Search engines use these signals to connect a clinic to its organisation and a doctor to a location. When the signals conflict, the risk is a patient in one country landing on the other country’s page, or a clinic that never gets credited to the group behind it.
Every earlier fix had been made page by page, so the same problems came back each time a new page went live.
Approach
This was a data modelling problem first and a markup problem second. Before writing any JSON-LD, I mapped the real entities and how they relate:
- Organisation: the group, with a distinct identity for each market and a clear link between them.
- Clinic: a
MedicalClinicthat belongs to its market’s organisation. - Doctor: a
Personlinked to every clinic they work at, rather than duplicated per clinic. - Article: published by the market’s organisation and connected to a named author where the page shows one.
Two principles held the model together.
Define once, reference everywhere
Every entity gets one stable @id. It is described in full on the page that is about it, and referenced by ID everywhere else. A doctor page describes the doctor and points to their clinics. A clinic page describes the clinic and points to its organisation. Pages stop re-describing entities, so there is nothing left to drift out of sync.
Market is an input, not a guess
The market decides which organisation a page belongs to and which contact details it carries. It also sets inLanguage to en-AU or en-NZ. Templates receive the market rather than working it out, so a shared template can’t output the wrong country’s details.
I also set a plain rule for healthcare content: markup describes only what the page visibly states. No ratings or claims a patient can’t see on the page itself.
Implementation
I built the model as a set of reusable template partials, one per entity type. Each takes the page’s content and the market as inputs and returns a JSON-LD node. Page templates compose those partials into a single @graph instead of carrying their own hand-written markup.
What went in
- Market configuration. One source per market for organisation and contact details. It also sets the base for that market’s
@idvalues, so no template hard-codes any of it. - Entity partials. Organisation, clinic, doctor and article, each producing a node with a stable
@idand references to the entities it relates to. - Relationships from content. Doctor-to-clinic links come from the same content the page displays, so the markup can’t say something the page doesn’t.
- Clean-up. I removed the older page-level markup so it couldn’t compete with the new graph, starting with the duplicate organisation declarations.
Checking it
I rolled it out one page type at a time and checked each in both markets before moving on:
- the graph is valid against schema.org definitions
- every
@idreference resolves within the page - nothing in the markup contradicts the visible content
- the organisation and contact details belong to the page’s own market
I also documented the model, so whoever adds the next page type knows which entities it should describe in full and which it should only reference.
Outcome
Structural outcome: what changed in how the site works
Organisation, clinic, doctor and article markup now comes from one shared model, and every page outputs a single connected graph tied to its own market. New clinic and doctor pages pick up correct structured data from their templates, so nobody writes or patches JSON-LD page by page. The AU and NZ sites now describe one group consistently instead of offering competing versions of it.