BBB A+ Rated
(919) 795-8596
Structured Data QA
Profile Launch

Structured Data Health Report

Triangle Home Solutionshttps://trianglehomesolutionsnc.com ·Last updated: June 23, 2026 at 12:00 PM
This is a manual structured-data QA report updated by Profile Launch review prompts. It is not an automatic scanner.
01 · Snapshot

Executive summary

High-level signal for how this site's structured data is performing against the recommended footprint for a blue-collar local service business.

Schema health score
90%
27 of 30 recommended items implemented
Critical missing items
0
High-priority gaps blocking core rich results
Recommended schema types
30
Total recommended for this site type
Implemented schema types
27
Found in source — pending render verification
Verified rendered
0
Confirmed in DOM by Profile Launch QA
Manual review items
6
Carry warnings — require human review
Google rich-result opportunities
30
Recommended types not yet Google-eligible
Total tracked types
38
Inventory size across all categories
02 · Industry detection

Detected industry & schema-type strategy

A client may operate in one or many trades. We pick the most specific LocalBusiness subtype where possible, then represent additional industries through Service / OfferCatalog / serviceType / knowsAbout / additionalType.

Detected on this site
General Contracting (residential)
Pending Base44 Audit
Confidence:
High
Evidence:
Schema @type already declared as ["GeneralContractor","HomeAndConstructionBusiness"] in lib/schemaBuilders.js. Homepage H1 + meta title: "Kitchen, Bath, Deck & Home Remodeling in Apex, NC". biz.gbpPrimaryCategory + service category set centered on remodeling and outdoor residential construction. No HVAC / Plumbing / Electrical / Roofing signals anywhere on the site.
Recommended primary @type:
GeneralContractor (currently implemented — correct)
Secondary notes:
Specialties (decks, kitchens, baths, outdoor living, full-home renovation) are represented as Service[] under /services/:cat/:svc. Single-industry — no additional LocalBusiness subtypes recommended.
Remodeling — Kitchen, Bath, Full-Home
Pending Base44 Audit
Confidence:
High
Evidence:
Title "Kitchen, Bath, Deck & Home Remodeling"; hero copy "premium residential construction, remodeling, and outdoor living solutions"; service categories include remodeling-focused services.
Recommended primary @type:
GeneralContractor (already covered by the primary type)
Secondary notes:
schema.org has no Remodeling @type. serviceType on each Service entity captures the remodeling specialty; OfferCatalog (Prompt 3 backlog) would surface this as a grouped service tree.
Outdoor Living / Deck Construction
Pending Base44 Audit
Confidence:
High
Evidence:
Hero references "custom decks"; category set includes outdoor-living scope; service detail pages cover deck construction.
Recommended primary @type:
HomeAndConstructionBusiness (already covered by the multi-type)
Secondary notes:
Surfaced via Service entities. Recommend grouping under an "Outdoor Living" OfferCatalog branch in Prompt 3.
Schema-type fallback chain
  1. Industry-specific LocalBusiness subtype (e.g. HVACBusiness, Plumber, RoofingContractor)
  2. HomeAndConstructionBusiness
  3. LocalBusiness
  4. ProfessionalService (fallback only)
  5. LocalBusiness (final fallback)
Supported industries
HVAC HVACBusinessPlumbing PlumberElectrical ElectricianRoofing RoofingContractorGeneral Contracting GeneralContractorRemodeling GeneralContractorLandscaping HomeAndConstructionBusinessLawn Care HomeAndConstructionBusinessTree Service HomeAndConstructionBusinessPressure Washing HomeAndConstructionBusinessPainting HousePainterPest Control HomeAndConstructionBusinessConcrete GeneralContractorGarage Door HomeAndConstructionBusinessFlooring HomeAndConstructionBusinessMasonry GeneralContractorFence HomeAndConstructionBusinessPool/Spa HomeAndConstructionBusinessSeptic PlumberMoving MovingCompanyLocksmith LocksmithCleaning HomeAndConstructionBusinessRestoration / Water Damage HomeAndConstructionBusinessOther Home Service HomeAndConstructionBusiness
03 · Schema inventory

Schema types tracked for this site

Every schema type relevant to a local-service business, grouped by role. Each row tracks availability, recommendation, implementation, render verification, and next action.

