정의
검색 엔진·답변 엔진이 내 페이지의 FAQ·가격·제품 설명을 인용하게 만들고 싶을 때, 기계용 마크업(구조화 데이터) 에 넣는 내용은 사람이 HTML에서 실제로 읽을 수 있는 내용과 같아야 한다.
구조화 데이터(structured data) 는 schema.org 어휘로 페이지 의미를 적은 JSON-LD 등이다. 가시 콘텐츠(visible content) 는 브라우저에 렌더되어 사용자가(또는 크롤러가 DOM/텍스트로) 볼 수 있는 본문·제목·FAQ다. 둘의 일치(parity) 란 마크업의 각 주장(질문·답·가격)이 화면에 대응 텍스트로 존재한다는 뜻이다. 화면에 없는 Q&A만 FAQPage로 넣는 것은 이 개념의 반대다.
왜 필요한가
구조화 데이터가 없으면 기계가 가격·FAQ 관계를 불안정하게 추측한다. 반대로 마크업만 풍부하고 화면이 비면(thin content), 검색 정책상 숨은 마크업·스팸에 가깝게 취급되고 사용자는 인용된 답을 페이지에서 못 찾는다. 로그인 벽·미리보기 잠금 UI를 쓰더라도 오버레이에 실제 H1·서술·FAQ를 실어 가시 텍스트를 확보하고, 그 텍스트와 JSON-LD를 같은 데이터 소스에서 뽑아야 한다.
동작 원리
- FAQ·플랜·제품 설명을
faqContent.ts같은 배열/모듈 하나에 둔다. - UI 컴포넌트는 그 배열을 map 하여 아코디언·목록을 그린다.
- JSON-LD 빌더는 같은 배열로
FAQPage/Offer노드를 만든다. - 조건부 렌더(익명만 FAQ 표시 등)와 graph 포함 여부를 같은 조건으로 묶는다 — 화면에서 FAQ를 제거하면 FAQPage 노드도 제거한다.
- 배포 전 HTML 소스에서
application/ld+json문자열과 본문 텍스트를 대조한다.
실무 적용
- 공개 홈·랜딩: 잠금/블러 UI여도 오버레이에 H1·짧은 설명·FAQ를 둔다.
- 가격 페이지:
Offer는 하드코딩 숫자보다 실제 요금표 함수에서 파생해 UI와 드리프트를 막는다. - i18n: 로케일별 FAQ 배열을 쓰되, 각 로케일 페이지의 JSON-LD도 그 로케일 배열을 쓴다.
- 별도
/landing으로 권위를 쪼개기보다, 가능하면 canonical 홈에 콘텐츠를 두는 쪽을 검토한다.
트레이드오프
| 선택 | 장점 | 비용 |
|---|---|---|
| SSOT 배열 | 불일치 버그 감소 | 모듈 설계·타입 공유 필요 |
| 마크업만 풍부 | 단기 rich result 유혹 | 정책 리스크·사용자 불신 |
| 별도 랜딩 URL | 실험 자유 | 검색 권위·canonical 분산 |
사용하면 안 되는 경우
- 화면에 절대 노출하지 않을 내부 FAQ를 JSON-LD에만 넣는 경우.
- CSS
display:none/ 0px 폰트로 “가시”를 위장하는 경우. - 로그인 후에만 보이는 답을 익명 페이지 FAQPage에 넣는 경우(조건 불일치).
흔한 실수
- UI에서 FAQ를 리팩터로 지웠는데 JSON-LD는 그대로 둠.
grep hreflang이 0이라 버그로 오진 — React가hrefLang으로 출력하는 대소문자 이슈와 혼동(별 문제지만, 소스 대소문자 무시 검색으로 확인).- 목(mock) E2E만 믿고 실환경 thin content·401 리다이렉트를 놓침.
관련 개념
- json-ld-structured-data — 서버에서 JSON-LD script를 주입하는 패턴
- single-source-of-truth-content-metadata — 메타·본문 단일 소스
- auth-resolution-gated-data-fetching — 공개 홈이 401로 튕기지 않게 하는 게이트