Kakao Maps API 통합 가이드

사이트 등록(/sites/new) 위저드의 "지도에서 선택" 모드, 사이트 상세 페이지의 폴리곤 표시에 Kakao Maps JavaScript SDK + Drawing 라이브러리 + Local Search API를 사용합니다.

2025-12-03 콘솔 개편 반영 — 이전 버전의 앱 설정 → 플랫폼 → Web 메뉴는 폐기. 현재는 앱 → 플랫폼 키 → JavaScript 키 → JavaScript SDK 도메인에서 등록합니다. 개편 안내 docs
출처: 앱·앱키 개편 안내 (2025-12-03) · JavaScript SDK 시작 · Maps Web 가이드 · 사용 한도
K

Kakao Developers 앱 등록

앱 1개를 등록한 뒤 JavaScript 키와 REST API 키를 발급받습니다. Web 플랫폼에 도메인 등록은 필수 — 미등록 도메인 호출 시 401.

완료 시 받을 것 — JavaScript 키(브라우저 SDK용) + REST API 키(서버 사이드 geocoding용). 두 값을 .env.dev/.env.prod에 저장.
1
개발자 등록 + 앱 생성
developers.kakao.com 로그인 → 우측 상단 내 애플리케이션 → 애플리케이션 추가하기:
  • 앱 이름: nurimap
  • 사업자명: 회사명 또는 개인 (비즈 인증은 추후 운영 진입 시)
  • 카테고리: 적절히 선택 (예: 환경 / 기업서비스)
2
플랫폼 키 확인 (4가지 키)
생성된 앱 진입 → 좌측 앱 → 플랫폼 키 페이지에서 4가지 키 확인:
  • 네이티브 앱 키 — 모바일 SDK용 (사용 안 함)
  • REST API 키 — 서버 사이드 주소 검색 등 (Spring Boot에서 사용)
  • JavaScript 키 — 브라우저 Maps SDK 로드용 (envi2/app에서 사용)
  • Admin 키 — 절대 클라이언트 노출 금지 (서버 관리자용)
JavaScript 키와 REST API 키 두 값을 복사.
3
JavaScript SDK 도메인 등록 — 필수
앱 → 플랫폼 키 → JavaScript 키 → JavaScript SDK 도메인 항목에서 [도메인 등록] → [+] 추가 → 도메인 입력 → [저장]. Maps SDK는 envi2/app(앱 도메인)에서만 사용하므로 3개만 등록:
  • https://app.nurimap.com — 운영 앱
  • https://dev-app.nurimap.com — 개발 앱 (Cloudflare Tunnel)
  • http://localhost:3001 — 로컬 dev (envi2/app)
마케팅 도메인(nurimap.com, dev.nurimap.com)은 Maps SDK 안 씀 → 등록 불필요.
미등록 도메인에서 호출 시 401 응답.
4
참고 — 메뉴 비슷한 다른 항목
콘솔에는 비슷해 보이는 항목이 있는데 Maps SDK엔 무관:
  • 제품 링크 관리 → 웹 도메인: 카카오톡 공유, 카카오 로그인 등 다른 제품용
  • 플랫폼 키 → JavaScript 키 → 리다이렉트 URI: 카카오 로그인(OAuth) 콜백용
  • 플랫폼 키 → REST API 키 → 리다이렉트 URI: REST OAuth 콜백용
Maps SDK는 "JavaScript SDK 도메인" 항목만 등록하면 충분.
JavaScript 키는 브라우저에 노출됩니다 — 도메인 화이트리스트가 유일한 방어선. Admin 키는 절대 클라이언트 코드에 두지 마세요.
M

SDK 로드 + Next.js 통합

SDK는 dapi.kakao.com/v2/maps/sdk.js에서 직접 로드. Drawing 사용 시 libraries=drawing 쿼리 추가.

1
기본 SDK URL
<script src="//dapi.kakao.com/v2/maps/sdk.js?appkey=YOUR_JS_KEY"></script>
// (protocol-relative)는 http/https 자동 매핑.
2
Drawing 라이브러리 포함
<script src="//dapi.kakao.com/v2/maps/sdk.js?appkey=YOUR_JS_KEY&libraries=drawing"></script>
폴리곤·마커·원 그리기 도구 사용 시 필수.
3
Next.js (App Router) — Script 컴포넌트
SSR/CSR 안전한 lazy load — autoload=false + kakao.maps.load(callback):
// app/components/KakaoMapScript.tsx
"use client";
import Script from "next/script";