Core site / business
Schema typeStatusPriorityPage typesNext action
Organization
Top-level business entity, linked from every page.
Evidence: No standalone Organization @type emitted site-wide. Phase 15 (SEO-032) intentionally consolidated this into a single LocalBusiness root entity. BlogPosting publisher inlines an Organization on /blog/:slug — that is a per-document inline node, not a duplicate site-level root.
Affected: /blog/:slug (inline inside BlogPosting publisher only)
RecommendedInfoAll pagesNo action — consolidation is intentional. LocalBusiness covers Knowledge Graph + local-pack eligibility.
LocalBusiness
Local-business core entity with address, hours, geo, contact info.
Evidence: buildLocalBusiness() emits @type=["GeneralContractor","HomeAndConstructionBusiness"], @id="…/#localbusiness", with name, url, telephone, email, address, geo, logo/image (@id refs), hours, sameAs, areaServed, paymentAccepted, currenciesAccepted, foundingDate, founder. Implemented in code; rendered output not personally verified.
Affected: / (full emission) · /about · /contact · /services* · /service-areas/:city · /faqs · /blog · /blog/:slug · /privacy-policy · /terms-and-conditions (all reference via @id)
ImplementedCriticalHome, Contact, AboutManual: confirm <script type="application/ld+json"> renders on / and parses clean via validator.schema.org.
HomeAndConstructionBusiness
LocalBusiness subtype suitable for home-service trades.
Evidence: Present on the LocalBusiness @type array — multi-type emission per Phase 15.
Affected: / (referenced site-wide via @id)
ImplementedHighHome, ContactNo action — implemented.
Industry-specific LocalBusiness subtype
e.g. HVACBusiness, Plumber, RoofingContractor — picked from detected industry.
Evidence: GeneralContractor is the industry-specific subtype currently in use — matches detected primary industry.
Affected: / (referenced site-wide via @id)
ImplementedHighHome, ContactNo action — GeneralContractor is the appropriate subtype.
WebSite
Site-wide WebSite entity with name, url, optional SearchAction.
Evidence: buildWebSite() emits @id="…/#website" with name, url, publisher → LocalBusiness @id. No SearchAction (intentional — no internal search).
Affected: /
ImplementedHighHomeNo action — implemented.
WebPage
Per-page WebPage entity describing each URL.
Evidence: WebPage entities emitted on /, /services/:cat/:svc, /service-areas/:city, /privacy-policy, /terms-and-conditions; subtypes cover the rest.
Affected: All indexable public routes
ImplementedMediumAll pagesNo action — implemented.
AboutPage
WebPage subtype for the About page.
Evidence: buildAboutSchema() emits AboutPage with isPartOf + about + mainEntity references.
Affected: /about
ImplementedMediumAboutNo action — implemented.
ContactPage
WebPage subtype for the Contact page.
Evidence: buildContactSchema() emits ContactPage with isPartOf + about + mainEntity → LocalBusiness @id (no re-emission, per SEO-033).
Affected: /contact
ImplementedMediumContactNo action — implemented.
CollectionPage
For index pages (services index, service areas index, blog index).
Evidence: CollectionPage emitted on /services, /services/:cat, /service-areas, /blog.
Affected: /services · /services/:cat · /service-areas · /blog
ImplementedMediumServices index, Service areas index, Blog indexPrompt 3: pair each CollectionPage with an ItemList (see ItemList row).
BreadcrumbList
Breadcrumb trail rendered on every non-home page.
Evidence: buildBreadcrumbList() emits BreadcrumbList on every public route. Home includes a single-item breadcrumb; deeper pages include full trails.
Affected: All public routes
ImplementedHighAll pages except HomeNo action — implemented.
SiteNavigationElement
Optional — primary nav as structured data.
Evidence: Not emitted — main nav is plain <Link> elements. Optional and low SEO value for local-service sites.
AvailableLowHomeNo action recommended.
Business details
Schema typeStatusPriorityPage typesNext action
PostalAddress
Street, locality, region, postal code, country.
Evidence: buildAddress() emits PostalAddress nested in LocalBusiness with streetAddress, addressLocality, addressRegion, postalCode, addressCountry.
Affected: / (LocalBusiness)
ImplementedCriticalNo action — implemented.
GeoCoordinates
Latitude/longitude for the primary business location.
Evidence: buildGeo() emits GeoCoordinates only when biz.geo has non-zero lat/lng. Runtime presence depends on whether values are populated.
Affected: / (LocalBusiness)
ImplementedHighVerify biz.geo.latitude / biz.geo.longitude are populated in business data; otherwise mark as "Coordinates Missing".
OpeningHoursSpecification
Per-day hours; required for hours-eligible rich results.
Evidence: buildOpeningHours() emits one OpeningHoursSpecification per non-closed day. Hours visibly rendered on /contact and footer (Mon–Sat 9AM–5PM).
Affected: / (LocalBusiness)
ImplementedHighNo action — implemented.
ContactPoint
Phone, contact type, areaServed.
Evidence: No discrete ContactPoint entity. LocalBusiness carries telephone + email directly (Google accepts both), but no ContactPoint child with contactType="customer service" exists.
RecommendedHighPrompt 3: add a ContactPoint child to LocalBusiness (contactType, telephone, email, areaServed, availableLanguage="en") — improves Knowledge Graph completeness.
sameAs / social profile links
Array of canonical social/profile URLs.
Evidence: sameAs emitted from biz.schemaDefaults.sameAs through clean() filter. Runtime population depends on the data file.
Affected: / (LocalBusiness)
ImplementedMediumVerify Facebook, Instagram, and Google Business Profile URLs are populated; any unknown → "Social Profile URL Here" placeholder for the client.
areaServed
Cities/regions served — surfaced site-wide and on service-area pages.
Evidence: areaServed emitted as City[] on LocalBusiness from biz.serviceAreaCities; Service entities also carry per-service areaServed (City or City[]).
Affected: / (LocalBusiness) · /services/:cat/:svc (Service)
ImplementedHighNo action — implemented.
serviceArea
GeoShape / GeoCircle describing service radius.
Evidence: No GeoCircle / GeoShape serviceArea emitted. biz.serviceRadiusMiles is rendered in UI but not surfaced into schema.
RecommendedMediumPrompt 3: add serviceArea GeoCircle (geoMidpoint = biz.geo, geoRadius = serviceRadiusMiles × 1609 meters) to LocalBusiness.
paymentAccepted
Accepted payment methods.
Evidence: paymentAccepted joined from biz.schemaDefaults.paymentAccepted on LocalBusiness; values visible on /about Business Details card.
ImplementedLowNo action — implemented.
priceRange
Indicative price range (e.g. "$$").
Evidence: Not emitted. Optional but recommended for LocalBusiness completeness — helps populate the local-pack card.
RecommendedLowPrompt 3 (low priority): add priceRange (e.g. "$$") to LocalBusiness if a representative range exists.
currenciesAccepted
ISO currency code(s).
Evidence: currenciesAccepted joined from biz.schemaDefaults.currenciesAccepted on LocalBusiness.
ImplementedInfoNo action — implemented.
foundingDate
Year/date business was founded — supports E-E-A-T.
Evidence: foundingDate emitted as String(biz.foundingYear) on LocalBusiness. Year-only granularity is schema-org valid.
ImplementedLowNo action — implemented.
founder / owner (Person)
Only include if owner is publicly visible on the site.
Evidence: founder Person emitted with biz.ownerName. Owner is publicly named on About + Home (owner card with portrait and bio), so inclusion is appropriate.
Affected: / (LocalBusiness)
  • Do not add unless the owner/founder is publicly named on the site.
