개발

[브라우저] 북마크 이미지는 왜 엉뚱하게 떴을까?

woojin06 2026. 5. 27. 21:41

안녕하시와요

금일 한 금융 서비스 홈페이지를 크롬에서 북마크했더니
서비스 로고가 아니라 특정 정치인 이미지가 보였다는 이슈가 있었습니다

처음 내용을 봤을 때 저도 살짝 의아했어요

북마크에 저장하는데 왜 사이트랑 상관없는 이미지가 나오지?

보통 이런 일이 생기면 자연스럽게 이런 생각이 먼저 듭니다

  • 누가 사이트 코드에 이미지를 심은 건가?
  • 사이트 내부에서 뭔가 잘못 설정한 건가?
  • 혹시 해킹이나 보안 사고인가?

저도 처음엔 이쪽으로 생각이 갔습니다

근데 기사와 서비스 측 설명을 같이 보면
서비스 내부에 이미지를 심었다기보다는
브라우저가 북마크 UI에 보여줄 이미지를 고르는 과정에서 생긴 문제에 더 가까워 보였어요

그래서 이번 글은 정치적인 해석보다는
이번 일을 계기로 크롬 북마크와 대표 이미지가 어떻게 연결될 수 있는지
제가 이해한 범위에서 정리해보려고 합니다


먼저 결론부터

결론부터 말하면
북마크는 기본적으로 “이미지 저장 기능”이 아닙니다

Chrome Extensions 문서에서 chrome.bookmarks API를 보면
북마크 노드는 대략 이런 정보를 가집니다

id
title
url
parentId
dateAdded
children

즉 북마크의 핵심 데이터는
“어떤 제목의 URL을 어느 폴더에 저장했는가”에 가까워요

그런데 우리가 실제로 보는 브라우저 UI는
단순히 제목과 URL만 보여주지 않습니다

탭이나 북마크 바에서는 favicon을 보여주고
사이드 패널이나 북마크 관련 화면에서는
페이지 대표 이미지나 썸네일을 같이 보여주기도 하죠

여기서 조금 헷갈릴 수 있습니다

북마크 데이터에 이미지가 저장된 것과
브라우저 UI가 이미지를 찾아서 보여주는 것은 다르다

저는 이 부분을 나눠서 보는 게
이번 이슈를 이해하는 핵심이라고 봤습니다


북마크 저장은 생각보다 단순하다

북마크를 저장한다고 해서
브라우저가 페이지 안의 이미지를 그대로 북마크 데이터에 넣는 것은 아닙니다

기본 흐름만 보면 꽤 단순해요

  1. 사용자가 별표 버튼을 누른다
  2. 브라우저가 현재 페이지의 제목과 URL을 저장한다
  3. 사용자가 저장 위치나 이름을 바꿀 수 있다
  4. 이후 북마크 목록에서 해당 URL로 다시 이동한다

여기까지만 보면 이미지는 핵심 데이터가 아닙니다

그런데 문제는 저장이 아니라 표시 쪽에서 생깁니다

북마크 목록을 보여줄 때 브라우저는
사용자가 페이지를 더 쉽게 구분할 수 있도록
작은 아이콘이나 대표 이미지를 같이 보여줄 수 있어요

이때 후보가 되는 것들은 보통 이런 것들입니다

  • favicon
  • apple-touch-icon
  • manifest 아이콘
  • og:image
  • 브라우저가 별도로 가져온 대표 이미지
  • 캐시된 이미지

그래서 이 상황은
“북마크에 이상한 이미지가 저장됐다”라기보다
“북마크를 보여주는 화면에서 이상한 이미지가 붙었다”라고 보는 게 더 정확합니다

처음엔 비슷해 보이지만
기술적으로는 꽤 다른 이야기예요


웹사이트는 대표 이미지를 어떻게 알려줄까

웹사이트는 브라우저나 검색엔진, 카카오톡 공유, 디스코드 미리보기 같은 곳에
자기 자신을 설명하기 위한 메타 정보를 넣어둡니다

대표적으로는 이런 식이에요

<title>Example Service</title>
<link rel="icon" href="/favicon.ico" />

<meta property="og:title" content="Example Service" />
<meta property="og:description" content="서비스 설명" />
<meta property="og:image" content="https://example.com/thumbnail.png" />

