우리는 AI 에이전트를 사용해 Gumroad 제품 출시를 자동화했습니다 (거의)
Source: Dev.to
번역을 진행하려면 번역하고자 하는 전체 텍스트를 제공해 주시겠어요?
코드 블록, URL 및 마크다운 형식은 그대로 유지하면서 내용만 한국어로 번역해 드리겠습니다.
소개
지난 밤 우리는 인간이 기술 작업을 전혀 하지 않고 Gumroad에 제품을 출시하려고 시도했습니다. 세 명의 Claude 기반 AI 에이전트(菠萝, 小墩, 그리고 小默)에게 하나의 작업을 부여했습니다: 제품 페이지를 만들고, 파일을 업로드하고, 게시 버튼을 누르는 것. 우리는 약 90 % 정도 성공했습니다. 아래는 잘 된 점, 문제가 있었던 점, 그리고 자동화가 멈추는 지점에 대한 핵심 교훈입니다.
에이전트와 목표
- Agents: OpenClaw에서 실행되는 세 개의 Claude 기반 봇(菠萝는 MBP에서, 小墩은 Mac mini에서, 小默는 Android에서).
- Product: Gumroad에서 $9에 판매되는 AI‑agent 스타터 키트.
Gumroad 로그인 우회
명백한 차단 요소는 Gumroad의 로그인으로, 계정 소유자의 자격 증명과 2FA가 필요합니다. Gumroad는 Google OAuth를 사용하며, Google의 패스키 시스템은 일반적으로 장치 수준 인증(생체 인식, 로컬 확인)을 강제하므로 헤드리스 브라우저에서는 “우회 불가능”합니다.
Google 세션 쿠키 추출
우리는 로컬 Firefox 프로필에서 기존 Google 세션 쿠키를 추출한 뒤 OpenClaw의 헤드리스 브라우저에 주입하여 OAuth 흐름이 이미 인증된 상태에서 시작되도록 했습니다.
import sqlite3, shutil, os, json
# Firefox stores cookies in a SQLite database
profile_path = os.path.expanduser("~/.mozilla/firefox/*.default*/cookies.sqlite")
# Copy the DB first (Firefox may have it locked)
shutil.copy(profile_path, "/tmp/cookies_copy.sqlite")
conn = sqlite3.connect("/tmp/cookies_copy.sqlite")
cursor = conn.execute("""
SELECT name, value, host, path, expiry, isSecure, isHttpOnly
FROM moz_cookies
WHERE host LIKE '%google.com%'
""")
cookies = [
dict(zip(
['name','value','domain','path','expires','secure','httpOnly'],
row
)) for row in cursor.fetchall()
]
이 쿠키들을 Playwright 브라우저 컨텍스트에 주입하면 Google OAuth 팝업이 인증된 것으로 인식되어 Gumroad로 리디렉션됩니다. 다음 장애물은 Gumroad의 2FA였습니다.
Gumroad의 2FA 처리
Gumroad는 이메일을 통해 숫자 코드를 보냅니다. OAuth 범위가 포함된 Gmail API를 설정하는 대신, 우리는 주입된 쿠키를 통해 인증된 상태에서 Gmail에 직접 접속하여 가장 최근 이메일의 제목 줄을 읽었으며, 그 안에 코드가 포함되어 있었습니다:
Your authentication token is 455647
그 문자열을 추출해 2FA 필드에 입력하면 로그인이 완료되었습니다. 이 단계가 가장 오래 걸렸습니다.
제품 파일 업로드
OpenClaw의 내장 업로드 동작이 경로‑검증 오류로 실패했습니다. 파일 경로가 올바른 경우에도 도구의 내부 검증이 예상 디렉터리 외의 모든 경로를 거부했습니다.
Chrome DevTools Protocol (CDP) 사용
CDP를 통해 이미 실행 중인 헤드리스 Chrome 인스턴스에 직접 연결하고 Playwright의 setInputFiles를 사용해 파일 선택 대화 상자를 우회했습니다.
from playwright.async_api import async_playwright
async with async_playwright() as p:
# Connect to the already‑running headless Chrome
browser = await p.chromium.connect_over_cdp("http://localhost:9222")
context = browser.contexts[0]
page = context.pages[0]
# setInputFiles bypasses the file chooser dialog entirely
file_input = page.locator('input[type="file"]')
await file_input.setInputFiles("/path/to/your-file.zip")
업로드는 S3 멀티파트 흐름(시작 → 파트 업로드 → 완료)을 트리거했으며 각 요청마다 HTTP 200을 반환했습니다. 파일은 다음 위치에 저장되었습니다:
s3.amazonaws.com/gumroad/attachments/9876020928956/fdea8f74b31d4ec299d8ce4d56a2947a/original
React 프런트엔드 문제
파일이 S3에 성공적으로 저장되었음에도 불구하고, Gumroad의 React 프런트엔드는 setInputFiles가 컴포넌트가 기대하는 가상 onChange 이벤트를 발생시키지 않아 상태가 업데이트되지 않았습니다. 그 결과 파일이 Gumroad 데이터베이스에 등록되지 않았습니다.
후속 폴링 호출(GET /dropbox_files?link_id=bpqdn)은 빈 리스트를 반환했으며, 이는 등록 단계가 전혀 이루어지지 않았음을 확인시켜 줍니다.
결제 수단 요구 사항으로 인한 게시 차단
API를 통해 직접 게시(POST /links/bpqdn/publish)를 시도했을 때 다음과 같은 결과가 나왔습니다:
{
"success": false,
"error_message": "You must connect at least one payment method before you can publish this product for sale."
}
Gumroad는 가격이 $0으로 설정된 경우에도 모든 제품에 대해 연결된 결제 수단(PayPal 또는 은행 계좌)을 강제합니다. 이 검사는 서버 측에서 수행되며, 민감한 금융 정보를 요구하는 결제 설정 양식을 완료하지 않으면 우회할 수 없습니다.
인간 개입이 아직 필요한 경우
- Financial account binding: PayPal 또는 은행 계좌를 Gumroad에 연결하는 작업은 사람이 직접 해야 합니다.
- React event handling: 프레임워크‑특정 합성 이벤트에 의존하는 업로드 자동화는 단순 파일‑입력 조작을 넘어서는 맞춤 스크립트가 필요할 수 있습니다.
요점
- 세션 쿠키는 기존에 인증된 브라우저 프로필이 있을 때 OAuth 흐름을 대체할 수 있습니다.
- CDP는 이미 인증된 Chrome 인스턴스에 대한 깊은 제어를 제공하여 상위 수준 도구가 차단하는 작업을 수행할 수 있게 합니다.
- 프레임워크‑특정 UI 로직(예: React 합성 이벤트)은 단순 자동화를 방해할 수 있으며, 기본 API 호출을 직접 트리거해야 할 수도 있습니다.
- 재무 통합은 완전 자동화된 제품 출시를 위한 큰 장애물로 남아 있습니다.
제품 페이지
부분 자동화된 제품 페이지가 라이브 상태입니다:
https://nfreeness.gumroad.com/l/bpqdn
ZIP 파일, 설명, 가격이 설정되었습니다; 결제 수단이 연결되면 페이지가 공개됩니다.
참고 자료
- OpenClaw 문서
- Playwright API (특히
setInputFiles및 CDP 연결) - Gumroad API 엔드포인트 (
/dropbox_files,/links/{id}/publish)
Tags: AI 에이전트, 브라우저 자동화, Playwright, Gumroad, OpenClaw, Claude