ImplementedInfoNo action — implemented and visibly supported.
logo
Square/wordmark logo URL.
Evidence: logo emitted as @id ref to "…/#logo" ImageObject anchor (300×227, live-probed). Header/footer use a 240px WebP for performance; schema references the canonical asset.
ImplementedHighNo action — implemented.
image
Primary business image(s) — must be crawlable.
Evidence: image emitted as @id ref to the logo anchor on LocalBusiness. Service / City / Category pages also pass page-specific Pexels images as primaryImageOfPage.
ImplementedMediumNo action — implemented.
Services & content
Schema typeStatusPriorityPage typesNext action
Service
One per offered service.
Evidence: buildServiceSchema() emits a Service entity with @id, name, description, url, provider (@id), areaServed, category, serviceType, image on every /services/:cat/:svc.
Affected: /services/:cat/:svc
ImplementedCriticalService pages, City × Service pagesNo action — implemented.
OfferCatalog
Grouped offerings under hasOfferCatalog.
Evidence: No hasOfferCatalog on LocalBusiness. Services are visibly listed on /services and /services/:cat but not surfaced as a graph.
RecommendedMediumHome, Services indexPrompt 3: add hasOfferCatalog to LocalBusiness grouping categories → Service[]. Surfaces the full service tree to Google.
Offer
Individual offer line items inside an OfferCatalog.
Evidence: No Offer entities — would require concrete pricing.
AvailableInfoNo action — defer until per-service pricing is published.
FAQPage
Only on pages where Q&A is visibly rendered (not templated CTAs).
Evidence: FAQPage emission is intentionally GATED (SEO-007/SEO-016). /faqs and /services/:cat/:svc SUPPRESS FAQPage because faqSeeds are question-only (no authored answers). FAQPage IS emitted on /blog/:slug when post.faq_items contains real Q&A.
Affected: /blog/:slug (conditional on post.faq_items)
  • Do NOT emit FAQPage for templated/CTA-only content — Google may flag as deceptive.
