Blogger 검색 설명, 분명 넣었는데 비어 있던 이유
Blogger 글 편집 화면의 검색 설명 칸에 값을 넣었다. 그런데 공개된 글의 HTML <head>를 열어 보니 name="description" 메타 태그가 3개였다. 첫 번째는 입력한 설명이었고, 두 번째는 빈 문자열, 세 번째는 글자 그대로 false였다. 2026년 10월 13일 이 블로그의 공개 HTML을 받아 확인한 결과다.
이 글은 검색 설명을 분명히 입력했는데 결과가 비어 보이는 Blogger 사용자를 위한 확인 순서다. 목표는 편집기에 넣은 값과 head에 실제로 찍힌 값을 따로 세고, 정상 값과 빈 값이 head의 어느 출처에서 나오는지 나누고, 고친 뒤 같은 기준으로 다시 재는 것이다.
먼저 결론의 범위를 밝힌다. 같은 날 테마를 고쳐 저장했고, 글 91편을 검사 스크립트로 다시 재서 91편 모두 기준을 통과했다. 이 기준은 head 태그의 개수와 빈 값을 보는 것이다. 검색 결과나 유입이 달라졌는지는 확인하지 않았다. 그리고 검색 설명 칸이 빈 글에는 지금도 description 태그가 아예 없다.
증상: 입력한 설명 뒤에 빈 값과 false가 붙는다
당시 감사에서 최근 글 5개와 오래된 글 2개는 description을 3개씩 출력했다. 정상 검색 설명, 빈 문자열, false 순서였다. 나머지 오래된 글도 description이 2개로 중복됐고, 홈은 같은 내용의 description을 2번 출력했다.
OG 태그도 같은 모양이었다. 가장 최근 글 하나를 기준으로 세면 다음과 같다.
| 태그 | 개수 | 값 |
|---|---|---|
| description | 3 | 정상 설명, 빈 값, false |
| og:description | 3 | 정상 설명, 빈 값, false |
| og:title | 2 | 정상 제목, 빈 값 |
| og:url | 2 | 정상 주소, 빈 값 |
| og:type | 2 | 둘 다 article |
편집기에서 보면 설명은 정상으로 들어가 있다. 문제는 입력값이 아니라 템플릿이 head에 무엇을 몇 번 출력하느냐였다. 검색엔진이나 공유 미리보기가 이 중 어느 값을 고르는지는 이번 기록으로 확인하지 못했다. 다만 빈 값이나 false를 고를 여지를 남겨 둔 것은 그 자체로 템플릿 결함이다.
1단계: 편집기 값과 head 출력을 따로 센다
브라우저 화면이나 편집기만 봐서는 이 문제가 보이지 않는다. 공개 URL의 HTML을 받아 </head> 앞부분에서 태그 이름별 개수와 빈 값, false 값을 센다. 아래는 독자가 그대로 돌려 볼 수 있게 정리한 예시 스크립트다. 감사 당시 쓴 도구가 아니라, 이 글을 쓰면서 보관해 둔 HTML로 다시 확인한 것이다.
import re, sys
html = open(sys.argv[1], encoding="utf-8", errors="replace").read()
head = html.split("</head>", 1)[0]
for key in ["description", "og:title", "og:description", "og:url", "og:type"]:
tags = re.findall(r"<meta\b[^>]*\b(?:name|property)=[\"']%s[\"'][^>]*>" % re.escape(key), head)
values = []
for tag in tags:
m = re.search(r"content=\"([^\"]*)\"|content='([^']*)'", tag)
values.append((m.group(1) if m.group(1) is not None else m.group(2)) if m else None)
empty = sum(1 for v in values if v is not None and v.strip() == "")
false = sum(1 for v in values if v == "false")
print(f"{key}: count={len(tags)} empty={empty} false={false}")
curl로 받아 둔 글 HTML 파일을 인자로 넘기면 된다. 10월 13일에 받아 둔 최신 글 HTML에 돌린 출력은 이랬다.
description: count=3 empty=1 false=1
og:title: count=2 empty=1 false=0
og:description: count=3 empty=1 false=1
og:url: count=2 empty=1 false=0
og:type: count=2 empty=0 false=0
판정 기준은 단순하다. 검색 설명을 넣은 글이라면 description 1개, 각 OG 단일값 태그 1개, 빈 값과 false는 0개. 출력에 태그 이름을 함께 찍는 이유는 3단계에서 설명한다.
2단계: head 출력을 출처별로 나눈다
같은 HTML에서 태그의 위치를 보면 출처가 갈린다. 정상 값 세트는 head 앞쪽, 피드 링크들 뒤에 모여 있었다. description, og:url, og:title, og:description, og:image 순서다. 이 묶음은 Blogger 기본 <b:include data='blog' name='all-head-content'/>가 내는 출력이다. 글에 검색 설명이 설정돼 있으면 이 include가 그 값을 description과 og:description에 그대로 넣는다. 정상 값은 이미 여기서 나오고 있었다.
빈 값과 false는 head 한참 뒤쪽, 테마가 직접 넣은 메타 태그 자리에서 나왔다. 수정 스크립트를 만들면서 세운 진단은 이렇다. Blogger 테마의 <head>에는 data:post 스코프가 없다. 그래서 head에서 data:post로 시작하는 값을 읽어 메타 태그를 만들면, 그 태그는 빈 값으로 찍히거나 아예 사라진다. 글 편집기에 설명을 넣었는지와 상관없이 생기는 문제다.
false에 대해서는 감사 보고서의 수정 지침이 단서다. 지침에는 "Boolean 존재 여부 표현식을 expr:content로 출력하지 않는다"고 적혀 있다. 존재 여부를 묻는 식이 내용 대신 그대로 찍히면 false라는 문자열이 남는다. 다만 감사 시점의 테마 XML은 보관하지 않았기 때문에, 어느 줄이 false를 만들었는지는 확정하지 못했다.
그래서 head를 볼 때는 세 가지를 확인한다.
- head 안에 기본
all-head-contentinclude가 있는가. 없으면 검색 설명을 넣어도 정상 값 세트 자체가 나오지 않는다. - 테마가 head에 직접 description이나 og 메타를 넣고 있는가. 특히
expr:content가data:post...를 참조하는가. include가 이미 내는 태그라면 지운다. expr:content에 조건식(존재 여부, 비교식)이 들어 있는가. 조건은<b:if cond=...>로 감싸고, content에는 값만 넣는다.
처음 만든 수정 스크립트는 테마 메타를 지운 뒤 data:view 스코프로 description·OG 세트를 새로 넣는 방식이었다. 보관 HTML을 다시 보고 방향을 바꿨다. 기본 include가 이미 정상 값을 내는데 새 세트를 넣으면 description이 다시 2개가 된다. 그래서 스크립트는 include가 내지 않는 og:type 한 줄만 넣도록 고쳤다.
3단계: 고친 뒤 같은 기준으로 다시 잰다
고치기 전에 상황이 한 번 더 나빠졌다. 같은 날 중간에 테마를 저장하는 과정에서 기본 include가 head에서 빠졌다. 그 저장이 언제, 어떤 편집으로 이루어졌는지는 따로 기록되지 않았고 결과만 남아 있다. 감사 때 받은 HTML에는 include 출력이 있었는데, 수정 직전에 내려받은 테마 백업의 head에는 include가 없었다. 대신 테마가 직접 쓴 메타가 남아 있었다.
<b:if cond='data:view.isSingleItem'>
<b:if cond='data:post.metaDescription'>
<meta expr:content='data:post.metaDescription' name='description'/>
<meta expr:content='data:post.metaDescription' property='og:description'/>
<b:else/>
<meta expr:content='data:post.snippet' name='description'/>
<meta expr:content='data:post.snippet' property='og:description'/>
</b:if>
<b:else/>
<meta expr:content='data:blog.metaDescription' name='description'/>
<meta expr:content='data:blog.metaDescription' property='og:description'/>
</b:if>
head 뒤쪽에도 data:post.snippet으로 description을 한 번 더 넣는 블록이 있었다. 합쳐서 테마가 직접 쓴 description·og:description 메타는 7개였다. 이 상태에서 라이브 글을 받아 보니 91편 모두 description이 빈 값이었고 og:title은 0개였다. 검사 스크립트로 잰 결과는 PASS 0/91이었다.
수정은 세 가지였다.
- head 맨 앞에 기본 include 한 줄을 되살렸다.
- 테마가 직접 쓴 description·og:description 메타 7개를 지웠다. head 뒤쪽
<b:if>블록은 통째로 사라졌고, head 앞쪽의<b:if>/<b:else/>껍데기는 내용 없이 남았다. 남은 껍데기는 아무것도 출력하지 않는다. </head>바로 앞에 og:type 한 줄을 넣었다.
<b:include data='blog' name='all-head-content'/>
...
<meta expr:content='data:view.isSingleItem ? "article" : "website"' property='og:type'/>
검사 스크립트의 기준은 글마다 이렇다. description은 0개나 1개이고 빈 값이나 false가 아닐 것. og:title은 1개이고 비어 있지 않을 것. og:url과 og:type은 각 1개. og:description은 1개 이하이고 빈 값이나 false가 아닐 것. 수정 전 PASS 0/91은 이보다 좁은 이전 판(description·og:title·og:url만 검사)으로 잰 값이지만, 그때 91편 모두 og:title이 0개였으므로 이 기준으로도 전부 실패다. 저장 뒤 이 기준으로 글 91편을 다시 잰 결과는 PASS 91/91이었다.
확인할 때 걸린 함정이 하나 있다. 검사 스크립트는 쿼리 문자열 없이 공개 주소를 받는다. 저장 직후 이렇게 재면 80/91이었고, 실패한 11편은 모두 저장 전 head(og:type·og:title·og:url 0개)였다. 1분 뒤에는 91/91이었지만, 2분여 뒤 같은 방식으로 다시 재자 77/91로 내려갔고 실패한 글은 이번에도 모두 저장 전 head였다. Blogger 쪽 캐시로 보인다. 주소 뒤에 쿼리 문자열을 붙여 캐시를 피해 받은 확인에서는 91편 모두 새 head(og:type 1개)였다. 저장 직후 결과가 그대로라고 실패로 판단해서도 안 되고, 쿼리 없이 한 번 통과했다고 끝났다고 판단해서도 안 된다.
같은 확인에서 남은 사실도 하나 나왔다. 91편 중 description이 1개인 글은 11편이고, 80편은 0개였다. 기본 include는 검색 설명이 설정된 글에서만 description을 낸다. 80편은 글마다 검색 설명 칸이 비어 있어서 description 태그가 아예 없다. 빈 값을 찍던 테마 메타를 지웠으니 빈 태그는 사라졌지만, 설명 자체는 글마다 칸을 채워야 생긴다.
그래서 같은 날 80편의 칸을 하나씩 채웠다. 62편은 저장했고, 캐시를 피해 다시 받은 HTML에서 62편 모두 description이 1개였으며 값은 입력한 글과 같았다. 나머지 18편은 본문에 base64로 박힌 이미지가 있어서, 저장하면 Blogger가 이미지를 올리면서 본문을 다시 쓴다. 그래서 저장하지 않았고, 이 18편에는 지금도 description이 없다.
중간에 만든 재검사 파일 하나는 증거로 쓰지 않았다. 이름에 수정 뒤라는 뜻의 after-descfix가 붙은 재검사 파일이다. 글 91편과 홈, URL 92개를 검사한 결과지만 내용은 성공 기록이 아니었다. URL마다 숫자 5개와 참/거짓 값 1개가 남아 있었고, 92행을 값별로 직접 묶어 센 분포는 이랬다.
| 대상 | 행 수 | 기록된 값 |
|---|---|---|
| 홈 | 1 | [1, 0, 1, 1, 2, true] |
| 글 | 82 | [2, 2, 1, 1, 2, true] |
| 글 | 9 | [2, 2, 2, 1, 2, true] |
이 파일에는 각 숫자가 무엇을 센 것인지 필드 이름이 없다. 어떤 스크립트로 만들었는지, 그 전에 테마 수정이 실제로 저장됐는지도 기록이 없다. 그래서 첫 번째 값이 description 개수라고 단정할 수 없고, 이 결과를 수정 완료나 실패의 증거로 쓸 수 없다. 1단계 스크립트가 태그 이름과 개수를 같이 찍는 것도 이 경험 때문이다.
남은 일과 다음 확인
- 본문에 base64 이미지가 있는 18편에는 아직 description이 없다. 이미지를 호스팅 이미지로 옮긴 뒤에 칸을 채워야 한다.
- 수정 뒤 검사는 글 91편만 했다. 홈은 아직 다시 재지 않았다. og:image와 canonical도 이번 검사 항목이 아니었다.
- 다음 검사는 홈을 포함한 공개 URL 전체에 1단계 스크립트를 돌리고, 결과를 태그 이름과 함께 남기는 것이다. 홈과 글을 따로 판정하고, 요청에는 쿼리 문자열을 붙인다.
- 테마를 저장하기 전에는 diff에서
all-head-content줄이 사라지지 않았는지 본다. 사라졌으면 저장하지 않는다.
이 기록으로 답하지 않는 것
- Google이 검색 결과 snippet에 실제로 어느 description을 썼는지.
- 중복 description이나 이번 수정이 검색 순위, 노출, 클릭 수에 준 영향.
- 다른 Blogger 테마에서도 같은 위치에서 같은 값이 나오는지.
검색 설명을 아직 입력하지 않았다면 그 전 단계부터 보는 편이 맞다. 메타 설명을 포함한 기본 점검은 블로그 SEO 초보 실수 5가지 — GSC 등록부터 내부 링크까지에 정리했다. "수정했다", "검사 파일이 있다"는 사실과 실제 공개 결과가 어긋나는 문제는 테스트 113개 다 통과했는데 실제론 0개를 긁었다 — AI가 짠 수집기의 함정과 같은 구조다.
결론: 입력값이 아니라 head 출력을 센다
이 블로그에서 검색 설명이 비어 보인 이유는 입력 누락이 아니었다. Blogger 기본 include가 이미 정상 값을 내는데 테마가 head에 직접 넣은 메타가 빈 값과 false를 덧붙였고, 중간 저장에서는 그 include마저 빠졌다. include를 되살리고 테마 메타 7개를 지운 뒤 검사 결과는 0/91에서 91/91로 바뀌었지만, 검색 설명 칸이 비어 있던 80편은 칸을 채워야 했고, 그중 18편은 본문 이미지 때문에 아직 비어 있다. 그래서 확인은 편집기가 아니라 캐시를 피한 공개 HTML의 태그 개수로 한다.
댓글
댓글 쓰기