여기서 favicon은 탭이나 북마크 바에 보이는 작은 아이콘이고
og:image는 링크 공유 미리보기에서 주로 쓰이는 대표 이미지입니다

처음에는 저도 이렇게 생각했습니다

북마크면 favicon만 보면 되는 거 아닌가?

근데 요즘 브라우저 UI는 예전보다 훨씬 시각적입니다

단순 북마크 바에서는 favicon 정도면 충분할 수 있지만
사이드 패널이나 북마크 관리 화면처럼 공간이 넓은 UI에서는
페이지를 더 쉽게 알아볼 수 있도록 대표 이미지를 같이 보여줄 수 있어요

그래서 북마크 이미지 문제를 볼 때
favicon만 보고 끝내면 원인을 놓칠 수 있습니다


크롬 코드에서는 어떻게 보일까

Chromium 코드에도 북마크와 대표 이미지가 연결되는 흐름이 보입니다

다만 여기서 하나 조심해야 합니다

이 코드가 “크롬의 모든 북마크 UI가 항상 이 방식으로 동작한다”는 뜻은 아니에요

제가 확인한 코드는 side_panel/bookmarks
즉 북마크 사이드 패널 계열의 코드입니다

해당 코드에는 이런 부분이 있습니다

await PageImageServiceBrowserProxy.getInstance()
  .handler.getPageImageUrl(
    PageImageServiceClientId.Bookmarks,
    url,
    { suggestImages: false, optimizationGuideImages: true }
  );

주석도 꽤 직관적입니다

// Fetch the representative image for this page, if possible.

가능하면 이 페이지의 대표 이미지를 가져온다는 뜻이죠

여기서 정리할 수 있는 건 두 가지입니다

  1. 북마크 데이터 자체에 이미지가 필수로 저장되는 것은 아니다
  2. 북마크를 보여주는 일부 UI는 대표 이미지를 별도로 요청할 수 있다

그래서 북마크 이미지 동작을 설명할 때
“크롬 북마크는 무조건 PageImageService를 쓴다”라고 쓰면 조금 과합니다

대신 이렇게 보는 게 안전해요

Chromium 계열 브라우저에는
북마크 UI에서 페이지 대표 이미지를 별도로 가져오는 코드 경로가 있다

딱 여기까지가 현재 확인 가능한 범위라고 봅니다


그럼 왜 엉뚱한 이미지가 나올 수 있을까

가능한 흐름을 단순화하면 이렇습니다

  1. 사용자가 어떤 사이트를 크롬에서 북마크한다
  2. 브라우저가 북마크 UI에 보여줄 제목, URL, 아이콘을 준비한다
  3. 특정 UI에서는 페이지 대표 이미지도 함께 가져오려고 한다
  4. 이때 사이트 메타데이터, 브라우저 이미지 서비스, 캐시된 데이터가 후보가 될 수 있다
  5. 그 후보가 잘못 연결되면 사이트와 상관없는 이미지가 보일 수 있다

여기서 중요한 건
랜덤으로 아무 이미지나 뽑는다는 뜻은 아니라는 점입니다

브라우저가 fallback을 쓴다고 해도
완전히 무작위로 이미지를 보여준다기보다는
사이트 메타데이터, 기존 캐시, 이미지 서비스가 가진 후보군 안에서
대표 이미지로 쓸 만한 값을 찾는 쪽에 가깝습니다

문제는 그 후보군이나 캐시가 잘못 엮였을 때예요

사용자 눈에는 랜덤처럼 보일 수 있지만
기술적으로는 후보 이미지 선택 또는 캐시 매칭이 잘못된 상황으로 보는 게 더 정확해 보입니다

그러다 보니 사용자 입장에서는 이렇게 느낄 수 있습니다

내가 이 사이트를 저장했는데 왜 전혀 다른 이미지가 나오지?

이렇게 느끼는 게 당연하죠

하지만 기술적으로 보면
사이트 화면에 이미지가 박힌 문제와
크롬 북마크 UI가 잘못된 대표 이미지를 붙인 문제는 다릅니다

북마크 이미지 문제를 볼 때는
이 둘을 분리해서 보는 게 중요합니다


캐시가 문제를 더 헷갈리게 만든다

또 하나 중요한 게 캐시입니다