ImplementedHighFAQ page, Service pages (only if visible)Manual review: if Profile Launch authors real answers to faqSeeds, the gate in buildFAQPageSchema() / ServiceFAQAccordion can be lifted to emit FAQPage on /faqs and service pages.
Question
Child of FAQPage.
Evidence: Question entities emitted as children of FAQPage on blog posts with faq_items.
Affected: /blog/:slug (conditional)
ImplementedHighNo action — child of FAQPage.
Answer
Child of Question.
Evidence: Answer entities emitted as acceptedAnswer of Question.
Affected: /blog/:slug (conditional)
ImplementedHighNo action — child of Question.
BlogPosting
Per blog article.
Evidence: BlogPosting emitted on /blog/:slug with headline, description, url, datePublished, dateModified, image, author (Person or Organization), publisher (inline Organization), mainEntityOfPage; optional editor + reviewedBy when post fields present.
Affected: /blog/:slug
ImplementedHighBlog postPer-post audit: confirm post.date_published, post.date_modified, post.author_name populated. Missing values weaken Article rich-result eligibility.
Article
Alternative to BlogPosting for non-blog editorial.
Evidence: Not used — BlogPosting (a subtype of Article) is used instead, which is the correct choice for editorial blog content.
AvailableInfoNo action — BlogPosting is the appropriate subtype.
ImageObject
Only where a real, crawlable image asset exists.
Evidence: buildLogoImageObject() emits one ImageObject with @id="…/#logo" on the homepage (300×227, verified). Service / City / Category pages emit ImageObject for primaryImageOfPage when a Pexels image is resolved.
Affected: / · /services/:cat · /services/:cat/:svc · /service-areas/:city
  • Do not emit ImageObject for missing or non-crawlable images.
ImplementedMediumNo action — implemented.
VideoObject
Only where real videos are embedded.
Evidence: No videos rendered anywhere on the site — emission would be inappropriate.
  • Do not emit unless an actual video is rendered on the page.
Needs Manual ReviewInfoNo action — emit only when real video content is added.
Review
Only if real reviews are visibly rendered on the site.
Evidence: GoogleReviewsSection displays Google review snippets on /, /about, /contact via Places API, but NO per-review schema.org Review entities are emitted. Self-served Review markup is generally not Google review-rich-result-eligible.
  • Never invent reviews.
  • Self-served Review markup on LocalBusiness is no longer eligible for Google review rich results in most cases.
Needs Manual ReviewMediumNo action recommended — display value remains via on-page rendering; rich-result eligibility is not improved by self-served Review markup.
AggregateRating
Site-level aggregate — manual review required.
Evidence: components/GoogleReviewSchema.jsx injects a SELF-SERVED LocalBusiness AggregateRating into <head> on / and /about when reviewData is available (overallRating + totalReviews from Google Places API).
Affected: / · /about
  • Default status: Needs Manual Review.
  • Self-served aggregate ratings on LocalBusiness are generally not eligible for Google star rich results.
