네이버 검색광고 API hintKeywords 11001 — 원인은 키워드 안의 공백 하나였다

·

블로그 글감을 고르기 전에 네이버 검색광고 API의 키워드도구(/keywordstool)로 월간 검색수와 경쟁 정도를 확인한다. 실제 검색어 형태 그대로 넣었다가 400을 맞았고, 에러 메시지가 원인을 전혀 알려주지 않아 격리 테스트로 좁혀야 했다.

증상 — 400 code 11001

$ node scripts/naver-keyword.mjs "주거급여 신청"
키워드도구 조회 실패 (400): {"code":11001,"message":"hintKeywords 파라미터가 유효하지 않습니다.","status":"BAD_REQUEST"}

메시지는 “유효하지 않습니다”뿐이다. 어떤 키워드의 무엇이 문제인지 지목하지 않는다. 인증은 정상이었다 — 서명이 틀렸다면 401이 났을 것이고, 같은 자격증명으로 직전 요청이 성공한 상태였다.

가설 1 — 키워드 개수 제한 (탈락)

여러 키워드를 한 번에 넣던 중이었으니 개수를 먼저 의심했다. 공백 없는 키워드로 늘려 가며 확인했다.

$ node scripts/naver-keyword.mjs 주거급여 월세
총 1200개 연관키워드 (요청 키워드: 주거급여, 월세)

$ node scripts/naver-keyword.mjs 주거급여 월세 전세 매매 청약
총 1200개 연관키워드 (요청 키워드: 주거급여, 월세, 전세, 매매, 청약)

$ node scripts/naver-keyword.mjs 주거급여 월세 전세 매매 청약 대출
총 0개 연관키워드 (요청 키워드: 주거급여, 월세, 전세, 매매, 청약, 대출)

6개도 400이 아니다. 마지막 요청은 200에 목록만 비었을 뿐이고, 이건 뒤에서 따로 다룬다. 개수 가설은 탈락이다.

가설 2 — 중복 키워드 (탈락)

같은 키워드가 두 번 들어간 요청도 통과했다.

$ node scripts/naver-keyword.mjs 주거급여 주거급여 신청 월세 전세
총 1200개 연관키워드 (요청 키워드: 주거급여, 주거급여, 신청, 월세, 전세)

여기서 힌트가 하나 나온다. 실패했던 요청에는 주거급여신청이 들어 있었는데, 둘을 따로 넣으니 통과한다. 남은 차이는 하나뿐이다.

원인 — 키워드 안의 공백

같은 두 단어를 한 인자로 묶느냐 나누느냐만 바꿔 비교했다.

$ node scripts/naver-keyword.mjs "주거급여 신청"
키워드도구 조회 실패 (400): {"code":11001, …}

$ node scripts/naver-keyword.mjs 주거급여 신청
총 58개 연관키워드 (요청 키워드: 주거급여, 신청)

$ node scripts/naver-keyword.mjs 주거급여신청
총 1개 연관키워드 (요청 키워드: 주거급여신청)

세 요청의 차이는 공백 하나다. hintKeywords의 각 항목에 공백이 들어가면 400이 난다. 공백을 지우거나 별도 항목으로 나누면 통과한다.

동작 자체는 이해할 수 있다. hintKeywords는 키워드를 쉼표로 구분해 넘기는 파라미터이고, 서버는 항목 하나를 공백 없는 단일 토큰으로 기대한다. 문제는 이 제약이 문서보다 에러 메시지에서 먼저 마주친다는 점, 그리고 메시지가 그 사실을 말해 주지 않는다는 점이다.

왜 이게 한국어에서 특히 아픈가

영어 SEO 도구를 쓰던 감각으로는 이 제약이 사소해 보인다. 하지만 한국어 검색어는 대부분 공백을 포함한다.

  • 주거급여 신청 방법
  • 청년월세지원 지급일
  • 기준임대료 2026

실제 사용자가 치는 형태 그대로 조회하려는 순간 400이 난다. 그리고 여기서 흔한 실수가 나온다 — 공백만 지우고 그 수치를 원래 검색어의 수치로 읽는 것이다.

