상품 나열 글에도 검색 유입이 생길까
상품 나열 글에도 검색 유입이 생길까요

쿠팡 파트너스 블로그가 왜 이렇게 많은지 궁금했습니다.
검색을 하다 보면 비슷한 제목, 비슷한 상품 구성, 비슷한 문장으로 된 글을 자주 보게 됩니다. 처음에는 그냥 자동으로 찍어낸 글처럼 보였습니다. 그런데도 이런 글이 계속 생기는 것을 보면, 누군가는 그 안에서 어떤 가능성을 보고 있는 것 같았습니다.
솔직히 말씀드리면 돈이 될 것 같지는 않습니다.
저부터도 상품만 쭉 나열된 글을 보면 오래 읽지 않습니다. 제목은 그럴듯한데 들어가 보면 상품 이미지, 가격, 링크, 비슷한 설명이 반복되는 경우가 많습니다. 그런 글에서는 금방 뒤로 가기를 누르게 됩니다.
그래서 이번 실험의 목적은 수익보다 유입 확인에 가깝습니다.
자동으로 만든 쿠팡 파트너스 글이 실제로 검색에 잡히는지, 노출이 생기는지, 누군가 클릭해서 들어오는지 보고 싶었습니다. 실험용 블로그는 review-coo로 만들었습니다.
프로젝트 구성
이번 자동화는 TypeScript로 만들었습니다.
Node.js 기반의 배치 프로그램이고, 별도 서버를 띄우는 구조는 아닙니다. Express나 NestJS 같은 서버 프레임워크는 쓰지 않았습니다. 매일 정해진 시간에 한 번 실행되고, 필요한 작업을 끝낸 뒤 종료되는 방식입니다.
사용한 주요 기술은 다음과 같습니다.
- TypeScript
- Node.js
- GitHub Actions
- 쿠팡 파트너스 API
- Google Gemini API
- Blogger API v3
- Google OAuth 2.0
- Zod
- Vitest
- Pino
- YAML
- JSON state storage
전체 흐름은 대략 다음과 같습니다.
- GitHub Actions 실행
- TypeScript 배치 실행
- Gemini가 오늘의 주제 후보 생성
- 쿠팡 파트너스 API로 후보 주제 검증
- 실제 상품 검색
- 상품 필터링 및 점수 계산
- Gemini로 글 생성
- TypeScript 코드로 글 검증
- HTML 렌더링
- Blogger API로 자동 등록
지금은 GitHub Actions에서 매일 오전 7시 50분에 실행되도록 설정해 두었습니다.
왜 GitHub Actions를 썼나