ImplementedHighMANUAL REVIEW (policy decision): self-served AggregateRating on LocalBusiness is generally NOT eligible for Google star rich results. Truthful (sourced from live Places API) and harmless to schema.org validity, but do not expect star rich results. Decide: KEEP for completeness signal, or REMOVE to keep the graph lean.
ItemList
For listings: services, areas, blog posts, reviews.
Evidence: No ItemList emitted on /services, /services/:cat, /service-areas, /blog. These pages render full visible lists, so ItemList would be schema-org-valid and would improve list-page structure.
RecommendedMediumServices index, Service areas index, Blog indexPrompt 3: add ItemList to /services (categories), /services/:cat (services in category), /service-areas (cities), /blog (posts).
04 · Page-specific expectations

What schema each page type should carry

Use these expectations as the target state during Prompt 2 (audit) and Prompt 3 (remediation).

Home page
  • Organization
  • LocalBusiness / HomeAndConstructionBusiness (and industry-specific subtype where possible)
  • WebSite
  • WebPage
  • Services summary (only if visibly listed)
  • areaServed (only if visibly listed / available)
  • ContactPoint
  • sameAs (only if real social links exist)
  • FAQPage ONLY if FAQs are visibly on the home page
About page
  • AboutPage
  • Organization / LocalBusiness reference
  • owner/founder Person (only if publicly visible)
  • BreadcrumbList
Services index page
  • CollectionPage
  • ItemList
  • Service or OfferCatalog
  • BreadcrumbList
Individual service pages
  • Service
  • WebPage
  • BreadcrumbList
  • provider
  • serviceType
  • areaServed
  • FAQPage ONLY if FAQs are visibly on that specific page
Service area index page
  • CollectionPage
  • ItemList
  • areaServed
  • BreadcrumbList
Individual city / service-area pages
  • WebPage
  • Service or LocalBusiness reference (where appropriate)
  • areaServed for that city/area
  • BreadcrumbList
  • FAQPage only if visible on that page
  • NEVER create fake addresses for service-area cities
FAQ page
  • FAQPage (only if Q&A are visible)
  • Question
  • Answer
  • BreadcrumbList
Blog index
  • CollectionPage or Blog
  • ItemList
  • BreadcrumbList
Blog detail pages
  • BlogPosting or Article
  • headline
  • description
  • author (if available)
  • publisher
  • datePublished / dateModified (if available)
  • image (only if real, crawlable image exists)
  • BreadcrumbList
Contact page
  • ContactPage
  • LocalBusiness
  • PostalAddress (only if visible)
  • ContactPoint
  • openingHours (if available)
  • geo (if available)
  • BreadcrumbList
05 · Reviews & ratings

Reviews & AggregateRating — handle with care

Reviews can be displayed for users while still being ineligible for Google review rich results. The two are independent — treat them separately.

  • Review schema may only be marked Available / Recommended if real reviews are visibly displayed on the site.
  • Never invent or generate reviews. Never invent aggregate ratings.
  • AggregateRating defaults to "Needs Manual Review" until validated against visible, on-page reviews.
  • Google reviews can be DISPLAYED on the site via Places API, but self-served LocalBusiness Review / AggregateRating markup is generally NOT eligible for Google review rich results — display value remains, rich-result value does not.
06 · Missing or uncertain data

Business facts needed to complete schema

Schema cannot accurately describe a business until these facts are confirmed. Prompt 2 should attempt detection; anything still unknown flows to a client-info request.

