Next.js OG 이미지 완전 가이드: SEO부터 로고·이미지·폰트 적용까지
웹사이트 주소를 카카오톡이나 슬랙에 공유하면 제목, 설명과 함께 대표 이미지가 표시됩니다. 이 이미지를 흔히 OG 이미지라고 부릅니다.
OG 이미지는 사이트 본문에는 직접 보이지 않지만, 링크가 공유되는 순간에는 본문보다 먼저 사용자에게 노출됩니다. 이미지가 흐리거나 제목이 잘리고 실제 사이트와 다른 로고가 표시되면 링크의 신뢰도도 함께 낮아질 수 있습니다.
이번 글에서는 OG 이미지가 표시되는 원리부터 Next.js에서 이미지를 동적으로 생성하는 방법, 브랜드 로고와 커스텀 폰트 적용, 다국어 처리, SEO와 캐시 관리 시 주의할 점까지 살펴봅니다.
OG 이미지는 이미지 파일 하나로 끝나지 않습니다
OG는 Open Graph의 약자입니다. 웹페이지의 제목, 설명, 이미지와 주소를 소셜 미디어와 메신저가 이해할 수 있도록 전달하는 메타데이터 규격입니다.
웹페이지의 <head>에는 다음과 같은 정보가 들어갑니다.
<meta property="og:type" content="website" />
<meta property="og:title" content="웹·앱·AI 자동화 개발 | 듀오랩스" />
<meta property="og:description" content="웹사이트, 앱, 업무 시스템과 AI 자동화를 개발합니다." />
<meta property="og:url" content="https://duolabs.co.kr" />
<meta property="og:image" content="https://duolabs.co.kr/social/ko/og.png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:type" content="image/png" />
<meta property="og:image:alt" content="듀오랩스 서비스 소개 이미지" />Open Graph 규격의 핵심 속성은 og:title, og:type, og:image, og:url입니다. 이미지에는 크기와 형식, 대체 설명도 함께 지정할 수 있습니다. og:image:alt에는 홍보 문구보다 이미지에 무엇이 들어 있는지 설명하는 문장이 적합합니다.
이미지 파일을 서버에 올려두는 것만으로는 충분하지 않습니다. 페이지의 메타데이터가 이미지의 공개된 절대 URL을 정확히 가리켜야 합니다.
사용자가 링크를 공유하면 다음과 같은 순서로 처리됩니다.
링크 공유
→ 플랫폼 크롤러가 웹페이지 방문
→ Open Graph 메타데이터 확인
→ og:image 주소로 이미지 요청
→ 제목·설명·이미지로 링크 카드 구성
→ 결과를 플랫폼 서버에 캐시문제가 생겼을 때는 이미지 디자인뿐 아니라 메타데이터, 이미지 응답과 플랫폼 캐시까지 함께 확인해야 합니다.
OG 이미지가 SEO 순위를 직접 올릴까요?
OG 이미지를 설정한다고 검색 순위가 곧바로 올라가는 것은 아닙니다. “OG 이미지를 넣으면 상위 노출된다”라고 설명하는 것은 정확하지 않습니다.
OG 이미지의 직접적인 목적은 링크가 공유될 때 페이지를 정확하고 매력적으로 표현하는 것입니다. 다만 다음과 같은 간접 효과를 기대할 수 있습니다.
- 공유 링크의 신뢰도와 브랜드 인지도를 높일 수 있습니다.
- 제목과 이미지가 명확하면 사용자가 링크의 내용을 빠르게 파악할 수 있습니다.
- 소셜 미디어와 메신저에서 클릭 가능성을 높일 수 있습니다.
- 검색엔진이 페이지의 대표 이미지를 선택할 때
og:image를 참고할 수 있습니다.
Google은 검색 결과에 표시할 이미지를 자동으로 선택하지만 og:image나 구조화 데이터의 이미지를 통해 선호 이미지를 전달할 수 있다고 설명합니다. 동시에 검색용 대표 이미지는 페이지 내용과 관련되어야 하며, 일반적인 로고나 텍스트 위주의 이미지는 피하라고 권장합니다.
여기에는 용도에 따른 차이가 있습니다.
- 회사 홈페이지나 서비스 소개 페이지에서는 브랜드 메시지가 들어간 카드가 대표 이미지 역할을 할 수 있습니다.
- 블로그, 사례 연구와 제품 페이지에서는 실제 내용을 보여주는 사진이나 일러스트를 중심으로 구성하는 편이 좋습니다.
- Google Discover나 이미지 검색이 중요하다면 텍스트가 많은 공유 카드 외에 콘텐츠 대표 이미지를 구조화 데이터로 별도 제공하는 방법도 고려할 수 있습니다.
소셜 공유에 좋은 이미지와 검색엔진의 콘텐츠 대표 이미지가 항상 같은 것은 아닙니다.
정적 이미지와 동적 이미지
가장 간단한 방법은 미리 만든 PNG나 JPG 파일을 사용하는 것입니다. 사이트 전체에 같은 이미지를 사용한다면 관리하기 쉽고 렌더링 비용도 거의 없습니다.
하지만 블로그 글, 상품, 포트폴리오처럼 페이지마다 제목과 이미지가 달라져야 한다면 매번 파일을 제작해야 합니다. 이때 동적 OG 이미지를 활용할 수 있습니다.
동적 OG 이미지는 페이지 제목, 작성자, 카테고리와 언어 같은 데이터를 받아 서버가 이미지를 자동으로 생성합니다. Next.js에서는 next/og의 ImageResponse를 이용해 JSX와 CSS로 이미지를 만들 수 있습니다.
import { ImageResponse } from "next/og";
export const size = {
width: 1200,
height: 630,
};
export const contentType = "image/png";
export default function OpenGraphImage() {
return new ImageResponse(
(
<div
style={{
width: "100%",
height: "100%",
display: "flex",
alignItems: "center",
justifyContent: "center",
background: "#ffffff",
color: "#0b1730",
fontSize: 64,
fontWeight: 800,
}}
>
Next.js로 OG 이미지 만들기
</div>
),
size
);
}페이지마다 제목만 전달해도 동일한 브랜드 템플릿으로 여러 OG 이미지를 만들 수 있습니다.
JSX가 PNG 이미지가 되는 과정
ImageResponse에 JSX와 CSS를 전달한다고 해서 브라우저 화면을 캡처하는 것은 아닙니다.
내부에서는 Satori라는 렌더링 엔진이 JSX와 CSS를 SVG로 변환하고, 그 결과를 다시 PNG 이미지로 렌더링합니다.
JSX와 CSS
→ Satori가 레이아웃과 글자를 SVG로 변환
→ SVG를 PNG로 렌더링
→ ImageResponse가 PNG 응답 반환Satori는 일반적인 HTML과 CSS에 가까운 방식으로 이미지를 설계할 수 있다는 장점이 있지만 실제 브라우저와 동일한 렌더러는 아닙니다. 지원하는 HTML과 CSS 범위가 제한되어 있으므로 브라우저에서 보이는 결과를 그대로 기대해서는 안 됩니다.
메타데이터와 이미지 연결하기
Next.js의 Metadata 객체를 이용하면 Open Graph와 X의 대형 이미지 카드를 함께 설정할 수 있습니다.
const socialImage =
`https://duolabs.co.kr/social/${locale}/og.png`;
return {
title,
description,
openGraph: {
type: "website",
siteName: "Duolabs",
title,
description,
url: canonicalUrl,
locale: "ko_KR",
images: [
{
url: socialImage,
width: 1200,
height: 630,
alt: "듀오랩스 웹·앱·업무 시스템·AI 자동화 개발",
},
],
},
twitter: {
card: "summary_large_image",
title,
description,
images: [socialImage],
},
};이미지 주소는 가능하면 https://로 시작하는 절대 URL을 사용합니다. 크기와 대체 설명까지 제공하면 플랫폼이 이미지를 해석하기 쉬워집니다.
OG 이미지의 기본 구성
듀오랩스에서는 범용성이 높은 1200×630 크기를 사용했습니다. 이미지 안에는 다음 요소를 배치했습니다.
- 실제 사이트와 동일한 브랜드 마크와 워드마크
- 서비스의 성격을 보여주는 핵심 키워드
- 작은 카드에서도 읽을 수 있는 핵심 문장
- 내용을 보완하는 일러스트
- 사이트 도메인과 브랜드 색상
- 한국어·영어·일본어·중국어별 문구
플랫폼마다 이미지를 조금씩 다르게 자를 수 있으므로 로고와 제목 같은 핵심 요소는 가장자리에서 여유를 두는 것이 안전합니다. 모바일 미리보기에서도 읽을 수 있도록 본문보다 큰 글자를 사용하고 제목과 배경의 명도 차이를 충분히 확보해야 합니다.
실제 사이트와 동일한 로고 적용하기
OG 이미지에서 자주 발생하는 문제 중 하나는 사이트 로고와 공유 이미지의 로고가 서로 다른 경우입니다. 임시 아이콘이나 비슷하게 만든 도형을 사용하면 작은 이미지에서는 그럴듯해 보여도 브랜드 일관성이 깨집니다.
로고는 가능하면 사이트에서 사용하는 원본 자산을 재사용하는 것이 좋습니다.
단순한 심볼이나 벡터 로고라면 인라인 SVG가 적합합니다.
- 확대해도 선명합니다.
- 색상과 크기를 코드에서 조절할 수 있습니다.
- 외부 이미지 요청이 필요하지 않습니다.
- 사이트 로고의 SVG 좌표를 그대로 재사용할 수 있습니다.
사진이나 복잡한 일러스트는 PNG 또는 JPG로 준비한 뒤 서버에서 읽어 전달할 수 있습니다.
import { readFile } from "node:fs/promises";
import path from "node:path";
const image = await readFile(
path.join(process.cwd(), "public", "illust", "og-illustration.png")
);
const imageSrc =
`data:image/png;base64,${image.toString("base64")}`;<img
src={imageSrc}
width={414}
height={311}
style={{ objectFit: "contain" }}
/>이미지의 가로와 세로 크기를 명시하면 렌더링 결과를 더 예측하기 쉽습니다.
웹사이트 폰트가 자동으로 적용되지 않는 이유
OG 이미지는 일반 웹페이지가 아니므로 웹사이트의 CSS나 next/font 설정이 자동으로 적용되지 않습니다.
웹페이지에서 Pretendard를 사용하더라도 OG 렌더러에 폰트를 별도로 전달하지 않으면 대체 글꼴로 렌더링될 수 있습니다. 이 경우 줄바꿈 위치, 글자 폭과 굵기까지 달라집니다.
Satori 공식 문서 기준으로 지원되는 폰트 형식은 TTF, OTF와 WOFF이며 WOFF2는 지원되지 않습니다. 웹페이지에서 WOFF2 가변 폰트를 사용한다면 OG 이미지용으로 필요한 굵기의 정적 WOFF 파일을 별도로 준비할 수 있습니다.
public/fonts/og/
├── Pretendard-Medium.woff
├── Pretendard-Bold.woff
└── Pretendard-ExtraBold.woff각 파일을 읽어 ImageResponse의 fonts 옵션에 전달합니다.
const fonts = await Promise.all([
["Pretendard-Medium.woff", 500],
["Pretendard-Bold.woff", 700],
["Pretendard-ExtraBold.woff", 800],
].map(async ([file, weight]) => ({
name: "Pretendard",
data: await readFile(
path.join(process.cwd(), "public", "fonts", "og", file)
),
weight,
style: "normal",
})));return new ImageResponse(
<div style={{ fontFamily: "Pretendard" }}>
웹·앱·AI 자동화 개발
</div>,
{
width: 1200,
height: 630,
fonts,
}
);이 폰트들은 OG 이미지를 생성할 때만 읽습니다. 웹페이지에서 불러오지 않는다면 방문자의 페이지 로딩 성능에는 영향을 주지 않습니다.
Satori에서 CSS를 사용할 때 주의할 점
Satori에서는 Flexbox를 중심으로 레이아웃을 구성하는 것이 안정적입니다.
- 필요한 요소에
display: flex를 명시합니다. z-index대신 JSX에 작성된 요소 순서로 겹침을 조절합니다.calc()와 3D transform은 피합니다.- 외부 스타일시트보다 인라인 스타일을 사용합니다.
- 긴 제목은 최대 줄 수와 폰트 크기를 제한합니다.
- 다국어 글꼴에 필요한 문자가 모두 들어 있는지 확인합니다.
- 로컬에서 실제 이미지를 렌더링해 줄바꿈과 정렬을 확인합니다.
라이브러리의 지원 범위는 버전에 따라 달라질 수 있으므로 적용 시점의 공식 문서를 함께 확인하는 것이 좋습니다.
다국어 OG 이미지 구성하기
다국어 사이트에서 모든 언어가 같은 한국어 OG 이미지를 사용하면 공유된 페이지의 언어와 미리보기 내용이 어긋납니다.
언어별 이미지 주소를 분리하면 관리하기 쉽습니다.
/social/ko/og.png
/social/en/og.png
/social/ja/og.png
/social/zh/og.png렌더러에서는 locale에 따라 제목과 설명을 선택합니다. 언어마다 문장 길이와 글자 폭이 다르기 때문에 번역문만 교체해서는 안 됩니다. 폰트 크기, 줄바꿈, 자간과 영역 너비도 언어별로 직접 확인해야 합니다.
og:locale, og:locale:alternate와 이미지 대체 설명 역시 페이지 언어에 맞춰 관리하는 것이 좋습니다.
메타 타이틀은 키워드와 브랜드를 어떻게 배치할까
서비스 페이지의 메타 타이틀은 다음과 같이 핵심 주제를 먼저 보여주고 브랜드를 뒤에 배치할 수 있습니다.
스타트업·중소기업 웹·앱·AI 자동화 개발 | 듀오랩스검색 결과에서 제목이 잘리더라도 사용자가 페이지의 성격을 먼저 파악할 수 있다는 장점이 있습니다.
다만 키워드를 앞에 배치하는 것 자체가 순위를 보장하지는 않습니다. 제목은 페이지 내용을 정확하게 설명하면서 간결해야 하고 같은 키워드를 반복해서 넣어서는 안 됩니다.
Google은 검색 결과 제목을 <title>만으로 결정하지 않습니다. 화면의 주요 제목, <h1>, og:title과 링크 텍스트 등 여러 정보를 종합할 수 있습니다. 따라서 메타 타이틀과 실제 페이지 제목이 서로 다른 내용을 말하지 않도록 일관성을 유지해야 합니다.
동적 OG 이미지의 활용 방법
한 번 만든 템플릿은 여러 콘텐츠에 확장할 수 있습니다.
블로그 게시물
글 제목, 카테고리, 작성일과 대표 이미지를 자동으로 조합할 수 있습니다.
포트폴리오와 고객 사례
프로젝트명, 개발 분야와 주요 결과를 카드 형태로 보여줄 수 있습니다. 공개 승인을 받지 않은 고객명이나 내부 지표가 이미지에 포함되지 않도록 주의해야 합니다.
제품과 서비스
제품 이름, 핵심 특징, 버전 또는 출시 상태를 데이터에서 가져와 표시할 수 있습니다.
이벤트와 채용 공고
행사명, 날짜, 모집 직군과 접수 기간이 바뀔 때 이미지를 다시 디자인하지 않고 데이터로 생성할 수 있습니다.
다국어 콘텐츠
같은 브랜드 디자인을 유지하면서 언어별 문구와 글자 크기를 조정할 수 있습니다.
OG 이미지는 단순한 대표 이미지가 아니라 콘텐츠 데이터를 시각적으로 표현하는 자동화 템플릿으로 활용할 수 있습니다.
배포 후 이미지가 바뀌지 않을 때
OG 이미지와 메타데이터가 정상적으로 배포됐는데 카카오톡에서 이전 이미지가 계속 표시될 수 있습니다. 카카오가 처음 수집한 정보를 서버에 캐시하기 때문입니다.
이 경우 카카오 개발자 도구의 공유 디버거에서 페이지 URL 또는 이미지 URL의 OG 캐시를 초기화합니다.
캐시를 초기화했는데도 이전 내용이 보인다면 다음을 다시 확인합니다.
- 페이지의 OG 메타 태그가 실제로 변경됐는가
- 이미지 URL이 올바른가
- 이미지 자체가 외부에서 정상적으로 열리는가
- 페이지 URL과 이미지 URL 중 어느 쪽이 캐시됐는가
- 새 채팅방에서 링크를 다시 전송했는가
배포 전 체크리스트
- 이미지가 의도한 크기와 비율로 렌더링되는가
- 작은 모바일 미리보기에서도 제목을 읽을 수 있는가
- 로고가 실제 사이트의 브랜드 자산과 일치하는가
- 이미지 가장자리에서 핵심 콘텐츠가 충분히 떨어져 있는가
- 이미지 URL이 외부에서 인증 없이 열리는가
- 이미지 요청이 HTTP 200과 올바른
Content-Type을 반환하는가 og:title,og:description,og:url,og:image가 들어 있는가og:image:width,og:image:height,og:image:alt가 설정됐는가- X용
summary_large_image가 설정됐는가 - 지원하는 모든 언어를 각각 렌더링해 확인했는가
- 긴 제목에서도 줄바꿈이 깨지지 않는가
- 배포 후 주요 공유 플랫폼의 캐시를 갱신했는가
마치며
OG 이미지는 개발 과정에서 우선순위가 낮아지기 쉽지만 링크가 공유되는 순간에는 사이트보다 먼저 사용자에게 노출되는 화면입니다.
잘 만든 OG 이미지는 화려함보다 정확성이 중요합니다. 실제 브랜드 로고를 사용하고 페이지 내용과 일치하는 제목과 이미지를 제공하며 작은 화면에서도 읽을 수 있어야 합니다.
Next.js의 동적 이미지 생성 기능을 활용하면 블로그, 서비스, 포트폴리오와 다국어 페이지에 일관된 브랜드 이미지를 자동으로 적용할 수 있습니다. 한 번 제대로 만든 템플릿은 새로운 콘텐츠가 추가될 때마다 반복되는 이미지 제작 작업도 크게 줄여줍니다.
참고 자료
함께 읽기
- 클릭했는데 화면이 늦게 바뀌는 느낌을 줄이는 방법사용자가 버튼이나 링크를 눌렀는데 아무 반응이 없는 것처럼 보이면, 실제 로딩 시간이 길지 않아도 서비스가 느리다고 느낍니다. 이 문제는 단순한 성능 문제가 아니라 체감 성능과 피드백의 문제입니다.
- Next.js와 Postgres 조합이 작은 팀에 좋은 이유웹 서비스를 만들 때 기술 스택은 단순한 취향 문제가 아닙니다. 개발 속도, 유지보수, 확장성, 채용 가능성, 운영 비용까지 영향을 줍니다. 작은 팀이나 1인 개발 조직이라면 특히 “적은 인원으로 오래 가져갈 수 있는 조합”이 중요합니다.
- Google 번역을 켰더니 React 앱이 오류 화면으로 바뀐 이유한국어, 영어, 일본어, 중국어를 직접 제공하는 React 랜딩 페이지에서 예상하지 못한 문제가 생겼습니다. Chrome이 띄운 "이 페이지를 번역하시겠습니까?" 제안을 수락하면 번역이 시작되는 듯하다가, 잠시 뒤 사이트의 "일시적인 오류가 발생했습니다" 화면으로 바뀌었습니다.
- 데스크톱 AI 화면을 모바일에서 과감히 제거한 이유데스크톱에서 잘 작동하는 AI 인터페이스를 모바일 화면에 그대로 줄이면 기능은 남지만 경험은 쉽게 무너집니다. 사이드바, 대화, 참고 문헌을 동시에 보여주는 3단 구조는 넓은 화면에서는 강력하지만 작은 화면에서는 탐색과 스크롤이 서로 경쟁합니다.
- iOS Safari 모바일 버그 3종 해결기: 헤더 잘림 · 흰 화면 · 가로 넘침같은 날 확인된 세 증상은 원인이 서로 달랐으며, 모두 해당 테스트 환경에서 데스크톱 Chrome과 다르게 나타난 WebKit 관련 동작이었습니다.