브라우저는 매번 모든 정보를 새로 가져오지 않습니다
속도를 위해 아이콘, 이미지, 메타데이터, 썸네일 정보를 저장해두고 재사용합니다

그래서 한 번 잘못된 이미지가 연결되면
사용자 입장에서는 이런 일이 생길 수 있어요

  • 새로고침해도 그대로 보인다
  • 어떤 PC에서는 보이고, 어떤 PC에서는 다르게 나온다
  • 크롬에서는 보이는데 다른 브라우저에서는 안 뜬다
  • 캐시 삭제 후에는 달라질 수 있다

이 지점이 문제를 더 헷갈리게 만듭니다

분명 어떤 사람에게는 재현되는데
다른 사람에게는 재현되지 않을 수 있기 때문입니다

그러면 커뮤니티에서는

나는 봤다
나는 안 보인다

가 섞이면서 원인 파악이 더 어려워집니다

저도 이런 류의 문제를 볼 때마다 느끼지만
캐시가 끼면 디버깅 난이도가 갑자기 올라갑니다


코드로 보면 더 이해가 쉽다

예를 들어 어떤 사이트에 대표 이미지 정보가 애매하게 들어가 있다고 해보겠습니다

<title>Example Service</title>
<link rel="icon" href="/favicon.ico" />

이 경우 작은 아이콘은 가져올 수 있지만
큰 미리보기 이미지로 쓸 대표 이미지는 명확하지 않을 수 있어요

반대로 아래처럼 명확하게 지정되어 있다면
브라우저나 외부 서비스가 잘못 추측할 여지가 줄어듭니다

<title>Example Service</title>
<link rel="icon" href="/favicon.ico" />
<link rel="apple-touch-icon" href="https://static.example.com/icon.png" />
<meta property="og:image" content="https://static.example.com/service-og.png" />
<meta name="twitter:image" content="https://static.example.com/service-og.png" />

물론 이렇게 한다고 모든 브라우저 동작을 100% 제어할 수 있는 건 아닙니다

그래도 웹사이트 입장에서는
“대표 이미지는 이거야”라고 최대한 명확하게 말해주는 게 중요합니다

브라우저나 외부 서비스가 추측할 여지를 줄여주는 셈이죠


이 동작에서 핵심은 무엇일까

북마크 이미지 문제를 단순히
“브라우저 버그였다”
정도로만 보면 조금 아쉽습니다

웹서비스 입장에서 보면 꽤 중요한 포인트 같아요

사용자가 보는 화면은 내 서비스 코드만으로 만들어지지 않는다

브라우저, 검색엔진, 캐시, 공유 미리보기, 앱 링크 프리뷰까지 서비스 바깥의 시스템이 이미지를 같이 만듭니다

특히 로그인, 결제, 금융, 채용처럼 신뢰가 중요한 서비스에서는
작은 대표 이미지 하나도 이상하게 보이면 사용자가 바로 이상함을 느낄 수 있습니다

기술적으로는 단순한 썸네일 문제일 수 있습니다

하지만 사용자 입장에서는 “이 사이트가 왜 이런 이미지를 보여주지?” 라는 신뢰 문제로 받아들일 수 있어요

그래서 이런 메타데이터 관리도 생각보다 중요한 것 같습니다


개발자가 확인하면 좋은 것들

어찌 보면 개발자 입장에서 확인해야 할 부분은 꽤 명확합니다

  1. favicon이 정상적으로 설정되어 있는지 확인한다
  2. apple-touch-icon이나 웹앱 매니페스트 아이콘도 확인한다
  3. og:image, twitter:image 같은 대표 이미지를 명확히 넣는다
  4. 이미지 URL이 404를 내지 않는지 확인한다
  5. 이미지가 리다이렉트나 권한 문제 없이 접근 가능한지 확인한다
  6. 배포 후 카카오톡, 디스코드, 크롬 북마크, 검색 결과에서 실제 미리보기를 확인한다
  7. 문제가 재현되면 캐시 삭제 전후를 나눠서 테스트한다

예전에 차트 이미지 404 때문에 삽질했던 것처럼
이미지 URL 하나가 잘못되면 생각보다 많은 곳에서 이상하게 보일 수 있습니다