FieldStatusNotes
Business phoneImplementedbiz.primaryPhone + biz.formattedPhone present; rendered site-wide (header CTA, footer, contact page).
Business addressImplementedbiz.address.formattedAddress + structured fields drive PostalAddress; rendered on /contact, /about, footer.
Business hoursImplementedbiz.hours feeds OpeningHoursSpecification; visible on /contact and footer (Mon–Sat).
Business emailImplementedbiz.primaryEmail present; visible on /contact and footer.
Primary industryImplementedDetected: General Contractor / Residential Remodeling. Matches existing @type.
Secondary industriesImplementedSpecialties (decks, kitchen/bath, outdoor living) — represented via Service[] (not separate trades).
Service areasImplementeddata.entities.cities populated; areaServed already emitted on LocalBusiness and per-Service.
Social linksNeeds Manual Reviewbiz.schemaDefaults.sameAs is emitted with clean() filtering. Confirm Facebook/Instagram/GBP URLs are populated; any unknown surfaces as "Social Profile URL Here".
LogoImplementedbiz.logoUrl → ImageObject @id="…/#logo" (300×227 verified). Header/footer now use a 240px WebP for performance; schema still references the canonical asset.
Owner / founder nameImplementedbiz.ownerName visibly rendered on About + Home owner card. founder Person emitted in LocalBusiness — appropriate since it is public.
License informationNeeds Manual Reviewbiz.licenses iterated in footer + TrustBadges when set. Confirm license numbers are populated; placeholder if missing: "License Information Here".
Insurance informationNeeds Manual Reviewbiz.insuranceInfo iterated in footer when set. Verify populated; placeholder if missing: "Insurance Information Here".
Warranty informationNeeds Manual Reviewbiz.warranties + biz.serviceGuarantees iterated on /about and /. Verify populated; placeholder if missing: "Warranty Information Here".
Financing / payment infoImplementedbiz.schemaDefaults.paymentAccepted joined into LocalBusiness paymentAccepted. Visible on /about Business Details card.
FAQs (real, on-page)MissingfaqSeeds are question-only — no authored answers. FAQPage emission is INTENTIONALLY suppressed on /faqs and service pages (SEO-007/SEO-016). FAQPage IS emitted on /blog/:slug when post.faq_items contains real Q&A.
Blog dates / authorsNeeds Manual ReviewBlogPosting schema reads post.date_published, post.date_modified, post.author_name. Confirm every published post has these populated; missing values weaken Article rich-result eligibility.
Page-specific service detailsImplementedService entity carries name/description/url/provider/areaServed/category/serviceType/image. Rich per-service body content (problems solved, signs you need it, process, pricing factors, local insights) all rendered.
Google review visibility / sourceNeeds Manual ReviewGoogle reviews rendered via Places API on /, /about, /contact (GoogleReviewsSection). GoogleReviewSchema.jsx ALSO emits a self-served LocalBusiness AggregateRating on / and /about — see Reviews Warning section for the policy decision.
07 · How to validate

Team instructions

Profile Launch QA workflow for keeping this report accurate.

  1. 1Run Prompt 2 to audit / check current schema and update this page.
  2. 2Run Prompt 3 to fix missing schema and update this page again.
  3. 3Use validator.schema.org for schema.org structural validation.
  4. 4Use Google Rich Results Test separately for Google rich-result eligibility.
  5. 5Do NOT assume schema.org validity equals Google rich-result eligibility — they are independent checks.
08 · What Prompt 3 should fix

Prompt 3 remediation backlog

Output of this audit pass — the ordered list of schema changes for the next prompt to implement. Nothing is fixed in Prompt 2.

PriorityAction
HighAdd discrete ContactPoint child entity to LocalBusiness (contactType="customer service", telephone, email, areaServed, availableLanguage="en").
HighAdd ItemList to listing pages: /services (categories), /services/:cat (services), /service-areas (cities), /blog (posts).
HighPolicy decision: self-served LocalBusiness AggregateRating on / and /about — keep (truthful, sourced from live Google Places API) or remove (no star rich-result eligibility expected).
MediumAdd serviceArea GeoCircle to LocalBusiness using biz.geo + biz.serviceRadiusMiles (meters = miles × 1609).
MediumAdd hasOfferCatalog to LocalBusiness — group categories → Service[] for a complete service tree.
MediumPer-post BlogPosting audit: confirm date_published, date_modified, author_name populated for every published post.
MediumVerify biz.schemaDefaults.sameAs is populated (Facebook, Instagram, Google Business Profile). Unknown → request "Social Profile URL Here" from client.
MediumVerify biz.licenses / biz.insuranceInfo / biz.warranties populated — request "License/Insurance/Warranty Information Here" from client if missing.
LowAdd priceRange (e.g. "$$") to LocalBusiness if a representative range exists.
InfoDecision: author real Q&A pairs for faqSeeds → lift FAQPage gate on /faqs and service pages. Otherwise leave the gate in place.
Prepared by Profile Launch · Report version 1 · This is a manual structured-data QA report updated by Profile Launch review prompts. It is not an automatic scanner.