ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • fetch로는 로그인·동적 페이지를 못 읽는다 — OpenClaw가 격리 브라우저로 푼 방법
    IT 2026. 7. 14. 23:00
    fetch로는 로그인·동적 페이지를 못 읽는다 — OpenClaw가 격리 브라우저로 푼 방법

    오픈소스 개인 AI 어시스턴트 OpenClaw를 집 서버에 올려 쓰면서, 에이전트가 "웹을 본다"는 게 생각보다 까다로운 문제라는 걸 알게 됐다. 단순히 URL을 받아 HTML을 내려받는 fetch(HTTP 요청 한 번으로 페이지 원문을 가져오는 방식)로는 로그인이 필요한 화면도, JavaScript로 그려지는 화면도 거의 읽지 못한다. OpenClaw는 이 문제를 에이전트 전용으로 격리된 진짜 Chrome 프로필을 제어하는 방식으로 푼다. 이 글은 왜 fetch로는 부족한지, 왜 하필 "격리된 별도 프로필"인지, 그리고 에이전트가 빗나간 클릭을 하지 않도록 OpenClaw가 둔 안전장치를 따라간다.

    배경 — 에이전트에게 "웹을 본다"는 두 가지 뜻이 있다

    AI 에이전트가 웹을 다룬다고 할 때, 실제로는 난이도가 전혀 다른 두 가지가 섞여 있다. 하나는 읽기만 하면 되는 정적 페이지(서버가 완성된 HTML을 그대로 내려주는 문서)이고, 다른 하나는 사람처럼 조작해야 하는 동적 페이지(로그인·클릭·입력을 거쳐야 비로소 내용이 보이는 화면)다. OpenClaw의 기본 도구 묶음에서 이 둘은 서로 다른 도구가 맡는다.

    diagram

    다이어그램 설명. 위 그림은 에이전트가 웹을 만났을 때 갈라지는 두 갈래를 보여준다. "정적 문서" 갈래는 서버가 이미 완성된 HTML을 주므로 HTTP 요청 한 번이면 끝나고, OpenClaw에서는 web_fetch·web_search(검색·내려받기 전용 도구)가 처리한다. "동적·로그인 페이지" 갈래는 그게 안 된다 — 그래서 browser라는 별도 도구가 필요하다. 여기서 핵심은 "둘이 다른 도구"라는 점인데, 실제로 OpenClaw의 Quick Presets 중 "coding"web_search·web_fetch는 포함하지만 무거운 browser 도구는 기본으로 넣지 않는다. 흔한 오해가 "에이전트면 당연히 브라우저도 쓰겠지"인데, 브라우저 자동화는 명시적으로 켜 줘야 하는 무거운 능력이라 기본 프로필에서 빠져 있다.

    핵심 문제 — fetch는 "그려지기 전의 페이지"를 본다

    왜 동적 페이지는 fetch로 안 될까? 현대 웹사이트 상당수는 서버가 빈 껍데기 HTML만 보내고, 실제 내용은 브라우저 안에서 JavaScript가 실행되며 채워진다. fetch는 JavaScript를 실행하지 않으므로, 받아 오는 건 아직 아무 내용도 그려지지 않은 빈 껍데기다. 로그인은 더 막막하다 — 로그인 뒤에만 보이는 화면은 세션 쿠키(로그인 상태를 증명하는 작은 토큰)가 있어야 하는데, 단발성 fetch에는 그 세션이 없다.

    diagram

    다이어그램 설명. 위 그림은 단순 fetch가 동적 페이지에서 줄줄이 막히는 세 지점을 보여준다. 첫째, JavaScript를 실행하지 않으니 내용이 채워지기 전의 빈 화면을 가져온다. 둘째, 로그인 세션이 없으니 보호된 페이지를 요청하면 로그인 화면으로 되튕긴다. 셋째, 애초에 fetch는 "받아 오기"만 할 뿐 버튼을 누르거나 입력칸을 채우는 조작을 할 수 없다. 세 번째가 가장 놓치기 쉬운 함정이다 — 검색 결과나 문서를 "읽는" 작업은 fetch로 어찌어찌 되지만, 폼을 제출하거나 단계를 밟아 가는 상호작용 자체가 불가능하다는 점이 진짜 벽이다. 이 세 가지를 한 번에 넘으려면 결국 "사람이 쓰는 것과 똑같은 진짜 브라우저"를 띄워 그 안에서 움직이는 수밖에 없다.

    해결 방법 — 격리된 에이전트 전용 브라우저를 제어한다

    OpenClaw의 답은 openclaw라는 이름의 전용 브라우저 프로필을 띄우고 그것을 에이전트가 제어하는 것이다. 브라우저 프로필(profile)이란 쿠키·로그인·확장·설정이 담긴 한 벌의 사용자 데이터를 말한다. 핵심은 이 프로필이 당신이 평소 쓰는 개인 Chrome과 완전히 분리돼 있다는 점이다. 제어는 Gateway(OpenClaw의 중앙 관리 프로세스) 안에 있는 작은 제어 서비스를 통해 이뤄지며, 이 서비스는 외부에 열리지 않고 같은 컴퓨터 안(loopback, 즉 127.0.0.1 자기 자신으로만 도는 연결)에서만 접근된다.

    diagram

    다이어그램 설명. 위 그림은 에이전트의 클릭 한 번이 실제 브라우저까지 닿는 경로를 보여준다. 에이전트는 browser라는 도구 하나만 쥐고, 그 호출은 Gateway 안의 loopback 전용 제어 서비스를 거쳐, CDP(Chrome DevTools Protocol — 크롬을 외부 프로그램이 조종하도록 크롬이 공개하는 표준 제어 채널)를 통해 브라우저로 전달된다. 점선으로 표시된 부분이 이 설계의 핵심이다 — 에이전트가 모는 것은 전용 user data dir(데이터 폴더)과 전용 디버그 포트를 가진 별도 프로필이고, 당신이 로그인해 둔 개인 Chrome은 건드리지 않는다. 흔한 함정은 "내 브라우저를 에이전트가 같이 쓰겠지"라는 가정인데, 기본값은 정반대다. 자동화 사고(엉뚱한 탭을 닫거나 로그인 세션을 망치는 일)가 당신의 실제 작업 환경으로 새어 나오지 않도록, 처음부터 차선을 갈라 둔 것이다.

    왜 하필 "격리된 별도 프로필"인가

    에이전트에게 그냥 내 Chrome을 쓰게 하면 안 될까? OpenClaw는 이 선택을 두 모드로 명확히 갈라 둔다. 기본은 격리된 openclaw 프로필이고, 내 로그인 세션이 꼭 필요할 때만 user 프로필(이미 로그인된 진짜 Chrome에 붙는 모드)을 쓴다. 둘은 안전성과 능력이 정반대로 맞바뀐다.

    diagram

    ▲ 격리 모드 — 안전이 기본값

    다이어그램 설명. 위 그림은 기본값인 격리 프로필이 무엇을 보장하는지 보여준다. 전용 데이터 폴더와 전용 포트를 써서 개인 브라우저와 물리적으로 분리되므로, 에이전트가 무엇을 하든 당신의 로그인·북마크·탭에 영향이 없다. 대신 이 프로필은 출발할 때 로그인 상태가 비어 있다 — 안전을 얻는 대가로 "이미 로그인된 사이트를 곧바로 보는 능력"은 포기한다. 이게 OpenClaw가 "이 브라우저는 당신의 데일리 드라이버가 아니다"라고 못 박는 이유다. 자동화·검증을 위한 안전한 격리 차선이지, 평소 쓰는 브라우저가 아니다.

    diagram

    ▲ attach 모드 — 능력을 얻는 대신 위험을 떠안음

    다이어그램 설명. 위 그림은 반대편 선택지인 user 프로필을 보여준다. 이 모드는 이미 실행 중인 진짜 Chrome에 Chrome DevTools MCP(크롬 세션에 외부 도구를 붙이는 공식 연결 방식)로 attach(이미 떠 있는 브라우저에 새로 띄우지 않고 붙는 것)해서, 당신이 로그인해 둔 세션과 열려 있는 탭을 그대로 쓴다. 능력은 강하지만 — 에이전트가 당신의 로그인된 브라우저 안에서 직접 움직이므로 격리 모드보다 위험이 높다. 그래서 OpenClaw는 사용자가 컴퓨터 앞에 있어 연결 승인 프롬프트를 직접 누를 수 있을 때만 쓰라고 권한다. 두 모드를 같은 축에서 비교하면 트레이드오프가 분명하다 — 격리 모드는 안전을 기본으로 깔고 로그인 능력을 포기하고, attach 모드는 로그인 능력을 얻는 대신 위험을 떠안고 사람의 승인을 요구한다. 기본을 안전 쪽에 둔 게 설계 의도다.

    스냅샷 기반 액션 — 깨지기 쉬운 셀렉터를 피한다

    브라우저를 띄웠다 쳐도, 에이전트가 "여기를 클릭해"를 어떻게 정확히 지시할까? 전통적인 자동화는 CSS 셀렉터(.btn-primary처럼 화면 요소를 문자열로 지목하는 표현)를 쓰는데, 페이지가 조금만 바뀌어도 깨지기로 악명 높다. OpenClaw는 대신 스냅샷(snapshot)을 먼저 찍고, 거기서 받은 안정적인 참조 ID로 조작한다.

    diagram

    다이어그램 설명. 위 그림은 OpenClaw가 권하는 조작 루프를 보여준다. 먼저 browser snapshot이 페이지를 훑어 안정적인 UI 트리(요소들의 계층 구조)를 돌려주는데, 이때 각 요소에 ref(reference, 그 요소를 가리키는 고유 식별자)가 붙는다. 그다음 browser act가 그 ref를 받아 클릭·입력·선택을 실행한다. 화면이 바뀌면 — 옛 ref는 더 이상 유효하지 않으므로 다시 스냅샷을 찍어 최신 ref로 갱신한 뒤 이어 간다. 이 패턴의 핵심 가치는 결정성이다. 문자열 셀렉터처럼 "버튼 클래스 이름이 바뀌면 깨지는" 추측이 끼어들 자리를 없애고, 에이전트가 매번 실제 화면 구조에서 출발하게 만든다. 놓치기 쉬운 함정은 "스냅샷을 한 번만 찍으면 된다"는 생각이다 — UI가 바뀐 뒤 옛 ref를 그대로 쓰면 stale ref(낡아서 더는 그 요소를 가리키지 못하는 참조) 오류가 난다. 그래서 "조작 → 화면 변화 → 재스냅샷"이 하나의 닫힌 고리로 돌아야 한다.

    에이전트가 막히면 — 추측하지 말고 사람에게 넘긴다

    로그인·2단계 인증(2FA)·캡차(CAPTCHA, 사람인지 가리는 그림 문제)나 카메라·마이크 권한 같은 건 에이전트가 풀 수 없다. OpenClaw에 번들로 딸려 오는 browser-automation 스킬(에이전트에게 조작 절차를 가르치는 설명서)은 이런 벽을 만나면 아무거나 눌러 뚫으려 하지 말고 "사람이 해야 할 일"로 보고하라고 지시한다.

    diagram

    다이어그램 설명. 위 그림은 에이전트가 조작하기 전에 거치는 판단을 보여준다. 막힌 원인이 평범한 UI라면 스냅샷·조작 루프를 그대로 이어 가고, 로그인·2FA·캡차·장치 권한처럼 사람만 풀 수 있는 벽이면 "수동 조치 필요"로 보고하고 멈춘다. 이 분기의 설계 의도는 틀린 자동화가 조용히 일을 망치는 것을 막는 것이다. 캡차를 아무 칸이나 채워 제출하거나 2FA 화면에서 임의 버튼을 누르면, 실패하는 데서 그치지 않고 계정 잠금 같은 더 큰 사고로 번질 수 있다. 함정은 "에이전트가 알아서 다 해 주겠지"라는 기대다 — 풀 수 없는 벽 앞에서는 똑똑한 추측보다 "여기서부터는 사람"이라고 정직하게 멈추는 쪽이 안전하다. 참고로 이 긴 스킬 설명서는 항상 메모리에 올라 있지 않고 필요할 때만 로딩돼, 평범한 대화 턴에서는 토큰 비용을 물지 않는다.

    결과 — 무엇이 좋아졌나

    이 구조가 들어오면서 "에이전트가 웹을 본다"는 막연한 능력이 구체적으로 정리된다.

    단순 fetch만 있을 때 격리 browser 도구가 있을 때
    JS로 그려지는 페이지는 빈 껍데기만 회수 진짜 브라우저가 JS를 실행해 완성된 화면을 읽음
    로그인 뒤 화면 접근 불가 필요 시 user 프로필로 로그인 세션 활용 (사람 승인 하에)
    클릭·입력 같은 조작 자체가 불가능 snapshot의 ref로 click·type·select·스크린샷·PDF까지
    자동화 사고가 곧 내 브라우저 사고 격리 프로필이라 개인 세션·탭에 영향 없음
    풀 수 없는 벽(캡차 등)에서 행동 미정의 사람이 풀 일로 보고하고 멈춤 — 추측 클릭 차단

    정리하면, OpenClaw의 browser 도구는 "에이전트에게 손과 눈을 주되, 그 손이 내 진짜 브라우저를 망치지는 않게" 한 설계다. JavaScript로 그려지는 페이지든 로그인이 필요한 화면이든 사람이 쓰는 것과 똑같은 브라우저로 다루되, 그 브라우저는 개인 환경과 분리된 안전한 차선에 두고, 조작은 깨지기 쉬운 셀렉터 대신 매번 실제 화면에서 찍은 스냅샷에서 출발한다. 화려한 자동화보다 이런 "사고가 새지 않는 격리 + 추측하지 않는 절차"가, 에이전트가 웹을 실제 업무에 쓸 수 있게 만드는 진짜 전제 조건이다 — 빠르지만 위험한 자동화는 결국 사람이 더 자주 들여다봐야 하기 때문이다.


    이 글은 생성형 AI의 도움을 받아 작성되었습니다. 원본 자료를 기반으로 AI가 초안을 생성하고, 작성자가 검토·편집하였습니다.

Designed by Tistory.