$ node scripts/naver-keyword.mjs 주거급여신청
총 1개 연관키워드 (요청 키워드: 주거급여신청)

연관키워드가 1개라는 건 이 붙여 쓴 형태가 사실상 독립 키워드로 거의 안 쓰인다는 뜻이다. 붙여 쓴 값과 띄어 쓴 값은 다른 키워드로 집계된다. 공백을 지운 결과를 원래 질의의 검색량으로 보고하면 그건 측정이 아니라 추정이다.

실무적으로는 이렇게 처리한다.

  1. 공백으로 잘라 각 단어를 별도 시드로 넣는다.
  2. 응답의 relKeyword 목록에서 원하는 조합을 찾아서 그 행의 수치를 읽는다.

키워드도구는 시드에 대한 연관키워드를 최대 1,200개까지 돌려주므로, 공백이 든 조합은 대개 그 목록 안에 이미 들어 있다.

const rows = await keywordTool(["주거급여", "신청"]);
const hit = rows.find((r) => r.relKeyword === "주거급여신청");

200인데 목록이 빈 경우

앞에서 미룬 케이스다. 시드가 6개일 때 결과가 0건이었다.

$ node scripts/naver-keyword.mjs 주거급여 월세 전세 매매 청약 대출
총 0개 연관키워드

이건 400과 성격이 다르다. 요청은 유효하고 응답도 200이며, 확장할 연관키워드가 없다는 뜻이다. 시드가 좁을수록 자주 생긴다 — 단일 시드 실측으로도 클로드코드는 1개(자기 자신)만, AI는 1,200개가 돌아온다.

두 실패를 구분해서 처리해야 한다.

응답대응
400 / 11001키워드에 공백 등 형식 위반공백 제거 또는 항목 분리
200 / 빈 목록시드가 좁아 확장 불가더 넓은 시드로 재조회
429호출 한도간격을 두고 재시도

정리

  • hintKeywords의 각 항목에 공백이 들어가면 400 / code 11001이다.
  • 개수(6개까지 확인)와 중복은 원인이 아니다.
  • 에러 메시지는 원인을 지목하지 않는다 — 키워드를 하나씩 빼는 격리 테스트가 유일한 경로다.
  • 공백을 지운 키워드는 다른 키워드다. 그 수치를 원래 검색어의 수치로 인용하면 안 된다.
  • 실전 해법은 단어를 나눠 시드로 넣고 연관키워드 목록에서 조합을 찾아 읽는 것이다.

자주 묻는 질문

공백을 지우고 조회하면 결과가 같나요?

같지 않습니다. '주거급여신청'과 '주거급여'는 서로 다른 키워드로 집계되고 월간 검색수도 다릅니다. 실제 사용자가 치는 형태는 공백이 든 쪽인 경우가 많으므로, 공백을 지운 값의 수치를 원래 검색어의 수치로 읽으면 안 됩니다. 공백으로 나눠 별도 키워드로 넣고 응답의 연관키워드 목록에서 원하는 조합을 찾는 편이 안전합니다.

키워드 개수 제한이 원인 아닌가요?

아닙니다. 공백 없는 키워드로 2개, 5개, 6개를 각각 넣어 모두 정상 응답을 받았습니다. 중복 키워드가 섞인 5개 요청도 통과했습니다. 개수와 중복은 11001의 원인이 아닙니다.

에러 메시지만 보고 원인을 알 수 있나요?

없습니다. 응답은 {"code":11001,"message":"hintKeywords 파라미터가 유효하지 않습니다.","status":"BAD_REQUEST"}뿐이고 어떤 키워드의 무엇이 문제인지 지목하지 않습니다. 키워드를 하나씩 빼면서 최소 재현 요청을 만드는 방식으로만 좁혀집니다.

연관키워드가 0개로 오는 경우도 실패인가요?

다른 상황입니다. HTTP 200에 목록만 빈 경우로, 시드가 지나치게 좁아 확장할 연관키워드가 없다는 뜻입니다. 400과 달리 요청 자체는 유효하므로 시드를 더 넓은 단어로 바꿔 다시 조회하면 됩니다.

#네이버#OpenAPI#SEO#자동화#에러