처음에는 로컬에서 수동으로 실행했습니다.
npm run draft나 npm run publish 같은 명령을 실행하면 글이 만들어지고 Blogger에 등록됩니다.
자동화 실험이라면 결국 사람이 매번 실행하지 않아야 합니다. 그래서 GitHub Actions를 붙였습니다.
GitHub Actions은 깃 무료 계정으로도 비공개 Repository로도 충분히 하루 1번정도의 블로그 포스팅은 감당이 될거라고 생각했습니다.
GitHub Actions는 정해진 시간에 자동으로 실행할 수 있고, API 키 같은 민감한 값은 Secrets에 넣어둘 수 있습니다.
로컬 .env 파일을 GitHub에 올리지 않아도 됩니다.
현재 워크플로는 이런 식으로 동작합니다.
- 매일 오전 7시 50분 실행
npm cinpm run typechecknpm testnpm run dev -- --mode=publish- 성공하면
data/state.json변경 사항 커밋
처음에는 여기서도 꽤 삽질을 하기도 했습니다.
NODE_ENV=production 상태에서 npm ci를 실행하니 devDependencies가 빠져서 vitest 타입을 못 찾는 문제가 있었습니다. 그래서 GitHub Actions에서는 테스트와 타입 검사를 위해 npm ci --include=dev로 수정했습니다.
또 GitHub의 Secrets and variables 화면에서 Secrets와 Variables가 나뉘어 있어서 값이 안 읽히는 문제도 있었습니다. 지금은 secrets.NAME과 vars.NAME 둘 다 읽을 수 있게 해두었습니다.
Gemini는 어디에 쓰나
Gemini는 두 군데에 사용합니다.
첫 번째는 주제 후보 생성입니다.
처음에는 config/topics.yaml에 적어둔 주제 목록 안에서만 글을 만들었습니다. 그런데 그렇게 하니 특정 주제, 특히 습도 관리 같은 글이 자주 반복되는 문제가 생겼습니다.
그래서 지금은 Gemini가 먼저 오늘 쓸 만한 세부 주제 후보를 만듭니다.
예를 들면 이런 식입니다.
- 현관 신발과 우산 정리
- 주방 싱크대 주변 정리
- 욕실 물때와 곰팡이 예방 정리
- 작은 공간 빨래 건조 정리
- 책상 조명과 눈부심 줄이기
다만 AI가 만든 주제를 바로 쓰지는 않습니다.
각 후보를 쿠팡 파트너스 API로 실제 검색해 보고, 상품이 충분히 나오고 필터를 통과하는 경우에만 채택합니다. AI가 이상한 주제를 만들거나 검색 결과가 부족하면 기존 topics.yaml 방식으로 fallback합니다.
두 번째는 글 생성입니다.
Gemini는 선택된 주제와 상품 팩트시트를 받아서 글을 만듭니다. 여기서 중요한 점은 Gemini에게 HTML을 직접 만들게 하지 않았다는 것입니다.
Gemini는 정해진 JSON 구조로만 응답합니다. 예를 들면 제목, 도입부, 선택 기준, 상품별 설명, 결론, 라벨 같은 항목을 JSON으로 받습니다.
이렇게 한 이유는 통제 때문입니다.
LLM이 HTML을 직접 만들게 하면 제휴 링크가 빠지거나, 상품 ID가 틀어지거나, 원하지 않는 태그가 들어갈 수 있습니다. 그래서 글 내용은 Gemini가 만들고, 실제 HTML 렌더링은 TypeScript 코드가 담당하게 했습니다.
쿠팡 파트너스 API 연결
상품 정보는 쿠팡 파트너스 API에서 가져옵니다.
처음에는 Mock 데이터로 전체 파이프라인을 만들었습니다. 이후 실제 쿠팡 파트너스 Access Key와 Secret Key를 넣고, 실제 API를 연결했습니다.
쿠팡 API는 HMAC 서명이 필요합니다. Node.js 기본 crypto 모듈로 서명을 만들었습니다.
대략 이런 흐름입니다.
- 요청 시간 생성
- HTTP method, path, query 조합
- secret key로 HMAC SHA256 생성
- Authorization 헤더에 CEA 서명 추가
- 쿠팡 API 호출
처음에는 Invalid signature 오류가 났습니다. 쿼리 문자열을 서명에 포함하는 방식이 맞지 않아서였습니다. 서명 문자열에서 ? 처리 방식을 고친 뒤 실제 응답을 받을 수 있었습니다.
쿠팡 API 응답에서 사용하는 값은 실제로 내려온 값만 씁니다.
- 상품 ID
- 상품명
- 상품 이미지
- 상품 가격
- 제휴 URL
- 카테고리
- 배송 관련 표시
- 검색 순위
리뷰 수, 별점, 판매량 같은 값은 API 응답에 없으면 만들지 않습니다.
링크도 확인했습니다. 일반 상품 URL이 아니라 쿠팡 파트너스 추적 링크였습니다.
link.coupang.com/re/AFFSDP?...lptag=...
lptag가 포함되어 있어서 제 쿠팡 파트너스 계정 기준으로 생성된 링크입니다.
상품 선정 로직
상품은 랜덤으로 고르지 않고 쿠팡 API에서 가져온 상품 후보를 필터링하고 점수를 계산했습니다.
필터링 기준은 대략 이렇습니다.
- 상품 ID가 있는가
- 상품명이 있는가
- 이미지가 있는가
- 제휴 URL이 있는가
- 가격 범위 안에 있는가
- 금지 키워드가 없는가
- 최근에 사용한 상품이 아닌가
- 주제와 관련성이 있는가
그다음 점수를 계산합니다.
- 검색 순위 점수
- 주제 관련성 점수
- 가격 적합성 점수
- 정보 완성도 점수
- 배송 정보 점수
- 상품 다양성 점수
- 최근 미사용 점수
- 상품명 과장 표현 패널티
- 유사 상품 패널티
최종적으로 2~4개 상품만 선택합니다.
이미 사용한 상품은 data/state.json에 기록하도록 했고, 같은 상품 ID나 같은 상품 조합이 반복되지 않도록 처리했습니다.
물론 완벽하지는 않습니다. 쿠팡에서 옵션만 다른 상품을 서로 다른 상품 ID로 내려주면 비슷한 상품이 다시 들어갈 수 있습니다. 그래도 완전히 같은 상품을 반복해서 올리는 문제는 줄일 수 있었습니다.
TypeScript로 한 번 더 검증한다
Gemini가 만든 글을 바로 올리지는 않았고 , TypeScript 코드로 한 번 더 검사했습니다.
예를 들면 이런 표현은 막았습니다.
- 직접 사용해 보니
- 제가 써봤는데
- 실제로 구매했습니다
- 무조건 추천
- 강력 추천
- 가성비 끝판왕
- 최고의 선택
실제로 사용하지 않은 상품을 사용한 것처럼 쓰면 안되기 때문에 이런 처리를 하였습니다.
반복 표현도 검사했습니다.
- 사용할 수 있습니다
- 확인할 수 있습니다
- 적합합니다
- 경우에는
- 또한
- 특히
- 따라서
이런 표현이 너무 많이 반복되면 이런 부분도 체크했습니다. 문장 종결이 계속 비슷하거나, 상품별 설명 구조가 지나치게 비슷해도 문제가 뭔가 너무 인위적일거 같다는 생각을 했습니다..
이 검사를 통과해야만 HTML로 렌더링하고 Blogger에 등록합니다.
Blogger API 등록
블로그는 Blogger를 사용했습니다.
주소는 아래입니다.
https://review-coo.blogspot.com/
Blogger를 고른 이유는 무료로 운영할 수 있고, Blogger API가 있어서 자동 등록을 붙이기 쉬워서였어요. 오히려 새로 만든 구글 블로그는 처음에 유입이 거의 없을 가능성이 높을 거라 생각했지만 그래도 실험용으로는 괜찮다고 봤습니다.
Google OAuth로 refresh token을 발급받고, 그 토큰으로 Blogger API를 호출하였습니다.
Blogger 등록도 처음에는 초안으로만 등록되게 했고 확인후 게시하는 흐름으로 했습니다.
PUBLISH_MODE=draftDRY_RUN=false
그러다 제가 일일이 접속할거 같지 않아 그냥 자동으로 발행하게 변경해서 적용했습니다.
PUBLISH_MODE=publishDRY_RUN=falseALLOW_AUTO_PUBLISH=true
공개 발행은 실수하면 바로 글이 올라가기 때문에 일부러 조건을 세 개로 나누긴 했지만 실제로는 자동 등록으로만 돌릴 것 같네요..
실제로 만들면서 생긴 문제들
생각보다 손이 많이 갔습니다.
처음에는 단순할 줄 알았습니다.
상품 가져오고, 글 만들고, 블로그에 올리면 끝일 줄 알았습니다. 그런데 실제로 연결하다 보니 자잘한 문제가 계속 나왔습니다.
예를 들면 이런 것들 이였습니다.
- Gemini JSON 스키마 불일치
- localhost 리다이렉트 문제
- 쿠팡 API HMAC 서명 오류
- GitHub Actions devDependencies 미설치
- 한글 인코딩 깨짐
- Mock 이미지가 실제 상품 이미지처럼 보이는 문제
- GitHub Actions에서 Secrets/Variables 읽기 차이
돈보다 먼저 볼 것
이걸로 바로 돈이 벌릴 거라고 기대하지는 않습니다.
오히려 저도 이런 상품 나열 글을 잘 안 읽는 편이라, 수익을 목표로 잡으면 시작부터 조금 어색합니다.
먼저 궁금한 건 유입입니다.
당분간은 다음을 볼 생각입니다.
- 글이 정상적으로 쌓이는지
- 구글에 색인되는지
- 검색 노출이 생기는지
- 어떤 주제가 클릭되는지
- 상품 링크까지 누르는 사람이 있는지
- 커미션이 실제로 발생하는지
커미션은 가장 마지막 지표에 가깝습니다.
검색 유입이 없다면 링크 클릭도 없고, 링크 클릭이 없다면 수익도 없습니다. 그래서 우선은 자동화된 글이 검색에 잡히는지부터 확인하려고 합니다.
지금 기준의 한계
아직 한계도 많습니다.
AI가 주제를 만든다고 해도, 결국 쿠팡 상품 검색에 잘 걸리는 주제 중심으로 갈 수밖에 없습니다. 그러다 보면 다시 비슷한 생활용품 글이 반복될 가능성이 있습니다.
또 글이 너무 무난해질 위험도 있습니다.
API에서 확인된 정보만 쓰도록 했기 때문에 허위 정보는 줄일 수 있지만, 반대로 글이 밋밋해질 수도 있습니다. 실제 사용 경험이 없으니 후기 같은 느낌으로 글이 써져도 안된다고 생각했습니다.
이건 자동화 상품 글의 근본적인 한계에 가깝습니다.
그래서 이 프로젝트는 좋은 글을 자동으로 만든다기보다는, 검색 유입 실험을 꾸준히 돌려보자는 느낌으로 만들어봤습니다.
결론
이 프로젝트는 자동화로 돈 벌기 같은 성공담이 아닙니다.
정확히는 쿠팡 파트너스 글이 왜 이렇게 많이 만들어지는지 궁금해서 직접 만들어본 실험입니다. 저도 상품 나열 글을 보면 뒤로 가기를 누르는 편이라, 이런 방식이 실제로 유입을 만들 수 있을지는 잘 모르겠습니다.
그래도 직접 돌려보면 알 수 있습니다.
글이 색인되는지. 검색 노출이 생기는지. 클릭이 발생하는지. 그리고 정말 아주 조금이라도 커미션이 생기는지.
안 되면 그것도 결과입니다.
자동으로 글을 올리는 것만으로는 아무 의미가 없다는 걸 확인한 셈이니까요.