본문으로 건너뛰기
Back to blog
Kakao SDK

Kakao Share Thumbnail Not Showing? Here's the Fix (JavaScript SDK 2025)

Learn why Kakao Share thumbnails don't appear even with a valid imageUrl, and fix it using scrapImage to convert your URL into a KAGE CDN URL. Step-by-step guide.

5 min readKakao SDK
Kakao SDKKakaoTalk ShareJavaScriptFrontendWeb Development

Kakao Share Thumbnail Not Showing? Here's the Fix (JavaScript SDK 2025)

You've implemented KakaoTalk sharing and set imageUrl correctly — but the thumbnail simply doesn't appear in the share preview. If this sounds familiar, the root cause lies in Kakao's internal CDN policy. This guide covers the exact reason and the code fix, step by step.

KakaoTalk share preview comparison — small thumbnail on the left vs. full-size thumbnail on the right

Why Kakao Share Thumbnails Don't Show Up

When you pass an external image URL directly to the imageUrl field of sendDefault(), the thumbnail often fails to render.

// ❌ This won't show a thumbnail
Kakao.Share.sendDefault({
  objectType: 'feed',
  content: {
    title: 'Share Title',
    description: 'Share description',
    imageUrl: 'https://example.com/my-image.png', // ← won't appear!
    link: { webUrl: 'https://example.com', mobileWebUrl: 'https://example.com' },
  },
});

Even if the image is publicly accessible, why does it fail?

Kakao serves share preview images through its own CDN (the KAGE server at k.kakaocdn.net). When you pass an external URL to imageUrl, Kakao's server attempts to fetch and re-host the image on KAGE — and this process frequently fails silently, leaving the thumbnail blank.

The fix is to upload the image to KAGE yourself first, then pass the resulting KAGE URL to imageUrl.

Fix: Use scrapImage to Get a KAGE URL

The solution to Kakao share thumbnail issues is to call Kakao.Share.scrapImage() first, upload the image to KAGE, then use the returned URL in imageUrl.

// ✅ Fix: scrapImage → KAGE URL → sendDefault
const imageUrl = 'https://example.com/my-image.png';

// Step 1: Upload to Kakao KAGE server
const result = await Kakao.Share.scrapImage({ imageUrl });
const kageUrl = result.infos.original.url;
// → "http://k.kakaocdn.net/dn/xxxxx/kakaolink40_original.png"

// Step 2: Share using the KAGE URL
Kakao.Share.sendDefault({
  objectType: 'feed',
  content: {
    title: 'Share Title',
    description: 'Share description',
    imageUrl: kageUrl, // ← use KAGE URL here
    link: { webUrl: 'https://example.com', mobileWebUrl: 'https://example.com' },
  },
});

Just two steps, and the KakaoTalk share thumbnail displays correctly.

Full Implementation with Caching

Calling scrapImage on every share triggers unnecessary API requests. Add a cache variable to upload only once and reuse the result.

let cachedKageUrl = null;

async function getKageImageUrl(imageUrl) {
  if (cachedKageUrl) return cachedKageUrl;

  try {
    const result = await Kakao.Share.scrapImage({ imageUrl });
    cachedKageUrl = result.infos.original.url;
    return cachedKageUrl;
  } catch (e) {
    console.warn('scrapImage failed:', e);
    return imageUrl; // fall back to original URL on failure
  }
}

async function shareToKakao() {
  const imageUrl = 'https://example.com/my-image.png';
  const thumbUrl = await getKageImageUrl(imageUrl);

  Kakao.Share.sendDefault({
    objectType: 'feed',
    content: {
      title: 'Share Title',
      description: 'Share description',
      imageUrl: thumbUrl,
      link: {
        webUrl: 'https://example.com',
        mobileWebUrl: 'https://example.com',
      },
    },
    buttons: [
      {
        title: 'Learn More',
        link: {
          webUrl: 'https://example.com',
          mobileWebUrl: 'https://example.com',
        },
      },
    ],
  });
}

scrapImage vs uploadImage: What's the Difference?

The Kakao SDK provides two functions for uploading images to KAGE — it's easy to mix them up.

APIInputUse Case
Kakao.Share.scrapImage({ imageUrl })URL stringUpload a server-hosted image to KAGE by URL
Kakao.Share.uploadImage({ file })File object arrayUpload a local file selected via <input type="file">
// ✅ Upload by URL
await Kakao.Share.scrapImage({ imageUrl: 'https://example.com/image.png' });

// ✅ Upload a file picked from a file input
const files = document.getElementById('file-input').files;
await Kakao.Share.uploadImage({ file: files });

// ❌ Passing a URL string to uploadImage will fail
await Kakao.Share.uploadImage({ file: ['https://example.com/image.png'] }); // won't work

Rule of thumb: use scrapImage for URLs, uploadImage for local files.

Kakao Share Opens the App Download Page on Desktop

Kakao.Share.sendDefault() relies on the KakaoTalk app being installed.

  • Mobile (KakaoTalk installed) → Opens KakaoTalk and shares directly
  • Desktop (KakaoTalk not installed) → Redirects to the KakaoTalk download page ← bad UX

Handle this gracefully by detecting the device type:

function isMobileDevice() {
  return /Android|iPhone|iPad|iPod|webOS|BlackBerry|IEMobile|Opera Mini/i.test(
    navigator.userAgent
  );
}

async function handleKakaoShare(shareUrl) {
  if (!isMobileDevice()) {
    // Desktop: copy URL to clipboard and notify the user
    await navigator.clipboard.writeText(shareUrl);
    alert('Link copied! Paste it into KakaoTalk.');
    return;
  }

  // Mobile: share via Kakao SDK
  const thumbUrl = await getKageImageUrl('https://example.com/my-image.png');
  Kakao.Share.sendDefault({
    objectType: 'feed',
    content: {
      title: 'Share Title',
      description: 'Share description',
      imageUrl: thumbUrl,
      link: { webUrl: shareUrl, mobileWebUrl: shareUrl },
    },
  });
}

Thumbnail Troubleshooting Checklist

If the thumbnail still isn't showing, go through this checklist in order:

#CheckDetails
1Using scrapImage?External URLs can't be used directly. Always convert with scrapImage → KAGE URL
2Image URL uses HTTPS?HTTP is not supported
3Image publicly accessible?Run curl -I <imageUrl> and confirm you get a 200 OK
4Standard port (80/443)?Kakao's scraper cannot reach non-standard ports like 8000 or 3000
5File size under 5 MB?Larger files will fail to upload
6Domain registered in Kakao Console?Go to App Settings → Platform → Web and add your site's domain
7Testing on localhost?Kakao's server can't reach localhost. Use a production image URL or a tunnel like ngrok

[Photo suggestion: Screenshot of the Kakao Developers Console (developers.kakao.com) showing the Web platform domain registration section under App Settings]

Quick Diagnostic Script (Browser Console)

Paste this script in your browser's DevTools console to pinpoint the failure at each stage — image fetch, SDK init, and scrapImage.

(async () => {
  const IMAGE_URL = 'https://example.com/my-image.png'; // ← your image URL
  const KAKAO_KEY = 'your-kakao-js-key'; // ← your app key

  // Step 1: Image accessibility check
  console.log('1. Image accessibility check');
  try {
    const res = await fetch(IMAGE_URL, { method: 'HEAD' });
    console.log('   Status:', res.status, '| Content-Type:', res.headers.get('content-type'));
  } catch (e) {
    console.error('   Image fetch failed:', e.message);
  }

  // Step 2: SDK initialization
  if (!window.Kakao?.isInitialized()) {
    if (!window.Kakao) {
      await new Promise(r => {
        const s = document.createElement('script');
        s.src = 'https://t1.kakaocdn.net/kakao_js_sdk/2.7.4/kakao.min.js';
        s.onload = r;
        document.head.appendChild(s);
      });
    }
    window.Kakao.init(KAKAO_KEY);
  }
  console.log('2. SDK initialized:', Kakao.isInitialized());

  // Step 3: scrapImage test
  console.log('3. scrapImage test');
  try {
    const result = await Kakao.Share.scrapImage({ imageUrl: IMAGE_URL });
    console.log('   KAGE URL:', result.infos.original.url);
  } catch (e) {
    console.error('   scrapImage failed:', e);
  }
})();

If scrapImage fails, check the error message — it usually points directly to the root cause (domain not registered, image inaccessible, file too large, etc.).

Notes on KAGE Image Expiry

  • KAGE-hosted images are automatically deleted after up to 100 days
  • Calling scrapImage again with the same URL issues a new KAGE URL
  • Cache the KAGE URL in a variable (like cachedKageUrl) to avoid re-uploading on every share

Frequently Asked Questions

Q: I'm using scrapImage but the thumbnail still doesn't show. What should I check?

A: Work through checklist items 2–7 above. Verify that the image is served over HTTPS, uses a standard port (80 or 443), and that your domain is registered in the Kakao Developer Console. Run the diagnostic script in the browser console to identify exactly which step fails.

Q: Can I test Kakao Share thumbnails on localhost?

A: No. Kakao's servers cannot reach localhost, so scrapImage will fail. During development, point imageUrl to an image on a real server (production or staging), or use a tunneling tool like ngrok to expose your local server to the internet.

Q: How do I prevent the Kakao share button from opening the app download page on desktop?

A: Use isMobileDevice() or a similar check to branch between mobile and desktop. On desktop, fall back to copying the URL to the clipboard, as shown in the code example above.

Q: When should I use uploadImage vs scrapImage?

A: Use scrapImage({ imageUrl }) when your image is already hosted on a public server and you have its URL. Use uploadImage({ file }) when the user has selected a local file via a file input element and you want to upload it to KAGE directly.

Conclusion

The most common cause of a missing Kakao Share thumbnail is passing an external image URL directly to imageUrl. The fix is straightforward: call Kakao.Share.scrapImage() first to upload the image to Kakao's KAGE CDN, then pass the returned URL to sendDefault(). Combine this with the checklist and the diagnostic script, and you'll resolve thumbnail issues in minutes.

For the full API reference, see the Kakao JavaScript SDK — KakaoTalk Share documentation.

Found this useful? Share it

Latest posts

Related projects

Get new posts by email

Insights on marketing, analytics, and dev, delivered to your inbox.