웹에서는 “화면에 직접 렌더링되는 부분”만 중요한 게 아니라
외부 서비스가 읽어가는 메타데이터도 같이 관리해야 좋습니다


직접 확인해볼 수 있는 코드

그럼 실제 사이트에서 대표 이미지 후보를 어떻게 확인할 수 있을까요?

브라우저 개발자 도구 콘솔에서 아래 코드를 실행하면
현재 페이지가 브라우저나 외부 서비스에 알려주는 이미지 관련 메타데이터를 볼 수 있습니다

const imageHints = [
  ...document.querySelectorAll(`
    link[rel*="icon"],
    link[rel="manifest"],
    meta[property="og:image"],
    meta[property="og:image:secure_url"],
    meta[name="twitter:image"]
  `),
].map((node) => ({
  tag: node.tagName.toLowerCase(),
  key: node.getAttribute("rel")
    || node.getAttribute("property")
    || node.getAttribute("name"),
  value: node.getAttribute("href")
    || node.getAttribute("content"),
}));

console.table(imageHints);

여기서 og:imagetwitter:image가 비어 있거나
이미지 URL이 깨져 있거나
접근할 수 없는 URL이라면 미리보기 이미지가 이상하게 나올 가능성이 커집니다

이미지가 실제로 로드되는지도 확인해볼 수 있습니다

const imageUrls = imageHints
  .map((hint) => hint.value)
  .filter(Boolean)
  .map((url) => new URL(url, location.href).href);

function checkImage(url) {
  return new Promise((resolve) => {
    const image = new Image();

    image.onload = () => {
      resolve({
        url,
        ok: true,
        width: image.naturalWidth,
        height: image.naturalHeight,
      });
    };

    image.onerror = () => {
      resolve({
        url,
        ok: false,
        width: 0,
        height: 0,
      });
    };

    image.src = url;
  });
}

Promise.all(imageUrls.map(checkImage)).then(console.table);

 

해당 코드에서 okfalse로 나오면
브라우저나 외부 미리보기 서비스가 그 이미지를 정상적으로 쓰기 어렵습니다

터미널에서 간단히 확인하고 싶다면 이런 식으로도 볼 수 있어요

curl -L https://example.com \
  | rg '<(meta|link)[^>]+(og:image|twitter:image|icon|manifest)[^>]+>'

물론 이 코드만으로 크롬 내부 캐시나 PageImageService의 최종 선택 결과까지 볼 수 있는 건 아닙니다

그래도 최소한 사이트가 어떤 대표 이미지 후보를 노출하고 있는지는 확인이 가능하죠

저라면 이 이슈를 디버깅할 때 먼저 이 순서로 볼 것 같습니다

  1. 페이지의 favicon, og:image, twitter:image 확인
  2. 해당 이미지 URL이 실제로 로드되는지 확인
  3. 시크릿 창 또는 캐시 삭제 후 북마크 UI 재현
  4. 다른 브라우저와 비교
  5. 그래도 다르면 크롬 쪽 캐시/대표 이미지 선택 문제로 범위를 좁힘

정리

북마크 이미지 문제는
겉으로 보면 단순히 이상한 이미지가 보인 사건처럼 보입니다

하지만 안쪽으로 들어가면
북마크 데이터와 북마크 UI를 구분해야 이해할 수 있는 문제였습니다

핵심만 정리하면 이렇습니다

  1. 북마크 자체는 기본적으로 제목과 URL을 저장하는 기능이다
  2. 북마크 UI는 favicon이나 대표 이미지를 별도로 가져와 보여줄 수 있다
  3. Chromium에는 북마크 UI에서 PageImageService로 대표 이미지를 요청하는 코드 경로가 있다
  4. 캐시나 이미지 후보가 잘못 연결되면 사이트와 상관없는 이미지가 보일 수 있다
  5. 그래서 웹서비스는 favicon, og:image, twitter:image, 공유 미리보기를 같이 관리해야 한다

처음에는 저도
“북마크에 왜 저런 이미지가 뜨지?”라고 생각했습니다

근데 브라우저 동작 방식을 따라가보니
단순히 사이트 코드 하나만 보고 판단하기는 어렵다는 걸 알 수 있었습니다

웹에서 사용자가 보는 화면은
생각보다 많은 시스템이 함께 만들어내는 결과였어요


참고 자료