export function KakaoMapScript() {
  const key = process.env.NEXT_PUBLIC_KAKAO_JS_KEY!;
  return (
    <Script
      src={`//dapi.kakao.com/v2/maps/sdk.js?appkey=${key}&libraries=drawing&autoload=false`}
      strategy="afterInteractive"
      onLoad={() => {
        window.kakao.maps.load(() => {
          // 모든 maps API 초기화는 이 콜백 안에서
        });
      }}
    />
  );
}
4
지도 초기화 + WGS84 좌표
const container = document.getElementById("map");
const options = {
  center: new kakao.maps.LatLng(36.5, 127.5),  // 한국 중앙
  level: 13,                                    // 줌 (낮을수록 확대)
};
const map = new kakao.maps.Map(container, options);
Kakao Maps의 LatLng(lat, lon)WGS84 EPSG:4326. PostGIS geometry(Polygon, 4326)과 좌표계 정확히 일치 — 변환 불필요.
D

Drawing Manager — 사이트 AOI 정의

사용자가 폴리곤·마커·원으로 영역을 그리고, 좌표를 GeoJSON으로 추출해 POST /api/sites로 전송합니다.

1
DrawingManager 생성
const manager = new kakao.maps.drawing.DrawingManager({
  map,
  drawingMode: [
    kakao.maps.drawing.DrawingMode.MARKER,
    kakao.maps.drawing.DrawingMode.POLYGON,
    kakao.maps.drawing.DrawingMode.CIRCLE,
  ],
  polygonOptions: {
    draggable: true, removable: true, editable: true,
    strokeColor: "#10B981",
    fillColor: "#10B981",
    fillOpacity: 0.2,
  },
});
2
그리기 모드 시작 + 완료 이벤트
// 폴리곤 모드로 진입
manager.select(kakao.maps.drawing.OverlayType.POLYGON);

// 그리기 완료 시 좌표 추출
kakao.maps.event.addListener(manager, "drawend", () => {
  const data = manager.getData();
  // data.polygon : [{ points: [{x, y}, ...] }, ...]
  if (data.polygon.length > 0) {
    const coords = data.polygon[0].points.map(p => [p.x, p.y]);
    coords.push(coords[0]);  // closed ring
    const geojson = { type: "Polygon", coordinates: [coords] };
  }
});
좌표 순서 주의 — Kakao의 x=경도, y=위도. GeoJSON 표준 [lon, lat]과 동일.
3
기존 폴리곤 표시 (사이트 상세)
// GET /api/sites/{id}의 geom (GeoJSON Polygon)
const polygon = new kakao.maps.Polygon({
  path: geom.coordinates[0].map(([lon, lat]) =>
    new kakao.maps.LatLng(lat, lon)
  ),
  strokeColor: "#047857",
  fillColor: "#10B981",
  fillOpacity: 0.25,
});
polygon.setMap(map);

// 폴리곤 중심으로 카메라 fit
const bounds = new kakao.maps.LatLngBounds();
polygon.getPath().forEach(p => bounds.extend(p));
map.setBounds(bounds);
4
좌표 입력 모드 — 원형 AOI
mockup 35의 "좌표 입력" 모드: lat/lon + radius 슬라이더 → Kakao Circle:
const circle = new kakao.maps.Circle({
  center: new kakao.maps.LatLng(36.031, 129.389),
  radius: 1000,  // meters
  strokeColor: "#10B981",
  fillColor: "#10B981",
  fillOpacity: 0.2,
});
circle.setMap(map);
Q

무료 사용 한도

2026-05 기준. 비즈 앱과 일반 앱 동일.

API일일 한도설명
Map SDK (JS / iOS / Android)300,000지도 표시 + Drawing + 마커 (브라우저 SDK 모든 호출)
Local API (주소·키워드 검색)100,000REST API로 좌표↔주소 변환, 장소 검색
Daum 검색 API50,000웹 검색 (현재 미사용)
KakaoTalk 메시지·프로필30,000(현재 미사용)
월간 통합 한도3,000,000 건 (앱 단위 합산) 초과 시 응답HTTP 401 / 403 + 카운터 다음 일 0시 KST 리셋 정책 페이지developers.kakao.com/.../quota
예상 사용량 — 사이트 등록 시 1~2회 Map SDK 호출. 일 1만 명 가입 시에도 2만 호출 → 한도 1.5% 사용.
R

