오픈그래프 프로토콜이 정의하는 것
오픈그래프 프로토콜(ogp.me에 문서화되어 있으며 원래 Facebook이 만들었습니다)은 <head>의 <meta property="og:..."> 태그로 웹 페이지를 타입이 있는 객체로 설명합니다. 링크 미리보기를 보여 주려는 서비스는 본문을 추측하는 대신 이 태그를 읽을 수 있습니다. 메신저, 소셜 네트워크, 업무 도구 대부분이 그렇게 동작하고, 태그를 추가하는 데는 비용이 들지 않습니다.
프로토콜은 모든 페이지에 네 가지 필수 속성을 정해 둡니다. og:title, og:type, og:image, og:url입니다. og:image가 없어도 대부분의 플랫폼은 텍스트만 있는 미리보기를 만들어 주지만, 프로토콜은 필수로 보며 이미지 없는 미리보기는 그냥 스쳐 지나가기 쉽습니다.
| 태그 | 구분 | 담는 내용 |
|---|---|---|
| og:title | 필수 | 카드에 표시될 객체의 제목 |
| og:type | 필수 | 객체 유형. website, article 등 |
| og:image | 필수 | 미리보기 이미지의 절대 URL |
| og:url | 필수 | 객체가 위치한 대표(canonical) URL |
| og:description | 선택 | 페이지를 요약하는 한두 문장 |
| og:site_name | 선택 | 페이지 제목과 구별되는 사이트 전체의 이름 |
| og:locale | 선택 | 페이지의 언어와 지역. 예: ko_KR |
| og:locale:alternate | 선택 | 이 페이지가 제공되는 다른 로케일. 로케일마다 태그를 반복 |
| og:image:width, og:image:height | 선택 | 이미지 크기(픽셀). 파일을 받기 전에 카드 레이아웃을 잡을 수 있음 |
| og:image:alt | 선택 | 이미지를 볼 수 없는 사람을 위한 대체 텍스트 |
트위터(X) 카드 태그
X(구 트위터)는 자체 twitter: 태그를 읽고, 없으면 오픈그래프 태그로 대체합니다. 실무에서 오픈그래프 위에 꼭 더해야 하는 태그는 레이아웃을 고르는 twitter:card 하나뿐입니다. summary는 제목·설명 옆에 작은 정사각형 이미지를 보여 주고, summary_large_image는 글 위에 가로로 넓은 이미지를 보여 줍니다.
twitter:title, twitter:description, twitter:image가 없으면 대응하는 og: 값이 쓰입니다. 그래서 og: 태그와 twitter:card만 쓰는 사이트도 많습니다. twitter: 태그를 같이 써도 해롭지 않으며, 이 사이트의 메타 태그 생성기도 그렇게 출력합니다. 나중에 카드만 오픈그래프와 다르게 하고 싶을 때 쓸모가 있습니다.
| 태그 | 용도 | 없을 때 대체되는 값 |
|---|---|---|
| twitter:card | 레이아웃: summary 또는 summary_large_image | 대체 없음, 직접 추가 |
| twitter:title | 카드 제목 | og:title |
| twitter:description | 카드 설명 | og:description |
| twitter:image | 카드 이미지 | og:image |
| twitter:image:alt | 이미지 설명 | og:image:alt |
| twitter:site | 사이트 계정의 @핸들 | 대체 없음, 선택 사항 |
그대로 복사해 쓰는 head 블록
아래 블록은 이미지, 사이트 이름, 이미지 설명, X 핸들을 넣은 글 페이지에 대해 메타 태그 생성기의 코드를 실제로 실행해서 얻은 출력입니다. 소셜 태그가 보통 같은 값을 반복하므로 검색용 태그(<title>, 설명, canonical)도 함께 들어 있습니다. 생성기는 og:image:width, og:image:height, og:locale, og:locale:alternate를 만들어 주지 않습니다. 블록 맨 아래 세 줄이 직접 추가하는 위치의 예입니다.
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Flexbox vs Grid: When to Use Each</title>
<meta name="description" content="A practical guide to choosing between CSS flexbox and grid.">
<link rel="canonical" href="https://example.com/guides/flexbox-vs-grid">
<meta property="og:type" content="article">
<meta property="og:title" content="Flexbox vs Grid: When to Use Each">
<meta property="og:description" content="A practical guide to choosing between CSS flexbox and grid.">
<meta property="og:url" content="https://example.com/guides/flexbox-vs-grid">
<meta property="og:site_name" content="Example">
<meta property="og:image" content="https://example.com/img/flexbox-vs-grid-1200x630.png">
<meta property="og:image:alt" content="A flex row and a grid side by side">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Flexbox vs Grid: When to Use Each">
<meta name="twitter:description" content="A practical guide to choosing between CSS flexbox and grid.">
<meta name="twitter:site" content="@example">
<meta name="twitter:image" content="https://example.com/img/flexbox-vs-grid-1200x630.png">
<meta name="twitter:image:alt" content="A flex row and a grid side by side">
<!-- 직접 추가한 태그: 생성기는 만들지 않음 -->
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:locale" content="en_US">이미지 크기: 1200x630과 지켜야 할 규칙
공유 이미지로 널리 쓰는 크기는 1200 x 630 픽셀, 가로세로 비율 약 1.91:1이며 큰 이미지 카드가 이 비율을 기준으로 설계됩니다. 다른 비율은 플랫폼이 잘라내거나 여백을 넣고, 어떻게 자를지는 플랫폼이 정하므로 글자와 로고는 가장자리에서 떼어 두세요. 사방에 5~10% 정도 여유를 두면 글자가 잘리지 않습니다.
og:image의 URL은 스킴을 포함한 절대 주소여야 합니다. https://example.com/img/card.png는 되고 /img/card.png는 안 됩니다. 크롤러는 페이지 맥락 없이 이미지를 직접 가져오므로 상대 경로는 기준이 될 것이 없습니다. HTTPS로 제공하고, 로그인 없이 정상적인 200 응답을 주는지 확인하고, 파일은 작게 유지하세요. 플랫폼 대부분에서 몇 MB가 상한이고, 수백 KB 정도면 안정적으로 불러오며 미리보기도 빠릅니다. 안전한 형식은 JPEG와 PNG이며, 크롤러가 해석하지 못할 수 있는 형식은 피하세요.
og:image:width와 og:image:height를 쓰면 플랫폼이 이미지를 내려받기 전에 알맞은 공간을 잡을 수 있어서, 처음 공유할 때 이미지가 작거나 빠진 카드가 나오는 일을 줄여 줍니다. og:image:alt는 이를 노출하는 플랫폼에서 실제 접근성 기능이므로 이미지가 보여 주는 내용을 한 문장으로 적으세요.
title과 description: 네 곳, 세 가지 역할
한 페이지에는 요약 텍스트가 최대 네 가지 있고, 서로 같을 필요는 없습니다. <title>과 메타 description은 검색 결과를 위한 것입니다. title은 클릭하는 제목이고, description은 검색엔진이 쓰거나 고쳐 쓰거나 무시할 수 있는 스니펫입니다. og:title과 og:description은 링크 카드를 위한 것으로, 검색 맥락 없이 링크가 공유된 자리에 표시됩니다.
이 차이 때문에 필요하면 따로 쓰는 편이 낫습니다. 검색용 제목에는 핵심 검색어를 앞에 두고 범위를 분명히 하는 것이 좋고, 공유용 제목은 더 짧고 눈길을 끌게 쓸 수 있습니다. 나눌 이유가 없으면 모든 곳에 같은 문구를 써도 괜찮으며 생성기도 그렇게 합니다. 생성기는 검색 제목의 픽셀 기준 미리보기도 보여 줍니다. Google은 글자 수가 아니라 렌더링된 폭(20px 기준 대략 600px)으로 제목을 자르는데, 도구는 Arial 글자 폭으로 그 폭을 추정하므로 근사치로 보세요.
| 태그 | 쓰이는 곳 | 일반적인 길이 목표 |
|---|---|---|
| <title> | 브라우저 탭, 검색 결과 제목 | 50~60자 안팎, 또는 폭 약 600px |
| meta description | 검색 스니펫(고쳐 쓰일 수 있음) | 120~160자 안팎 |
| og:title | 링크 카드 제목 | 잘리지 않을 길이. 60~90자 정도가 흔함 |
| og:description | 링크 카드 본문 | 한두 문장. 플랫폼마다 자르는 길이가 다름 |
canonical URL과 og:url
<link rel="canonical">은 추적 파라미터나 끝 슬래시 차이처럼 여러 URL이 같은 내용을 보여 줄 때 검색엔진에 어느 것이 대표 주소인지 알려 줍니다. og:url은 그에 해당하는 오픈그래프 속성으로, 플랫폼이 공유된 객체에 붙일 영구 주소입니다. 어느 변형 URL로 공유되든 좋아요와 공유 수가 한 URL에 모입니다.
둘 다 같은 깨끗한 절대 URL로 설정하세요. 생성기는 canonical 칸 하나로 두 태그를 모두 채웁니다. 입력한 값을 URL 파서로 정규화하기 때문에 https://example.com은 https://example.com/이 되고 경로의 공백은 %20이 됩니다. 두 값이 어긋나거나 canonical이 다른 페이지를 가리키면 플랫폼이 엉뚱한 페이지를 미리보기로 보여 줄 수 있습니다.
미리보기가 안 바뀌는 이유와 새로고침 방법
플랫폼은 누가 공유할 때마다 페이지를 새로 가져오지 않습니다. 한 번 스크랩해서 제목, 설명, 이미지를 캐시에 두고 몇 시간, 길게는 며칠 동안 같은 카드를 재사용합니다. 오타를 고치거나 이미지를 바꿨는데도 옛 카드가 나온다면 원인은 마크업이 아니라 캐시입니다.
확실한 방법은 두 가지입니다. 첫째, 플랫폼의 도구로 해당 URL을 다시 스크랩합니다. Facebook의 공유 디버거(Sharing Debugger)와 LinkedIn의 Post Inspector는 페이지를 다시 가져와 캐시를 갱신합니다. 둘째, 이미지 URL을 바꿉니다. 예를 들어 card-v2.png나 card.png?v=2로 바꾸면 옛 캐시 항목으로는 새 이미지를 보여 줄 수 없고, 이미지 URL이 바뀌어야만 이미지를 갱신하는 플랫폼도 있습니다. 모든 플랫폼에 디버거가 있는 것은 아니고 메신저 앱은 자체 캐시를 지울 방법이 없는 경우가 많아서, 이미지 URL 변경이 가장 이식성이 좋은 방법입니다.
출시 전에 미리 계획하세요. URL을 공개적으로 처음 공유하기 전에 최종 태그와 이미지를 확정해야 합니다. 첫 스크랩이 그대로 굳기 때문입니다.
흔한 실수와 원인
깨진 미리보기의 대부분은 몇 가지 원인으로 정리됩니다. 출시 전에 하나씩 확인하기 쉬운 항목들입니다.
- 상대 경로 이미지 URL: 크롤러가 기준으로 삼을 페이지가 없어 이미지가 나오지 않습니다. 절대 https URL을 쓰세요.
- width·height 누락: 플랫폼이 파일을 받기 전까지 첫 공유에서 이미지가 없거나 작게 나올 수 있습니다.
- 로그인이나 봇 차단 뒤의 페이지: 크롤러는 로그인 화면을 보고 그 제목과 이미지를 씁니다. 공개 페이지만 미리보기가 됩니다.
- robots.txt로 차단: robots.txt를 따르는 크롤러는 허용되지 않은 페이지나 이미지를 가져오지 않습니다. 이미지 폴더 경로까지 확인하세요.
- 클라이언트 JavaScript로만 렌더링한 태그: 미리보기 크롤러 대부분은 원본 HTML만 읽고 스크립트를 실행하지 않으므로, 태그가 서버가 내려주는 마크업에 있어야 합니다.
- URL 변형마다 값이 다름: canonical이 다른 곳을 가리키거나 og:url이 없으면, 공유한 페이지와 다른 페이지를 설명하는 카드가 나옵니다.
미리보기 크롤러와 이미지 경로의 robots.txt 확인
이미지 폴더를 검색에서 빼려고 막아 놓고는 공유 카드에 그림이 없다고 의아해하는 경우가 흔합니다. robots.txt 테스터는 규칙 세트를 사용자 에이전트와 경로에 대해 실행해 볼 수 있습니다. 아래 규칙과 사용자 에이전트 Twitterbot으로 실행하면 /img/og/post.png는 Disallow: /img/에 막히고, /img/public/og.png는 더 긴 Allow: /img/public/ 규칙에 허용되며, /members/profile은 막히고 /blog/post는 허용됩니다. 가장 길게 일치하는 규칙이 이기기 때문에 더 좁은 Allow가 넓은 Disallow를 이깁니다.
User-agent: *
Disallow: /img/
Disallow: /members/
Allow: /img/public/
# Twitterbot: /img/og/post.png -> 차단 (Disallow: /img/)
# Twitterbot: /img/public/og.png -> 허용 (Allow: /img/public/)
# Twitterbot: /members/profile -> 차단 (Disallow: /members/)
# Twitterbot: /blog/post -> 허용 (일치하는 규칙 없음)