REST API vs JavaScript SDK

두 가지 키를 모두 발급받고 용도별로 사용. 주소 검색은 서버 사이드(REST) 권장 — CORS 회피 + 키 노출 차단.

구분JavaScript SDKREST API
호출 위치브라우저서버
인증 키JavaScript 키REST API 키 (Authorization: KakaoAK ...)
주 용도지도 + Drawing + 마커 + 폴리곤주소→좌표, 좌표→주소, 키워드 장소 검색
도메인 제약Web 플랫폼에 등록된 도메인만없음 (서버 IP 기반)
한도300,000건/일 (Map SDK)100,000건/일 (Local API)
nurimap에서SiteMapPicker, 사이트 상세 미니맵GET /api/geocode/search?q=...
주소 검색 백엔드 예시:
// Spring Boot — KakaoLocalClient
String url = "https://dapi.kakao.com/v2/local/search/address.json?query="
  + URLEncoder.encode(q, StandardCharsets.UTF_8);
HttpRequest req = HttpRequest.newBuilder(URI.create(url))
  .header("Authorization", "KakaoAK " + restApiKey)
  .build();
// 응답: { "documents": [ { "address_name", "x"(lon), "y"(lat) }, ... ] }
i

envi2 통합 체크리스트

사용자가 발급 (Kakao Developers Console)

  • developers.kakao.com에서 이미 만든 nurimap 앱 진입 (OAuth용)
  • 플랫폼 키 → JavaScript 키 페이지에서 키 값 복사 (없으면 [JavaScript 키 생성])
  • 같은 페이지에서 JavaScript SDK 도메인에 3개 추가 (app.nurimap.com, dev-app.nurimap.com, localhost:3001)
  • REST API 키는 이미 발급되어 있음 (.env.dev의 KAKAO_REST_API_KEY)

envi2 환경변수

# Kakao Maps — JS 키, 클라이언트에서만 사용 (NEXT_PUBLIC_ prefix 필수) NEXT_PUBLIC_KAKAO_JS_KEY=your_javascript_key # REST API 키는 이미 카카오 OAuth용으로 .env.dev에 있음 (KAKAO_REST_API_KEY) # Maps Local Search도 같은 키 재사용 — 별도 발급/추가 불필요

envi2/app — 새로 만들 파일

  • src/app/components/KakaoMapScript.tsx — next/script로 SDK 로드
  • src/app/components/SiteMapPicker.tsx — Drawing Manager 래퍼
  • src/app/components/SitePolygonView.tsx — 읽기 전용 폴리곤 표시
  • (app)/sites/new/page.tsx 위저드 Step 3에서 <SiteMapPicker /> 사용
  • (app)/sites/[id]/page.tsx 미니맵을 Kakao 폴리곤 view로 교체

envi2/api — 새로 만들 엔드포인트

  • GET /api/geocode/search?q={주소} — Spring Boot가 Kakao Local Search 호출
  • Authorization 헤더 KakaoAK {REST_API_KEY} 설정
  • 응답: [{ addressName, lat, lon }, ...]

layout.tsx — SDK 스크립트 한 번만 로드

// envi2/app/src/app/(app)/layout.tsx
import { KakaoMapScript } from "@/components/KakaoMapScript";

export default async function AppLayout({ children }) {
  // ... auth gate ...
  return (
    <>
      <KakaoMapScript />
      <div className="app">{/* ... */}</div>
    </>
  );
}
T

트러블슈팅

증상원인 / 해결
Kakao is not definedSDK 로드 전 호출 — 모든 maps 초기화는 kakao.maps.load(cb) 안에서.
401 / 403 응답JavaScript SDK 도메인에 현재 도메인 미등록 — 앱 → 플랫폼 키 → JavaScript 키 → JavaScript SDK 도메인에서 추가.
지도가 회색만 표시컨테이너 <div> 너비/높이 0. CSS로 명시적 height: 360px 등 지정.
kakao.maps.drawing undefinedSDK URL에 libraries=drawing 누락.
HTTP localhost 동작 안 함http://localhost:3001을 JavaScript SDK 도메인에 별도 등록 (https와 다른 항목).
좌표가 거꾸로 (한국 → 일본)LatLng(lat, lon) 순서 확인. Kakao x=lon, y=lat.
Local API CORS 차단브라우저에서 직접 호출 금지 — Spring Boot 경유.